{"id":40272491,"url":"https://github.com/averbraeck/djunits","last_synced_at":"2026-03-17T09:10:07.743Z","repository":{"id":57965818,"uuid":"524717968","full_name":"averbraeck/djunits","owner":"averbraeck","description":"Delft Java UNIT System for using strongly-typed quantities and units","archived":false,"fork":false,"pushed_at":"2026-03-15T22:33:37.000Z","size":9133,"stargazers_count":1,"open_issues_count":8,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-16T08:51:54.047Z","etag":null,"topics":["java","matrix","quantity","scalar","si","unit","vector"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/averbraeck.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-08-14T16:05:25.000Z","updated_at":"2026-03-15T22:33:40.000Z","dependencies_parsed_at":"2026-01-20T03:12:34.883Z","dependency_job_id":null,"html_url":"https://github.com/averbraeck/djunits","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/averbraeck/djunits","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/averbraeck%2Fdjunits","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/averbraeck%2Fdjunits/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/averbraeck%2Fdjunits/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/averbraeck%2Fdjunits/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/averbraeck","download_url":"https://codeload.github.com/averbraeck/djunits/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/averbraeck%2Fdjunits/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30619827,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-17T08:10:05.930Z","status":"ssl_error","status_checked_at":"2026-03-17T08:10:04.972Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["java","matrix","quantity","scalar","si","unit","vector"],"created_at":"2026-01-20T02:57:52.503Z","updated_at":"2026-03-17T09:10:07.736Z","avatar_url":"https://github.com/averbraeck.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# djunits version 6\n## Delft Java UNIT System\n\nDJUNITS is a set of Java classes that make life easy for scientific software writers by catching many common errors with the use \nof quantities and units at compile time and some others at runtime.\n\n* DJUNITS performs automatic conversions between most commonly used units of the same type. E.g., conversion of distances from miles \n  to kilometers.\n* DJUNITS stores all values internally in the basic SI unit for that quantity. The value can be converted to any (user-selectable) \n  suitable unit for display.\n* DJUNITS distinguishes absolute and relative values to catch common errors at compile time,\n* DJUNITS ensures that quantities expressed in different (but compatible) units are correctly added together. E.g. a distance in \n  miles is correctly added to a distance in kilometers.\n* DJUNITS knows or computes the SI type of the result when a value in one unit is multiplied, or divided by another value \n  (that may have another unit),\n* DJUNITS handles Scalars, Vectors and Matrices, as well as quantity tables.\n* DJUNITS stores everything in immutable objects. \n* DJUNITS stores the data for vectors and matrices as float or double values, and using dense or sparse storage.\n\n\n## Origin\n\nDJUNITS was developed at Delft University of Technology as part of the Open Traffic Simulator project (started in 2014).\n\nIn August 2015 it became obvious that the units and values classes developed for the Open Traffic Simulator were sufficiently \nmature to be used in other projects. In 2026, a complete re-implementation of djunits version 6 took place.\n\nThe main authors/contributors of the DJUNITS project are Alexander Verbraeck and Peter Knoppers.\n\n\n## Absolute and Relative values\n\nValues in DJUNITS are either absolute or relative.\n\nAn absolute value is a value measured from a standard reference. Examples are time with a reference point 1-1-1970 (UNIX epoch) or \na reference point 1-1-0000 (Gregorian calendar time). As an other example, geographical directions, a direction can use North and East \nas reference points. Adding two absolute values together makes no sense. Subtracting one absolute value from another does make sense \n(and results in a relative value). Subtracting East from North should result in an angle of ±90° or ±π/2 (depending on the unit used \nto express the result). An absolute quantity always needs a reference to be useful. Values subtracted from each other need to know \ntheir reference to be able to carry out the subtraction. Therefore, a reference is explicitly stored with an absolute quantity.\n\nA relative value expresses the difference between two (absolute or relative) values. The angle in the example above is a relative \nvalue. Relative values can be added together and subtracted from each other (resulting in relative values). Adding a relative \nvalue to an absolute value results in an absolute value. Subtracting a relative value from an absolute value also results in \nan absolute value.\n\nIn the geographical example, directions are absolute and angles are relative. Similarly, when applied to lengths, positions are \nabsolute and distances are relative.\n\nGenerally, if adding a value to itself makes no sense, the value is absolute; otherwise it is relative.\n\n| Operation \t| Operands              | Result      |\n| ----------- | --------------------- | ----------- |\n| + (plus) \t  | Absolute + Absolute \t| Not allowed |\n| + (plus) \t  | Absolute + Relative \t| Absolute    |\n| + (plus)    | Relative + Absolute\t  | Absolute \t  | \n| + (plus)    | Relative + Relative\t  | Relative    |\n| - (minus)\t  | Absolute - Absolute \t| Relative (corresponding quantity) |\n| - (minus)\t  | Absolute - Relative \t| Absolute    |\n| - (minus)   | Relative - Absolute\t  | Not allowed | \n| - (minus)   | Relative - Relative\t  | Relative    |\n| * (times) \t| Absolute * Absolute\t  | Not allowed |\n| * (times) \t| Absolute * Relative\t  | Not allowed |\n| * (times) \t| Relative * Absolute\t  | Not allowed |\n| * (times) \t| Relative * Relative\t  | Relative (different quantity) |\n| / (divide) \t| Absolute / Absolute\t  | Not allowed |\n| / (divide) \t| Absolute / Relative\t  | Not allowed |\n| / (divide) \t| Relative / Absolute\t  | Not allowed |\n| / (divide) \t| Relative / Relative\t  | Relative (different quantity) |\n\nAttempts to perform operations that are marked not allowed are caught at compile time.\n\nAll quantities make sense as relative values. The four quantities that also make sense as absolute values are listed in the \ntable below.\n\n\n| Quantity    | Absolute interpretation | Absolute class\u003cbr/\u003eand Unit | Relative interpretation | Relative class\u003cbr/\u003e and Unit |\n| ----------- | ----------------------- | ----------------------------| ----------------------- | ---------------------------- |\n| Length      | Position                | Position\u003cbr/\u003eLength.Unit   | Distance                | Length\u003cbr/\u003eLength.Unit        |\n| Angle       | Direction or Slope      | Direction\u003cbr/\u003eAngle.Unit | Angle (direction or slope difference) | Angle\u003cbr/\u003eAngle.Unit |\n| Temperature | Temperature             | Temperature\u003cbr/\u003eTemperature.Unit | Temperature difference | TemperatureDifference\u003cbr/\u003eTemperature.Unit |\n| Time        | Time (instant)          | Time\u003cbr/\u003eDuration.Unit           | Duration                | Duration\u003cbr/\u003eDuration.Unit    |\n\n`Dimensionless` is a special relative unit in DJUNITS that has a `Unitless` unit.\n\n\n## Units\n\nDJUNITS has a large number of pre-defined units. Internally, all values are stored in SI-units or an equivalent standard unit. For scalar values, the field is called si and can be retrieved as it is a public (immutable) field. Alternatively, the getSI() method can be used. The internal storage in SI units allows addition and subtraction of values that have been initialized using different units. Formatting and expressing the unit can be done using any defined unit. The code below illustrates some of the features.\n\n```java\nSpeed speed1 = new Speed(30, Speed.Unit.mi_h);\nSystem.out.println(\"speed1:     \" + speed1);\nSpeed speed2 = new Speed(10, Speed.Unit.m_s);\nSystem.out.println(\"speed2:     \" + speed2);\nSpeed diff = speed1.subtract(speed2);\n\n// Default display unit will be SI unit for speed:\nSystem.out.println(\"difference: \" + diff);\n\n// Change default display unit; internal SI value is unaltered:\ndiff.setDisplayUnit(Speed.Unit.mi_s);\nSystem.out.println(\"difference: \" + diff);\n\n// Works, but not mistake-safe:\nSystem.out.println(\"difference: \" + diff.getInUnit(Speed.Unit.kt) + \" kt\");\n\n// Safer:\nSystem.out.println(\"difference: \" + diff.toString(Speed.Unit.kt));\n\n// Programmer must be really sure that SI-unit is m/s:\nSystem.out.println(\"difference: \" + diff.si() + \" m/s (si)\");\n\n// Safer:\nSystem.out.println(\"difference: \" + diff.toString(Speed.Unit.SI) + \" (si)\");\nSystem.out.println(\"difference: \" + diff.toString(Speed.Unit.km_h));\n```\n\nThis would create the following output:\n\n```\nspeed1:     30.0000000 mi/h\nspeed2:     10.0000000 m/s\ndifference: 7.63063708 mi/h\ndifference: 0.00211962 mi/s\ndifference: 6.630842332613389 kt\ndifference: 6.63084233 kt\ndifference: 3.411199999999999 m/s (si)\ndifference: 3.41120000 m/s (si)\ndifference: 12.2803200 km/h\n```\n\nIt is possible to use units without the Quantity.Unit. The `of()` methods are helper methods to easily use a unit, e.g.,\n`Length.of(12.0, \"m\")` instead of `new Length(12.0, Length.Unit.m)`.\n\n\n## Multiplication and Division\n\nMultiplying or dividing physical quantities produces a result in a different physical unit. There is no general way where the Java \ncompiler can check the type of the result in the general case. Therefore DJUNITS has an extensive list of built-in multiplication \nand division operations with known result type. For instance\n\n```java\nSpeed speed = new Speed(50, Speed.Unit.km_h);\nDuration duration = new Duration(0.5, Duration.Unit.h);\nLength distance = speed.multiply(duration);\nAcceleration acc = speed.divide(duration);\nArea area = distance.multiply(distance);\nVolume vol = area.multiply(distance);\n```\n\nDJUNITS knows that the result of multiplication of a speed and a time is a distance. The value of the distance in the above case is 2500 m.\n\nThere is never a need for multiplication or division with an absolute operand. It just does not make sense to multiply \n23 September 2025, 3 PM (an absolute Time) by 2.\n\n\n## Catch mistakes at compile time where possible\n\nDJUNITS is designed to protect the programmer from easily made mistakes:\n\n```java\nSpeed speed = new Speed(12, Speed.Unit.km_h);\nLength length = new Length(4, Length.Unit.mi);\n\n// Good:\nDuration howLongOK = length.divide(speed); \n\n// Does not compile; result would be a frequency:\nDuration howLongWrong = speed.divide(length); \n\n// Does not compile; subtracting a length from a speed make no sense:\nSpeed other = speed.subtract(length); \n\n// Throws a UnitRuntimeException:\nAcceleration acceleration = speed.multiply(speed).as(Acceleration.Unit.m_s2); \n\n// OK:\nEnergy kineticEnergy = speed.multiply(speed).multiply(new Mass(3, Mass.Unit.kg)\n    .scaleBy(0.5)).as(Energy.Unit.J);\n```\n\nThe mistakes on the lines with comments starting with Does not compile will be caught at compile time. In a development environment that continously checks for coding errors (like Eclipse) such mistakes will be marked in by the java editor.\n\nThe before-last line multiplies a speed by another speed. The result of this operation is not something that DJUNITS supports directly. Such scalars can be cast to something DJUNITS does know of with an `as(TargetUnit)` method. Whether that cast is permitted can only be checked at runtime and this example would fail with:\n\n```\nIllegalArgumentException: org.djunits.quantity.def.Quantity.as (804): \n    Quantity.as(m/s2) called, but units do not match: m2/s2 \u003c\u003e m/s2\n```\n\nA correct example where DJUNITS does not know the unit of the result (thus requiring an `as(TargetUnit)` cast) is:\n\n```java\nEnergy kineticEnergy = speed.multiply(speed).multiply(new Mass(3, Mass.Unit.kg)\n    .scaleBy(0.5)).as(Energy.Unit.J);\nSystem.out.println(kineticEnergy);\n```\n\nThis would print:\n\n```\n16.6666667 J\n```\n\n\n## Scalars, Vectors and Matrices\n\nSimple values are referred to as quantities or scalars. DJUNITS also handles groups of values (these must all be of the same unit) as vectors or \nmatrices. Efficient classes have been created for the 'small' vectors and matrices of size 1 to 3. The following vector and matrix classes exist:\n\n* `Vector1` for a vector with just one element\n* `Vector2.Row` and `Vector2.Col` for a row and column vector of size 2\n* `Vector3.Row` and `Vector3.Col` for a row and column vector of size 3\n* `VectorN.Row` and `VectorN.Col` for a row and column vector of any size\n* `Matrix1x1` for a square matrix of size 1 x 1\n* `Matrix2x2` for a square matrix of size 2 x 2\n* `Matrix3x3` for a square matrix of size 3 x 3\n* `MatrixNxN` for a square matrix of any size\n* `MatrixNxM` for a non-square or square matrix of any size\n\nThe larger vectors and matrices (`VectorN`, `MatrixNxN`, `MatrixNxM`) come in four varieties:\n\n* Dense, Double\n* Dense, Float\n* Sparse, Double\n* Sparse, Float\n\nDense vectors and matrices use arrays to store the values. Sparse vectors and matrices use an indexed structure to store only the \nnon-zero values. Numeric 0.0 values are not stored explicitly in Sparse vectors and matrices. Very large vectors and matrices with \nlots of 0.0 values are more efficiently stored using Sparse data storage.\n\nThe Java double precision floating point value takes 8 bytes of memory, the float value takes 4 bytes. Both are available in DJUNITS\nfor storage in `VectorN`, `MatrixNxN`, `MatrixNxM`. \n\nCreating vectors and matrices is straightforward:\n\n```java\nSystem.out.println(\"\\n\\nMatrices\");\nvar mat = Matrix2x2.of(new double[][] {{1.0, 2.0}, {5.0, 4.0}}, Duration.Unit.s);\nSystem.out.println(\"matrix:\\n\" + mat);\nSystem.out.println(\"\\nmatrix + matrix:\\n\" + mat.add(mat));\nSystem.out.println(\"\\nmatrix + 1 day:\\n\" + mat.add(Duration.of(1.0, \"day\")));\nSystem.out.println(\"\\ndeterminant: \" + mat.determinant());\n```\n\nThis prints:\n\n```\nMatrices\nmatrix:\n[1.00000000, 2.00000000\n 5.00000000, 4.00000000] s\n\nmatrix + matrix:\n[2.00000000, 4.00000000\n 10.0000000, 8.00000000] s\n\nmatrix + 1 day:\n[86401.0000, 86402.0000\n 86405.0000, 86404.0000] s\n\ndeterminant: -6.0000000 s2\n```\n\n\n## Vector and Matrix calculations\n\nAll standard vector and matrix operations are available, such as row and column extraction, calculation of determinant, inverse, and adjugate, transposing of vectors and matrices, matrix-matrix multiplication, matrix-vector multiplication, vector-vector multiplication, matrix-quantity multiplication, and vector-quantity multiplication. Hadamard operations on the elements of a vector or matrix are also supported. In all cases, units of the reculting vector or matrix are calculated. This means that if we multiply a `Length` matrix with a `Length` matrix, we get a resulting matrix of quantity `Area` with an `Area.Unit` as its unit.\n\nThe following example first shows a Hadamard operation (element-wise), followed by an algebraic matrix multiplication:\n\n```java\nVectorN.Col\u003cLength, Length.Unit\u003e lv1 = VectorN.Col.of(new double[] {10, 20.0, 60, 120.0, 400.0}, Length.Unit.km);\nDuration duration = Duration.of(2.0, \"h\");\nVectorN.Col\u003cSpeed, Speed.Unit\u003e sv1 = lv1.divideElements(duration).as(Speed.Unit.km_h);\nSystem.out.println(\"Length: \" + lv1);\nSystem.out.println(\"Speed : \" + sv1);\n\nMatrixNxM\u003cLength, Length.Unit\u003e lm4x2 = MatrixNxM.of(new double[][] {{1, 2, 3, 4}, {5, 6, 7, 8}}, Length.Unit.m);\nMatrixNxM\u003cLength, Length.Unit\u003e lm2x4 = MatrixNxM.of(new double[][] {{1, 2}, {3, 4}, {5, 6}, {7, 8}}, Length.Unit.m);\n\nvar mult44 = lm4x2.multiply(lm2x4).as(Area.Unit.m2);\nSystem.out.println(\"\\nMatrix1:\\n\" + lm4x2);\nSystem.out.println(\"Matrix2:\\n\" + lm2x4);\nSystem.out.println(\"Multiplication:\\n\" + mult44);\n\nMatrix2x2\u003cArea, Area.Unit\u003e mult22 = lm4x2.multiply(lm2x4).asMatrix2x2().as(Area.Unit.a);\nSystem.out.println(\"\\nMatrix1:\\n\" + lm2x4);\nSystem.out.println(\"Matrix2:\\n\" + lm4x2);\nSystem.out.println(\"Multiplication:\\n\" + mult22);\n```\n\nThe last matrix is cast to a strongly typed `Matrix2x2\u003cArea, Area.Unit\u003e`, where values are expressed in are. The code results in the following output:\n\n```\nLength: Col[10.0, 20.0, 60.0, 120.0, 400.0] km\nSpeed : Col[5.0, 10.0, 30.0, 60.0, 200.0] km/h\n\nMatrix1:\n[1.00000000, 2.00000000, 3.00000000, 4.00000000\n 5.00000000, 6.00000000, 7.00000000, 8.00000000] m\nMatrix2:\n[1.00000000, 2.00000000\n 3.00000000, 4.00000000\n 5.00000000, 6.00000000\n 7.00000000, 8.00000000] m\nMultiplication:\n[50.0000000, 60.0000000\n 114.000000, 140.000000] m2\n\nMatrix1:\n[1.00000000, 2.00000000\n 3.00000000, 4.00000000\n 5.00000000, 6.00000000\n 7.00000000, 8.00000000] m\nMatrix2:\n[1.00000000, 2.00000000, 3.00000000, 4.00000000\n 5.00000000, 6.00000000, 7.00000000, 8.00000000] m\nMultiplication:\n[0.50000000, 0.60000000\n 1.14000000, 1.40000000] a\n```\n\n\n## QuantityTable\n\nFor those cases where a tabular storage of data is needed, but it is not necessary to carry out matrix or vector operations, the `QuantityTable` exists. It behaves like a `MatrixNxM` without the overhead of a matrix. Hadamard (element-wise) operations are allowed on the `QuantityTable`. \n\n\n## Localization\n\nDJUNITS has been designed with localization in mind. This means that quantities, units, vectors and matrices can print the unit information based on a resource bundle file for that country. On the input side, quantities can also be created using localized string representations, as the example below shows:\n\n```java\nSystem.out.println(\"\\nLOCALIZATION US\");\nLocale.setDefault(Locale.US);\nvar speed = Speed.of(50.0, \"km/h\");\nSystem.out.println(\"Absorbed dose name: \" + AbsorbedDose.ONE.getName());\nSystem.out.println(\"50 km/h = \" + speed);\nSystem.out.println(\"Acceleration: \" + Units.localizedQuantityName(Acceleration.Unit.class));\n\nSystem.out.println(\"\\nLOCALIZATION NL\");\nLocale.setDefault(Locale.forLanguageTag(\"nl\"));\nSystem.out.println(\"Absorbed dose name: \" + AbsorbedDose.ONE.getName());\nSystem.out.println(\"50 km/h = \" + speed);\nSystem.out.println(\"Acceleration: \" + Units.localizedQuantityName(Acceleration.Unit.class));\n\nvar d3du = Duration.valueOf(\"3 dag\");\nd3du.setDisplayUnit(\"u\");\nSystem.out.println(\"3 dagen in uren: \" + d3du);\n```\n\nThis results in:\n\n```\nLOCALIZATION US\nAbsorbed dose name: Absorbed dose\n50 km/h = 50.0000000 km/h\nAcceleration: Acceleration\n\nLOCALIZATION NL\nAbsorbed dose name: Geabsorbeerde straling\n50 km/h = 50,0000000 km/u\nAcceleration: Versnelling\n3 dagen in uren: 72,0000000 u\n```\n\nThe following localizations are currently bundled with DJUNITS: `en_US`, `de`, `en_GB`, `es`, `fr`, `it`, `ja`, `ko`, `nl`, `pt`, `zh_TW`, `zh`. \n\n\n## Difference with previous versions\n\nDJUNITS version 6 is different from versions 1 to 5, and not upward compatible. Version 6 is a completely new implementation of the code with the following notable differences:\n\n- The `Quantity` is now the central object from which all quantities inherit.\n- Unit classes are inner classes of the quantity, such as `Energy.Unit`.\n- The `SIQuantity` and `SIUnit` classes have been implemented as a normal quantity.\n- The `DimensionlessUnit` unit class has been renamed to `Unitless`.\n- Localization is built-in as a design guideline and not as an afterthought. \n- Absolute quantities have been re-implemented using a `Reference` for the reference point. \n- Operation names are streamlined across quantities, vectors and matrices, e.g., `add`, `subtract`, `multiply`, `divide`.\n- Vector and matrix classes use generics for definitions such as `Matrix3x3\u003cArea, Area.Unit\u003e`, and only allow correct operations.\n- Vector and matrix operations sich as trace, multiplication, and inverse are now fully supported with consistent unit calculations.\n- Hadamard operations have been added to vector and matrix calculations.\n- The `QuantityTable` has been added for storage of tabular quantity data.\n\nThe manual of the latest **version 5** can be found at \u003ca href=\"https://djunits.org/docs/5.4.2/manual/\"\u003ehttps://djunits.org/docs/5.4.2/manual/\u003c/a\u003e. \n\n\n## Documentations and test reports\n\nDJUNITS documentation and test reports for the current version can be found at [https://djunits.org/docs/latest](https://djunits.org/docs/latest). The manual is at [https://djunits.readthedocs.io](https://djunits.readthedocs.io), or at [https://djunits.org/manual](https://djunits.org/manual) The API can be \nfound at [https://djunits.org/docs/latest/apidocs/index.html](https://djunits.org/docs/latest/apidocs/index.html).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faverbraeck%2Fdjunits","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faverbraeck%2Fdjunits","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faverbraeck%2Fdjunits/lists"}