diff --git a/Dockerfile b/Dockerfile index 693a141c91644a9b7a214df832a47b9bc37975cc..173f1ece3038661b02ec39fc20e3898c37658e37 100644 --- a/Dockerfile +++ b/Dockerfile @@ -70,6 +70,7 @@ RUN cp dist/nomad-lab-*.tar.gz dist/nomad-lab.tar.gz RUN python -m nomad.cli dev metainfo > gui/src/metainfo.json RUN python -m nomad.cli dev search-quantities > gui/src/searchQuantities.json RUN python -m nomad.cli dev toolkit-metadata > gui/src/toolkitMetadata.json +RUN python -m nomad.cli dev units > gui/src/units.js WORKDIR /install/docs RUN make html RUN \ @@ -90,6 +91,7 @@ COPY --from=build /install/gui/src/metainfo.json /app/src/metainfo.json COPY --from=build /install/gui/src/searchQuantities.json /app/src/searchQuantities.json COPY --from=build /install/gui/src/parserMetadata.json /app/src/parserMetadata.json COPY --from=build /install/gui/src/toolkitMetadata.json /app/src/toolkitMetadata.json +COPY --from=build /install/gui/src/units.js /app/src/units.js RUN yarn run build # Build the Encyclopedia GUI in the gui build image diff --git a/gui/src/components/archive/ArchiveBrowser.js b/gui/src/components/archive/ArchiveBrowser.js index 28a46a5d24b5d33a26b7eca68d2331f6cd0c4eb5..6cc52403ba71f53291fe15197a79fa5684cceecc 100644 --- a/gui/src/components/archive/ArchiveBrowser.js +++ b/gui/src/components/archive/ArchiveBrowser.js @@ -1,4 +1,3 @@ - import React, { useMemo, useState, useCallback } from 'react' import PropTypes from 'prop-types' import { atom, useRecoilState, useRecoilValue } from 'recoil' @@ -16,17 +15,36 @@ import { ErrorHandler, ErrorCard } from '../ErrorHandler' import DOS from '../visualization/DOS' import { StructureViewer, BrillouinZoneViewer } from '@lauri-codes/materia' import Markdown from '../Markdown' -import { convert } from '../../utils' +import { UnitSelector } from './UnitSelector' +import { convertSI } from '../../utils' +import { conversionMap } from '../../units' export const configState = atom({ key: 'config', default: { 'showMeta': false, 'showCodeSpecific': false, - 'showAllDefined': false + 'showAllDefined': false, + 'energyUnit': 'joule' } }) +let defaults = {} +for (const dimension in conversionMap) { + const info = conversionMap[dimension] + defaults[dimension] = info.units[0] +} +const override = { + 'length': 'angstrom', + 'energy': 'electron_volt', + 'system': 'custom' +} +defaults = {...defaults, ...override} +export const unitsState = atom({ + key: 'units', + default: defaults +}) + // Shared instance of the StructureViewer const viewer = new StructureViewer() const bzViewer = new BrillouinZoneViewer() @@ -50,6 +68,7 @@ ArchiveBrowser.propTypes = ({ function ArchiveConfigForm({searchOptions}) { const [config, setConfig] = useRecoilState(configState) + const handleConfigChange = event => { const changes = {[event.target.name]: event.target.checked} if (changes.showCodeSpecific) { @@ -64,21 +83,23 @@ function ArchiveConfigForm({searchOptions}) { const { url } = useRouteMatch() return ( - <Box marginTop={-6}> - <FormGroup row style={{alignItems: 'flex-end'}}> - <Autocomplete - options={searchOptions} - getOptionLabel={(option) => option.name} - style={{ width: 350 }} - onChange={(_, value) => { - if (value) { - history.push(url + value.path) - } - }} - renderInput={(params) => <TextField {...params} label="search" margin="normal" />} - /> + <Box marginTop={-3} padding={0}> + <FormGroup row style={{alignItems: 'center'}}> + <Box style={{width: 350, height: 60}}> + <Autocomplete + options={searchOptions} + getOptionLabel={(option) => option.name} + style={{ width: 350, marginTop: -20 }} + onChange={(_, value) => { + if (value) { + history.push(url + value.path) + } + }} + renderInput={(params) => <TextField {...params} label="search" margin="normal" />} + /> + </Box> <Box flexGrow={1} /> - <Tooltip title="Enable to also show all code specfic data"> + <Tooltip title="Enable to also show all code specific data"> <FormControlLabel control={ <Checkbox @@ -113,6 +134,7 @@ function ArchiveConfigForm({searchOptions}) { label="definitions" /> </Tooltip> + <UnitSelector unitsState={unitsState}></UnitSelector> </FormGroup> </Box> ) @@ -246,6 +268,7 @@ class QuantityAdaptor extends ArchiveAdaptor { } function QuantityItemPreview({value, def}) { + const units = useRecoilState(unitsState)[0] if (def.type.type_kind === 'reference') { return <Box component="span" fontStyle="italic"> <Typography component="span">reference ...</Typography> @@ -280,9 +303,14 @@ function QuantityItemPreview({value, def}) { </Typography> </Box> } else { + let finalValue = value + let finalUnit = def.unit + if (def.unit) { + [finalValue, finalUnit] = convertSI(value, def.unit, units) + } return <Box component="span" whiteSpace="nowarp"> - <Number component="span" variant="body1" value={value} exp={8} /> - {def.unit && <Typography component="span"> {def.unit}</Typography>} + <Number component="span" variant="body1" value={finalValue} exp={8} /> + {finalUnit && <Typography component="span"> {finalUnit}</Typography>} </Box> } } @@ -292,10 +320,18 @@ QuantityItemPreview.propTypes = ({ }) function QuantityValue({value, def}) { + // Figure out the units + const units = useRecoilState(unitsState)[0] + let finalValue = value + let finalUnit = def.unit + if (def.unit) { + [finalValue, finalUnit] = convertSI(value, def.unit, units) + } + return <Box marginTop={2} marginBottom={2} textAlign="center" fontWeight="bold" > - {def.shape.length > 0 ? <Matrix values={value} shape={def.shape} invert={def.shape.length === 1} /> : <Number value={value} exp={16} variant="body2" />} + {def.shape.length > 0 ? <Matrix values={finalValue} shape={def.shape} invert={def.shape.length === 1} /> : <Number value={finalValue} exp={16} variant="body2" />} {def.shape.length > 0 && <Typography noWrap variant="caption"> ({def.shape.map((dimension, index) => <span key={index}> @@ -303,7 +339,7 @@ function QuantityValue({value, def}) { </span>)} ) </Typography> } - {def.unit && <Typography noWrap>{def.unit}</Typography>} + {def.unit && <Typography noWrap>{finalUnit}</Typography>} </Box> } QuantityValue.propTypes = ({ @@ -371,14 +407,14 @@ function Overview({section, def}) { } else if (sectionPath === visualizedSystem.sectionPath && nAtoms === visualizedSystem.nAtoms) { positionsOnly = true system = { - positions: convert(section.atom_positions, 'm', 'angstrom') + positions: convertSI(section.atom_positions, 'meter', {length: 'angstrom'}, false) } // Completely new system } else { system = { 'species': section.atom_species, - 'cell': convert(section.lattice_vectors, 'm', 'angstrom'), - 'positions': convert(section.atom_positions, 'm', 'angstrom'), + 'cell': convertSI(section.lattice_vectors, 'meter', {length: 'angstrom'}, false), + 'positions': convertSI(section.atom_positions, 'meter', {length: 'angstrom'}, false), 'pbc': section.configuration_periodic_dimensions } } @@ -409,6 +445,7 @@ function Overview({section, def}) { className={style.bands} data={section} aspectRatio={1} + unitsState={unitsState} ></BandStructure> </ErrorHandler> </Box> @@ -453,6 +490,7 @@ function Overview({section, def}) { className={style.dos} data={section} aspectRatio={1 / 2} + unitsState={unitsState} ></DOS> </ErrorHandler> } diff --git a/gui/src/components/archive/UnitSelector.js b/gui/src/components/archive/UnitSelector.js new file mode 100644 index 0000000000000000000000000000000000000000..28a31f424ce1ed0c802068888719a6812363ca1e --- /dev/null +++ b/gui/src/components/archive/UnitSelector.js @@ -0,0 +1,177 @@ +import React, { useCallback, useState } from 'react' +import { useRecoilState } from 'recoil' +import { makeStyles } from '@material-ui/core/styles' +import { + Box, + Button, + Menu, + MenuItem, + FormControl, + InputLabel, + Select, + FormLabel, + FormControlLabel, + RadioGroup, + Radio, + Tooltip +} from '@material-ui/core' +import PropTypes from 'prop-types' +import clsx from 'clsx' +import { conversionMap, unitMap, unitSystems } from '../../units' + +/** + * Component that wraps it's children in a container that can be 'floated', + * i.e. displayed on an html element that is positioned relative to the + * viewport and is above all other elements. + */ +export function UnitSelector({className, classes, unitsState, onUnitChange, onSystemChange}) { + // States + const [canSelect, setCanSelect] = useState(true) + const [anchorEl, setAnchorEl] = React.useState(null) + const open = Boolean(anchorEl) + const [units, setUnits] = useRecoilState(unitsState) + + // Styles + const useStyles = makeStyles((theme) => { + return { + menuItem: { + width: '10rem' + }, + systems: { + margin: theme.spacing(2), + marginTop: theme.spacing(1) + } + } + }) + const style = useStyles(classes) + + // Callbacks + const openMenu = useCallback((event) => { + setAnchorEl(event.currentTarget) + }, []) + const closeMenu = useCallback(() => { + setAnchorEl(null) + }, []) + const handleSystemChange = useCallback((event) => { + const systemName = event.target.value + let changes = {system: systemName} + if (systemName === 'custom') { + setCanSelect(true) + } else { + setCanSelect(false) + const system = unitSystems[systemName] + changes = {...changes, ...system.units} + } + setUnits({...units, ...changes}) + if (onSystemChange) { + onSystemChange(event) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + const handleUnitChange = useCallback(event => { + const changes = {[event.target.name]: event.target.value} + if (onUnitChange) { + onUnitChange(event) + } + console.log(changes) + setUnits({...units, ...changes}) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + // Ordered list of controllable units. It may be smaller than the full list of + // units. + const unitNames = ['energy', 'length', 'force', 'mass', 'time', 'temperature'] + const systemNames = ['SI', 'AU'] + + return ( + <Box className={clsx(style.root, className)}> + <Button + aria-controls="customized-menu" + aria-haspopup="true" + variant="outlined" + color="primary" + onClick={openMenu} + > + Select units + </Button> + <Menu + id="select-unit" + anchorEl={anchorEl} + getContentAnchorEl={null} + anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} + transformOrigin={{ vertical: 'top', horizontal: 'right' }} + keepMounted + open={open} + onClose={closeMenu} + > + <FormControl + component="fieldset" + classes={{root: style.systems}} + > + <FormLabel component="legend">Unit system</FormLabel> + <RadioGroup aria-label="gender" name="gender1" value={units.system} onChange={handleSystemChange}> + <Tooltip title="Custom units"> + <FormControlLabel value="custom" control={<Radio />} label="Custom" /> + </Tooltip> + {systemNames.map((systemName) => { + const system = unitSystems[systemName] + return <Tooltip key={systemName} title={system.description}> + <FormControlLabel value={systemName} control={<Radio />} label={system.label} /> + </Tooltip> + })} + </RadioGroup> + </FormControl> + {unitNames.map((dimension) => { + const unitList = conversionMap[dimension].units + return <MenuItem + key={dimension} + > + <FormControl disabled={!canSelect}> + <InputLabel id="demo-simple-select-label">{dimension}</InputLabel> + <Select + classes={{root: style.menuItem}} + labelId="demo-simple-select-label" + id="demo-simple-select" + name={dimension} + value={units[dimension]} + onChange={handleUnitChange} + > + {unitList.map((unit) => { + const unitLabel = unitMap[unit].label + return <MenuItem key={unit} value={unit}>{unitLabel}</MenuItem> + })} + </Select> + </FormControl> + </MenuItem> + })} + </Menu> + </Box> + ) +} + +UnitSelector.propTypes = { + /** + * CSS class for the root element. + */ + className: PropTypes.string, + /** + * CSS classes for this component. + */ + classes: PropTypes.object, + /** + * Recoil atom containing the unit configuration that this component will + * attach to. + */ + unitsState: PropTypes.object, + /** + * Callback for unit selection. + */ + onUnitChange: PropTypes.func, + /** + * Callback for unit system selection. + */ + onSystemChange: PropTypes.func +} +UnitSelector.defaultProps = { + float: false +} diff --git a/gui/src/components/visualization/BandStructure.js b/gui/src/components/visualization/BandStructure.js index d18dde174c59c8e5ba652108d61ac40d9ff65982..f689ad22afc31b22853e873020e2516d7698692b 100644 --- a/gui/src/components/visualization/BandStructure.js +++ b/gui/src/components/visualization/BandStructure.js @@ -1,4 +1,5 @@ import React, {useState, useEffect, useMemo} from 'react' +import { useRecoilValue } from 'recoil' import PropTypes from 'prop-types' import { makeStyles, useTheme } from '@material-ui/core/styles' import clsx from 'clsx' @@ -6,11 +7,12 @@ import { Box } from '@material-ui/core' import Plot from '../visualization/Plot' -import { convert, distance, mergeObjects } from '../../utils' +import { convertSI, distance, mergeObjects } from '../../utils' -export default function BandStructure({data, layout, aspectRatio, className, classes, onRelayout, onAfterPlot, onRedraw, onRelayouting}) { +export default function BandStructure({data, layout, aspectRatio, className, classes, onRelayout, onAfterPlot, onRedraw, onRelayouting, unitsState}) { const [finalData, setFinalData] = useState(undefined) const [pathSegments, setPathSegments] = useState(undefined) + const units = useRecoilValue(unitsState) // Styles const useStyles = makeStyles( @@ -89,7 +91,7 @@ export default function BandStructure({data, layout, aspectRatio, className, cla // Create plot data entry for each band for (let band of bands) { - band = convert(band, 'joule', 'eV') + band = convertSI(band, 'joule', units, false) plotData.push( { x: path, @@ -122,7 +124,7 @@ export default function BandStructure({data, layout, aspectRatio, className, cla // Create plot data entry for each band for (let band of bands) { - band = convert(band, 'joule', 'eV') + band = convertSI(band, 'joule', units, false) plotData.push( { x: path, @@ -138,7 +140,7 @@ export default function BandStructure({data, layout, aspectRatio, className, cla } setFinalData(plotData) - }, [data, theme.palette.primary.main, theme.palette.secondary.main]) + }, [data, theme.palette.primary.main, theme.palette.secondary.main, units]) // Merge custom layout with default layout const tmpLayout = useMemo(() => { @@ -241,5 +243,6 @@ BandStructure.propTypes = { onAfterPlot: PropTypes.func, onRedraw: PropTypes.func, onRelayout: PropTypes.func, - onRelayouting: PropTypes.func + onRelayouting: PropTypes.func, + unitsState: PropTypes.object // Recoil atom containing the unit configuration } diff --git a/gui/src/components/visualization/DOS.js b/gui/src/components/visualization/DOS.js index ae8a2aaaeb8d4f069eeb902811f7d94e1595313a..aba50c9e085648e3d5d1178a5423a4096ffe045e 100644 --- a/gui/src/components/visualization/DOS.js +++ b/gui/src/components/visualization/DOS.js @@ -1,4 +1,5 @@ import React, {useState, useEffect, useMemo} from 'react' +import { useRecoilValue } from 'recoil' import PropTypes from 'prop-types' import { makeStyles, useTheme } from '@material-ui/core/styles' import clsx from 'clsx' @@ -6,22 +7,23 @@ import { Box } from '@material-ui/core' import Plot from '../visualization/Plot' -import { convert, mergeObjects } from '../../utils' +import { convertSI, convertSILabel, mergeObjects } from '../../utils' -export default function DOS({data, layout, aspectRatio, className, classes, onRelayout, onAfterPlot, onRedraw, onRelayouting}) { +export default function DOS({data, layout, aspectRatio, className, classes, onRelayout, onAfterPlot, onRedraw, onRelayouting, unitsState}) { const [finalData, setFinalData] = useState(undefined) + const units = useRecoilValue(unitsState) // Merge custom layout with default layout const tmpLayout = useMemo(() => { let defaultLayout = { yaxis: { title: { - text: 'Energy (eV)' + text: `Energy (${convertSILabel('joule', units)})` } } } return mergeObjects(layout, defaultLayout) - }, [layout]) + }, [layout, units]) // Styles const useStyles = makeStyles( @@ -45,7 +47,7 @@ export default function DOS({data, layout, aspectRatio, className, classes, onRe const plotData = [] if (data !== undefined) { let nChannels = data[valueName].length - let energies = convert(data[energyName], 'joule', 'eV') + let energies = convertSI(data[energyName], 'joule', units, false) if (nChannels === 2) { plotData.push( { @@ -74,7 +76,7 @@ export default function DOS({data, layout, aspectRatio, className, classes, onRe ) } setFinalData(plotData) - }, [data, theme.palette.primary.main, theme.palette.secondary.main]) + }, [data, theme.palette.primary.main, theme.palette.secondary.main, units]) // Compute layout that depends on data. const computedLayout = useMemo(() => { @@ -85,12 +87,12 @@ export default function DOS({data, layout, aspectRatio, className, classes, onRe let defaultLayout = { xaxis: { title: { - text: norm ? 'states/eV/m<sup>3</sup>/atom' : 'states/eV/cell' + text: norm ? convertSILabel('states/joule/m^3/atom', units) : convertSILabel('states/joule/cell', units) } } } return defaultLayout - }, [data]) + }, [data, units]) // Merge the given layout and layout computed from data const finalLayout = useMemo(() => { @@ -123,5 +125,6 @@ DOS.propTypes = { onAfterPlot: PropTypes.func, onRedraw: PropTypes.func, onRelayout: PropTypes.func, - onRelayouting: PropTypes.func + onRelayouting: PropTypes.func, + unitsState: PropTypes.object // Recoil atom containing the unit configuration } diff --git a/gui/src/units.js b/gui/src/units.js new file mode 100644 index 0000000000000000000000000000000000000000..73e2eee67eabe8637591c7f8caf7d7526edcf67a --- /dev/null +++ b/gui/src/units.js @@ -0,0 +1,500 @@ +// Generated by NOMAD CLI. Do not edit manually. +export const unitMap = { + second: { + dimension: 'time', + label: 'Second', + abbreviation: 's' + }, + atomic_unit_of_time: { + dimension: 'time', + label: 'Atomic unit of time', + abbreviation: 'atomic_unit_of_time' + }, + meter: { + dimension: 'length', + label: 'Meter', + abbreviation: 'm' + }, + bohr: { + dimension: 'length', + label: 'Bohr', + abbreviation: 'bohr' + }, + angstrom: { + dimension: 'length', + label: '\u00c5ngstrom', + abbreviation: '\u00c5' + }, + kilogram: { + dimension: 'mass', + label: 'Kilogram', + abbreviation: 'kg' + }, + electron_mass: { + dimension: 'mass', + label: 'Electron mass', + abbreviation: 'm\u2091' + }, + unified_atomic_mass_unit: { + dimension: 'mass', + label: 'Unified atomic mass unit', + abbreviation: 'u' + }, + ampere: { + dimension: 'current', + label: 'Ampere', + abbreviation: 'A' + }, + atomic_unit_of_current: { + dimension: 'current', + label: 'Atomic unit of current', + abbreviation: 'atomic_unit_of_current' + }, + mole: { + dimension: 'substance', + label: 'Mole', + abbreviation: 'mole' + }, + candela: { + dimension: 'luminosity', + label: 'Candela', + abbreviation: 'cd' + }, + kelvin: { + dimension: 'temperature', + label: 'Kelvin', + abbreviation: 'K' + }, + celsius: { + dimension: 'temperature', + label: 'Celsius', + abbreviation: '\u00b0C' + }, + fahrenheit: { + dimension: 'temperature', + label: 'Fahrenheit', + abbreviation: '\u00b0F' + }, + atomic_unit_of_temperature: { + dimension: 'temperature', + label: 'Atomic unit of temperature', + abbreviation: 'atomic_unit_of_temperature' + }, + newton: { + dimension: 'force', + label: 'Newton', + abbreviation: 'N' + }, + atomic_unit_of_force: { + dimension: 'force', + label: 'Atomic unit of force', + abbreviation: 'atomic_unit_of_force' + }, + pascal: { + dimension: 'pressure', + label: 'Pascal', + abbreviation: 'Pa' + }, + joule: { + dimension: 'energy', + label: 'Joule', + abbreviation: 'J' + }, + electron_volt: { + dimension: 'energy', + label: 'Electron volt', + abbreviation: 'eV' + }, + hartree: { + dimension: 'energy', + label: 'Hartree', + abbreviation: 'Ha' + }, + watt: { + dimension: 'power', + label: 'Watt', + abbreviation: 'W' + }, + hertz: { + dimension: 'frequency', + label: 'Hertz', + abbreviation: 'Hz' + }, + volt: { + dimension: 'electric_potential', + label: 'Volt', + abbreviation: 'V' + }, + farad: { + dimension: 'capacitance', + label: 'Farad', + abbreviation: 'F' + }, + coulomb: { + dimension: 'charge', + label: 'Coulomb', + abbreviation: 'C' + }, + elementary_charge: { + dimension: 'charge', + label: 'Elementary charge', + abbreviation: 'e' + }, + tesla: { + dimension: 'magnetic_field', + label: 'Tesla', + abbreviation: 'T' + }, + weber: { + dimension: 'magnetic_flux', + label: 'Weber', + abbreviation: 'Wb' + }, + henry: { + dimension: 'inductance', + label: 'Henry', + abbreviation: 'H' + }, + dimensionless: { + dimension: 'dimensionless', + label: 'Dimensionless', + abbreviation: '' + } +} +export const conversionMap = { + time: { + units: [ + 'second', + 'atomic_unit_of_time' + ], + multipliers: { + second: { + second: 1, + atomic_unit_of_time: 4.134137333518244e+16 + }, + atomic_unit_of_time: { + second: 2.4188843265856806e-17, + atomic_unit_of_time: 1 + } + } + }, + length: { + units: [ + 'meter', + 'bohr', + 'angstrom' + ], + multipliers: { + meter: { + meter: 1, + bohr: 18897261246.22279, + angstrom: 10000000000.0 + }, + bohr: { + meter: 5.2917721090397754e-11, + bohr: 1, + angstrom: 0.5291772109039775 + }, + angstrom: { + meter: 1e-10, + bohr: 1.8897261246222794, + angstrom: 1 + } + } + }, + mass: { + units: [ + 'kilogram', + 'electron_mass', + 'unified_atomic_mass_unit' + ], + multipliers: { + kilogram: { + kilogram: 1, + electron_mass: 1.0977691057577633e+30, + unified_atomic_mass_unit: 6.022140762081123e+26 + }, + electron_mass: { + kilogram: 9.1093837015e-31, + electron_mass: 1, + unified_atomic_mass_unit: 0.0005485799090624057 + }, + unified_atomic_mass_unit: { + kilogram: 1.6605390666e-27, + electron_mass: 1822.8884862173131, + unified_atomic_mass_unit: 1 + } + } + }, + current: { + units: [ + 'ampere', + 'atomic_unit_of_current' + ], + multipliers: { + ampere: { + ampere: 1, + atomic_unit_of_current: 150.97488474455437 + }, + atomic_unit_of_current: { + ampere: 0.006623618237509995, + atomic_unit_of_current: 1 + } + } + }, + substance: { + units: [ + 'mole' + ], + multipliers: { + mole: { + mole: 1 + } + } + }, + luminosity: { + units: [ + 'candela' + ], + multipliers: { + candela: { + candela: 1 + } + } + }, + temperature: { + units: [ + 'kelvin', + 'celsius', + 'fahrenheit', + 'atomic_unit_of_temperature' + ], + multipliers: { + kelvin: { + kelvin: 1, + celsius: 1.0, + fahrenheit: 1.7999999999999998, + atomic_unit_of_temperature: 3.1668115634555572e-06 + }, + celsius: { + kelvin: 1, + celsius: 1, + fahrenheit: 1.7999999999999998, + atomic_unit_of_temperature: 3.1668115634555572e-06 + }, + fahrenheit: { + kelvin: 0.5555555555555556, + celsius: 0.5555555555555556, + fahrenheit: 1, + atomic_unit_of_temperature: 1.7593397574753097e-06 + }, + atomic_unit_of_temperature: { + kelvin: 315775.0248040719, + celsius: 315775.0248040719, + fahrenheit: 568395.0446473294, + atomic_unit_of_temperature: 1 + } + }, + constants: { + kelvin: { + celsius: -273.15, + fahrenheit: -459.67 + }, + celsius: { + celsius: -273.15, + fahrenheit: -459.67 + }, + fahrenheit: { + celsius: -273.15, + fahrenheit: -459.67 + }, + atomic_unit_of_temperature: { + celsius: -273.15, + fahrenheit: -459.67 + } + } + }, + force: { + units: [ + 'newton', + 'atomic_unit_of_force' + ], + multipliers: { + newton: { + newton: 1, + atomic_unit_of_force: 12137802.66097955 + }, + atomic_unit_of_force: { + newton: 8.238723498238991e-08, + atomic_unit_of_force: 1 + } + } + }, + pressure: { + units: [ + 'pascal' + ], + multipliers: { + pascal: { + pascal: 1 + } + } + }, + energy: { + units: [ + 'joule', + 'electron_volt', + 'hartree' + ], + multipliers: { + joule: { + joule: 1, + electron_volt: 6.241509074460763e+18, + hartree: 2.2937122783962883e+17 + }, + electron_volt: { + joule: 1.602176634e-19, + electron_volt: 1, + hartree: 0.03674932217565436 + }, + hartree: { + joule: 4.35974472220717e-18, + electron_volt: 27.21138624598847, + hartree: 1 + } + } + }, + power: { + units: [ + 'watt' + ], + multipliers: { + watt: { + watt: 1 + } + } + }, + frequency: { + units: [ + 'hertz' + ], + multipliers: { + hertz: { + hertz: 1 + } + } + }, + electric_potential: { + units: [ + 'volt' + ], + multipliers: { + volt: { + volt: 1 + } + } + }, + capacitance: { + units: [ + 'farad' + ], + multipliers: { + farad: { + farad: 1 + } + } + }, + charge: { + units: [ + 'coulomb', + 'elementary_charge' + ], + multipliers: { + coulomb: { + coulomb: 1, + elementary_charge: 6.241509074460763e+18 + }, + elementary_charge: { + coulomb: 1.602176634e-19, + elementary_charge: 1 + } + } + }, + magnetic_field: { + units: [ + 'tesla' + ], + multipliers: { + tesla: { + tesla: 1 + } + } + }, + magnetic_flux: { + units: [ + 'weber' + ], + multipliers: { + weber: { + weber: 1 + } + } + }, + inductance: { + dimension: 'inductance', + units: [ + 'henry' + ], + multipliers: { + henry: { + henry: 1 + } + } + }, + dimensionless: { + dimension: 'dimensionless', + units: [ + 'dimensionless' + ], + multipliers: { + dimensionless: { + dimensionless: 1 + } + } + } +} +export const unitSystems = { + SI: { + label: 'SI', + description: 'International System of Units (SI)', + units: { + time: 'second', + length: 'meter', + mass: 'kilogram', + current: 'ampere', + substance: 'mole', + luminosity: 'candela', + temperature: 'kelvin', + force: 'newton', + pressure: 'pascal', + energy: 'joule', + power: 'watt', + frequency: 'hertz', + electric_potential: 'volt', + charge: 'coulomb' + } + }, + AU: { + label: 'Atomic units', + description: 'Hartree atomic units', + units: { + time: 'atomic_unit_of_time', + length: 'bohr', + mass: 'electron_mass', + current: 'atomic_unit_of_current', + temperature: 'atomic_unit_of_temperature', + force: 'atomic_unit_of_force', + energy: 'hartree' + } + } +} diff --git a/gui/src/utils.js b/gui/src/utils.js index 6e34e4dc8a9980866c905702e979101b98fdca20..f39bc8038f5cf70c620594092875e9f2c13f659b 100644 --- a/gui/src/utils.js +++ b/gui/src/utils.js @@ -1,4 +1,5 @@ -import { unit } from 'mathjs' +import { parse } from 'mathjs' +import { conversionMap, unitMap, unitSystems } from './units' import { cloneDeep, merge } from 'lodash' export const isEquivalent = (a, b) => { @@ -35,42 +36,57 @@ export const capitalize = (s) => { } /** - * Used to convert numeric values from one unit to another. Works on - * n-dimensional arrays and implemented as a relatively simple for loop for - * performance. If conversion times become an issue, it might be worthwhile to - * look at vectorization with WebAssembly. + * Used to scale numeric values. Works on n-dimensional arrays and implemented + * as a relatively simple for loop for performance. If conversion times become + * an issue, it might be worthwhile to look at vectorization with WebAssembly. * * @param {*} value The values to convert - * @param {*} from Original unit. - * @param {*} to Target unit. + * @param {number} factor Scaling factor to apply. * - * @return {*} A copy of the original data with units converted. + * @return {*} A copy of the original data with numbers scaled. */ -export function convert(value, from, to) { - // Determine the scaling factor - let factor = unit(1, from).toNumber(to) - +export function scale(value, factor) { // Convert arrays - return scale(value, factor) + function scaleRecursive(list, newList) { + let isScalarArray = !Array.isArray(list[0]) + if (isScalarArray) { + for (let i = 0, size = list.length; i < size; ++i) { + newList.push(list[i] * factor) + } + } else { + for (let i = 0, size = list.length; i < size; ++i) { + let iList = [] + newList.push(iList) + scaleRecursive(list[i], iList) + } + } + } + let isArray = Array.isArray(value) + let newValue + if (!isArray) { + newValue = value * factor + } else { + newValue = [] + scaleRecursive(value, newValue) + } + return newValue } /** - * Used to scale numeric values. Works on n-dimensional arrays and implemented - * as a relatively simple for loop for performance. If conversion times become - * an issue, it might be worthwhile to look at vectorization with WebAssembly. + * Used to add a single scalar value to an n-dimensional array. * * @param {*} value The values to convert - * @param {number} factor Scaling factor to apply. + * @param {number} addition Value to add. * * @return {*} A copy of the original data with numbers scaled. */ -export function scale(value, factor) { +export function add(value, addition) { // Convert arrays function scaleRecursive(list, newList) { let isScalarArray = !Array.isArray(list[0]) if (isScalarArray) { for (let i = 0, size = list.length; i < size; ++i) { - newList.push(list[i] * factor) + newList.push(list[i] + addition) } } else { for (let i = 0, size = list.length; i < size; ++i) { @@ -83,7 +99,7 @@ export function scale(value, factor) { let isArray = Array.isArray(value) let newValue if (!isArray) { - newValue = value * factor + newValue = value + addition } else { newValue = [] scaleRecursive(value, newValue) @@ -91,6 +107,120 @@ export function scale(value, factor) { return newValue } +/** + * Used to convert numeric values from SI units to the given unit system. Works + * on n-dimensional arrays. + * + * @param {*} value The values to convert. Can be a scalar or an n-dimensional + * array. + * @param {string} from Original SI unit definition. Can be any algebraic + * combination of SI units, e.g. "1 / meter^2". The unit names should follow + * the definitions provided in the file units.js that is generated by the NOMAD + * CLI. + * @param {*} system Target unit system. A Javascript object where each + * physical quantity (e.g. "length") acts as a key that corresponds to a target + * unit (e.g. "angstrom"). The unit names should follow the definitions + * provided in the file units.js that is generated by the NOMAD CLI. + * + * @return {*} A copy of the original data with units converted. + */ +export function convertSI(value, unit, system, units = true) { + // Modify syntax to comply with math.js evaluation + const from = unit.replace('**', '^') + + // Temperatures require special handling due to the fact that Celsius and + // Fahrenheit are not absolute units and are non-multiplicative. Two kinds of + // temperature conversions are supported: ones with a single temperature unit + // and ones where temperature is used as a part of an expression. If a single + // temperature unit is specified, they are converted normally taking the + // offset into account. If they are used as a part of an expression, they are + // interpreted as ranges and the offset is ignored. + if (from === 'kelvin') { + const unitTo = system['temperature'] + const multiplier = conversionMap['temperature'].multipliers['kelvin'][unitTo] + const constant = conversionMap['temperature'].constants['kelvin'][unitTo] + const label = unitMap['kelvin'].label + let newValues = value + if (multiplier !== 1) { + newValues = scale(newValues, multiplier) + } + if (constant !== undefined) { + newValues = add(newValues, constant) + } + return [newValues, label] + } + + // Gather all units present + const variables = new Set() + const rootNode = parse(from) + rootNode.traverse((node, path, parent) => { + if (node.isSymbolNode) { + variables.add(node.name) + } + }) + + // Check if conversion is required. The unit definition string is standardized + // even if no conversion took place. + let isSI = true + for (const unit of variables) { + const dimension = unitMap[unit].dimension + const unitSI = unitSystems['SI'][dimension] + isSI = unit === unitSI + if (isSI) { + break + } + } + if (isSI) { + if (units) { + const newUnit = convertSILabel(from, system) + return [value, newUnit] + } + return value + } + + // Gather conversion values for each present SI unit + const scope = {} + for (const unitFrom of variables) { + const dimension = unitMap[unitFrom].dimension + const unitTo = system[dimension] + scope[unitFrom] = conversionMap[dimension].multipliers[unitFrom][unitTo] + } + + // Compute the scaling factor by evaluating the unit definition with the + // SI units converted to target system + const code = rootNode.compile() + const factor = code.evaluate(scope) + + // Scale values to new units + let newValues = scale(value, factor) + + // Form new unit definition string by replacing the SI units with the target + if (units) { + const newUnit = convertSILabel(from, system) + return [newValues, newUnit] + } + return newValues +} + +export function convertSILabel(label, system) { + // Form new unit definition string by replacing the SI units with the target + const rootNode = parse(label) + const newRoot = rootNode.transform((node, path, parent) => { + if (node.isSymbolNode) { + const unitFromInfo = unitMap[node.name] + if (unitFromInfo !== undefined) { + const dimension = unitFromInfo.dimension + const unitTo = system[dimension] + const unitToInfo = unitMap[unitTo] + const label = unitToInfo.abbreviation + node.name = label + } + } + return node + }) + return newRoot.toString() +} + /** * Used to calculate the distance between two n-dimensional points, * diff --git a/nomad/cli/dev.py b/nomad/cli/dev.py index e395d67852878ecf2d361866f52448d7525c6907..af3a82cd34410cf085e1b329b3d9fd12a980c595 100644 --- a/nomad/cli/dev.py +++ b/nomad/cli/dev.py @@ -55,6 +55,10 @@ def gui_qa(): @dev.command(help='Generates a JSON with all metainfo.') def metainfo(): import json + print(json.dumps(metainfo_undecorated(), indent=2)) + + +def metainfo_undecorated(): from nomad.metainfo import Package, Environment # TODO the __init_metainfo__() should not be necessary and automatically performed @@ -81,7 +85,7 @@ def metainfo(): for package in Package.registry.values(): export.m_add_sub_section(Environment.packages, package) - print(json.dumps(export.m_to_dict(with_meta=True), indent=2)) + return export.m_to_dict(with_meta=True) @dev.command(help='Generates a JSON with all search quantities.') @@ -345,3 +349,458 @@ def update_parsers_metadata(): local.seek(0) # go to the top local.write(body) local.truncate() + + +@dev.command(help='Creates a Javascript source file containing the required unit conversion factors.') +@click.pass_context +def units(ctx): + import re + import json + from nomad.units import ureg + + # Mapping from unit name to dimension + unit_map = { + # Time + "second": { + "dimension": "time", + "label": "Second", + "abbreviation": "s", + }, + "atomic_unit_of_time": { + "dimension": "time", + "label": "Atomic unit of time", + "abbreviation": "atomic_unit_of_time", + }, + # Length + "meter": { + "dimension": "length", + "label": "Meter", + "abbreviation": "m", + }, + "bohr": { + "dimension": "length", + "label": "Bohr", + "abbreviation": "bohr", + }, + "angstrom": { + "dimension": "length", + "label": "Ångstrom", + "abbreviation": "Å", + }, + # Mass + "kilogram": { + "dimension": "mass", + "label": "Kilogram", + "abbreviation": "kg", + }, + "electron_mass": { + "dimension": "mass", + "label": "Electron mass", + "abbreviation": "mₑ", + }, + "unified_atomic_mass_unit": { + "dimension": "mass", + "label": "Unified atomic mass unit", + "abbreviation": "u", + }, + # Current + "ampere": { + "dimension": "current", + "label": "Ampere", + "abbreviation": "A", + }, + "atomic_unit_of_current": { + "dimension": "current", + "label": "Atomic unit of current", + "abbreviation": "atomic_unit_of_current", + }, + # Substance + "mole": { + "dimension": "substance", + "label": "Mole", + "abbreviation": "mole", + }, + # Luminosity + "candela": { + "dimension": "luminosity", + "label": "Candela", + "abbreviation": "cd", + }, + # Temperature + "kelvin": { + "dimension": "temperature", + "label": "Kelvin", + "abbreviation": "K", + }, + "celsius": { + "dimension": "temperature", + "label": "Celsius", + "abbreviation": "°C", + }, + "fahrenheit": { + "dimension": "temperature", + "label": "Fahrenheit", + "abbreviation": "°F", + }, + "atomic_unit_of_temperature": { + "dimension": "temperature", + "label": "Atomic unit of temperature", + "abbreviation": "atomic_unit_of_temperature", + }, + # Force + "newton": { + "dimension": "force", + "label": "Newton", + "abbreviation": "N", + }, + "atomic_unit_of_force": { + "dimension": "force", + "label": "Atomic unit of force", + "abbreviation": "atomic_unit_of_force", + }, + # Pressure + "pascal": { + "dimension": "pressure", + "label": "Pascal", + "abbreviation": "Pa" + }, + # Energy + "joule": { + "dimension": "energy", + "label": "Joule", + "abbreviation": "J", + }, + "electron_volt": { + "dimension": "energy", + "label": "Electron volt", + "abbreviation": "eV", + }, + "hartree": { + "dimension": "energy", + "label": "Hartree", + "abbreviation": "Ha", + }, + # Power + "watt": { + "dimension": "power", + "label": "Watt", + "abbreviation": "W", + }, + # Frequency + "hertz": { + "dimension": "frequency", + "label": "Hertz", + "abbreviation": "Hz", + }, + # Electric potential + "volt": { + "dimension": "electric_potential", + "label": "Volt", + "abbreviation": "V", + }, + # Capacitance + "farad": { + "dimension": "capacitance", + "label": "Farad", + "abbreviation": "F", + }, + # Charge + "coulomb": { + "dimension": "charge", + "label": "Coulomb", + "abbreviation": "C", + }, + "elementary_charge": { + "dimension": "charge", + "label": "Elementary charge", + "abbreviation": "e", + }, + # Magnetic field + "tesla": { + "dimension": "magnetic_field", + "label": "Tesla", + "abbreviation": "T", + }, + # Magnetic flux + "weber": { + "dimension": "magnetic_flux", + "label": "Weber", + "abbreviation": "Wb", + }, + # Inductance + "henry": { + "dimension": "inductance", + "label": "Henry", + "abbreviation": "H", + }, + # dimensionless + "dimensionless": { + "dimension": "dimensionless", + "label": "Dimensionless", + "abbreviation": "", + }, + } + + # Units that are supported + unit_table = { + # Base units + "time": { + "units": [ + "second", + "atomic_unit_of_time", + ], + "multipliers": {}, + }, + "length": { + "units": [ + "meter", + "bohr", + "angstrom", + ], + "multipliers": {}, + }, + "mass": { + "units": [ + "kilogram", + "electron_mass", + "unified_atomic_mass_unit", + ], + "multipliers": {}, + }, + "current": { + "units": [ + "ampere", + "atomic_unit_of_current", + ], + "multipliers": {}, + }, + "substance": { + "units": [ + "mole", + ], + "multipliers": {}, + }, + "luminosity": { + "units": [ + "candela", + ], + "multipliers": {}, + }, + "temperature": { + "units": [ + "kelvin", + "celsius", + "fahrenheit", + "atomic_unit_of_temperature", + ], + "multipliers": {}, + "constants": {}, + }, + # Derived units + "force": { + "units": [ + "newton", + "atomic_unit_of_force", + ], + "multipliers": {}, + }, + "pressure": { + "units": [ + "pascal", + ], + "multipliers": {}, + }, + "energy": { + "units": [ + "joule", + "electron_volt", + "hartree", + ], + "multipliers": {}, + }, + "power": { + "units": [ + "watt", + ], + "multipliers": {}, + }, + "frequency": { + "units": [ + "hertz", + ], + "multipliers": {}, + }, + "electric_potential": { + "units": [ + "volt", + ], + "multipliers": {}, + }, + "capacitance": { + "units": [ + "farad", + ], + "multipliers": {}, + }, + "charge": { + "units": [ + "coulomb", + "elementary_charge", + ], + "multipliers": {}, + }, + "magnetic_field": { + "units": [ + "tesla", + ], + "multipliers": {}, + }, + "magnetic_flux": { + "units": [ + "weber", + ], + "multipliers": {}, + }, + "inductance": { + "dimension": "inductance", + "units": [ + "henry", + ], + "multipliers": {}, + }, + "dimensionless": { + "dimension": "dimensionless", + "units": [ + "dimensionless", + ], + "multipliers": {}, + }, + } + + # Unit systems + unit_systems = { + "SI": { + "label": "SI", + "description": "International System of Units (SI)", + "units": { + "time": "second", + "length": "meter", + "mass": "kilogram", + "current": "ampere", + "substance": "mole", + "luminosity": "candela", + "temperature": "kelvin", + "force": "newton", + "pressure": "pascal", + "energy": "joule", + "power": "watt", + "frequency": "hertz", + "electric_potential": "volt", + "charge": "coulomb", + }, + }, + "AU": { + "label": "Atomic units", + "description": "Hartree atomic units", + "units": { + "time": "atomic_unit_of_time", + "length": "bohr", + "mass": "electron_mass", + "current": "atomic_unit_of_current", + "temperature": "atomic_unit_of_temperature", + "force": "atomic_unit_of_force", + "energy": "hartree", + } + } + } + + # Precompute conversion factors and possible shifts + for value in unit_table.values(): + units = value["units"] + for i_unit in units: + for j_unit in units: + # Create dictionaries if not present + multipliers = value["multipliers"] + if i_unit not in multipliers: + multipliers[i_unit] = {} + if j_unit not in multipliers[i_unit]: + multipliers[i_unit][j_unit] = {} + + # Check if there is a constant shift: y = ax + b -> y(0) = b. + # Uses delta units for temperatures since only they are + # multiplicative. + y_0 = 0 * getattr(ureg, "delta_" + i_unit, getattr(ureg, i_unit)) + b = y_0.to(getattr(ureg, j_unit)).magnitude + + # Solving the multiplication factor with: + # y(1) = a + b -> a = y(1) - b + # Uses delta units for temperatures since only they are + # multiplicative. Causes minor numerical accuracy issues in the + # factor due to floating point precision + y_1 = 1 * getattr(ureg, "delta_" + i_unit, getattr(ureg, i_unit)) + a = y_1.to(getattr(ureg, "delta_" + j_unit, getattr(ureg, j_unit))).magnitude + multipliers[i_unit][j_unit] = a + + # Create dictionaries if not present + if b != 0: + constants = value["constants"] + if i_unit not in constants: + constants[i_unit] = {} + if j_unit not in constants[i_unit]: + constants[i_unit][j_unit] = {} + constants[i_unit][j_unit] = b + + # Check that all defined units are present in the conversion table + for unit, info in unit_map.items(): + dimension = info["dimension"] + unit_list = unit_table[dimension]["units"] + assert unit in unit_list, "Could not find '{}' in the unit table under the dimension '{}'.".format(unit, dimension) + + # Check unit system correctness + for system in unit_systems.values(): + for dimension, unit in system["units"].items(): + info = unit_map[unit] + assert dimension == info["dimension"] + + # Go through the metainfo and check that all units are defined + all_metainfo = metainfo_undecorated() + units = set() + packages = all_metainfo["packages"] + for package in packages: + sections = package["section_definitions"] + for section in sections: + quantities = section.get("quantities", []) + for quantity in quantities: + unit = quantity.get("unit") + if unit is not None: + parts = unit.split() + for part in parts: + is_operator = part in {"/", "**", "*"} + is_number = True + try: + int(part) + except Exception: + is_number = False + if not is_operator and not is_number: + units.add(part) + for unit in units: + assert unit in unit_map, "The unit '{}' is not defined in the unit definitions.".format(unit) + + # Print unit conversion table and unit systems as a Javascript source file + output = "// Generated by NOMAD CLI. Do not edit manually.\n" + output += "export const unitMap = " + json_string = json.dumps(unit_map, indent=2) + json_string = re.sub(r'(?<!: )"(\S*?)":', '\\1:', json_string) + json_string = json_string.replace("\"", "'") + output += json_string + output += "\nexport const conversionMap = " + json_string = json.dumps(unit_table, indent=2) + json_string = re.sub(r'(?<!: )"(\S*?)":', '\\1:', json_string) + json_string = json_string.replace("\"", "'") + output += json_string + output += "\nexport const unitSystems = " + json_string = json.dumps(unit_systems, indent=2) + json_string = re.sub(r'(?<!: )"(\S*?)":', '\\1:', json_string) + json_string = json_string.replace("\"", "'") + output += json_string + print(output) diff --git a/nomad/units.py b/nomad/units/__init__.py similarity index 78% rename from nomad/units.py rename to nomad/units/__init__.py index 5fbcc0ffe1e9f5f2baf1cc05ddca39823317b64c..780aaf37b0c0fb6d59744613e4fa22e255ef4149 100644 --- a/nomad/units.py +++ b/nomad/units/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018 Markus Scheidgen, empty_task +# Copyright 2018 Markus Scheidgen # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,10 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -""" -This module contains a global unit registry used thoughout the nomad-FAIR -package. -""" +import os from pint import UnitRegistry -ureg = UnitRegistry() +ureg = UnitRegistry(os.path.join(os.path.dirname(__file__), "default_en.txt")) diff --git a/nomad/units/constants_en.txt b/nomad/units/constants_en.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3ecbf1c20fcb0399ada0eb29576566ad8f7e04f --- /dev/null +++ b/nomad/units/constants_en.txt @@ -0,0 +1,73 @@ +# Default Pint constants definition file +# Based on the International System of Units +# Language: english +# Source: https://physics.nist.gov/cuu/Constants/ +# https://physics.nist.gov/PhysRefData/XrayTrans/Html/search.html +# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. + +#### MATHEMATICAL CONSTANTS #### +# As computed by Maxima with fpprec:50 + +pi = 3.1415926535897932384626433832795028841971693993751 = π # pi +tansec = 4.8481368111333441675396429478852851658848753880815e-6 # tangent of 1 arc-second ~ arc_second/radian +ln10 = 2.3025850929940456840179914546843642076011014886288 # natural logarithm of 10 +wien_x = 4.9651142317442763036987591313228939440555849867973 # solution to (x-5)*exp(x)+5 = 0 => x = W(5/exp(5))+5 +wien_u = 2.8214393721220788934031913302944851953458817440731 # solution to (u-3)*exp(u)+3 = 0 => u = W(3/exp(3))+3 + +#### DEFINED EXACT CONSTANTS #### + +speed_of_light = 299792458 m/s = c = c_0 # since 1983 +planck_constant = 6.62607015e-34 J s = h # since May 2019 +elementary_charge = 1.602176634e-19 C = e # since May 2019 +avogadro_number = 6.02214076e23 # since May 2019 +boltzmann_constant = 1.380649e-23 J K^-1 = k = k_B # since May 2019 +standard_gravity = 9.80665 m/s^2 = g_0 = g0 = g_n = gravity # since 1901 +standard_atmosphere = 1.01325e5 Pa = atm = atmosphere # since 1954 +conventional_josephson_constant = 4.835979e14 Hz / V = K_J90 # since Jan 1990 +conventional_von_klitzing_constant = 2.5812807e4 ohm = R_K90 # since Jan 1990 + +#### DERIVED EXACT CONSTANTS #### +# Floating-point conversion may introduce inaccuracies + +zeta = c / (cm/s) = ζ +dirac_constant = h / (2 * π) = ħ = hbar = atomic_unit_of_action = a_u_action +avogadro_constant = avogadro_number * mol^-1 = N_A +molar_gas_constant = k * N_A = R +faraday_constant = e * N_A +conductance_quantum = 2 * e ** 2 / h = G_0 +magnetic_flux_quantum = h / (2 * e) = Φ_0 = Phi_0 +josephson_constant = 2 * e / h = K_J +von_klitzing_constant = h / e ** 2 = R_K +stefan_boltzmann_constant = 2 / 15 * π ** 5 * k ** 4 / (h ** 3 * c ** 2) = σ = sigma +first_radiation_constant = 2 * π * h * c ** 2 = c_1 +second_radiation_constant = h * c / k = c_2 +wien_wavelength_displacement_law_constant = h * c / (k * wien_x) +wien_frequency_displacement_law_constant = wien_u * k / h + +#### MEASURED CONSTANTS #### +# Recommended CODATA-2018 values +# To some extent, what is measured and what is derived is a bit arbitrary. +# The choice of measured constants is based on convenience and on available uncertainty. +# The uncertainty in the last significant digits is given in parentheses as a comment. + +newtonian_constant_of_gravitation = 6.67430e-11 m^3/(kg s^2) = _ = gravitational_constant # (15) +rydberg_constant = 1.0973731568160e7 * m^-1 = R_∞ = R_inf # (21) +electron_g_factor = -2.00231930436256 = g_e # (35) +atomic_mass_constant = 1.66053906660e-27 kg = m_u # (50) +electron_mass = 9.1093837015e-31 kg = m_e = atomic_unit_of_mass = a_u_mass # (28) +proton_mass = 1.67262192369e-27 kg = m_p # (51) +neutron_mass = 1.67492749804e-27 kg = m_n # (95) +lattice_spacing_of_Si = 1.920155716e-10 m = d_220 # (32) +K_alpha_Cu_d_220 = 0.80232719 # (22) +K_alpha_Mo_d_220 = 0.36940604 # (19) +K_alpha_W_d_220 = 0.108852175 # (98) + +#### DERIVED CONSTANTS #### + +fine_structure_constant = (2 * h * R_inf / (m_e * c)) ** 0.5 = α = alpha +vacuum_permeability = 2 * α * h / (e ** 2 * c) = µ_0 = mu_0 = mu0 = magnetic_constant +vacuum_permittivity = e ** 2 / (2 * α * h * c) = ε_0 = epsilon_0 = eps_0 = eps0 = electric_constant +impedance_of_free_space = 2 * α * h / e ** 2 = Z_0 = characteristic_impedance_of_vacuum +coulomb_constant = α * hbar * c / e ** 2 = k_C +classical_electron_radius = α * hbar / (m_e * c) = r_e +thomson_cross_section = 8 / 3 * π * r_e ** 2 = σ_e = sigma_e diff --git a/nomad/units/default_en.txt b/nomad/units/default_en.txt new file mode 100644 index 0000000000000000000000000000000000000000..916e924c74a4e60ba39360c0d97d152d2e588bb9 --- /dev/null +++ b/nomad/units/default_en.txt @@ -0,0 +1,848 @@ +# Default Pint units definition file +# Based on the International System of Units +# Language: english +# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. + +# Syntax +# ====== +# Units +# ----- +# <canonical name> = <relation to another unit or dimension> [= <symbol>] [= <alias>] [ = <alias> ] [...] +# +# The canonical name and aliases should be expressed in singular form. +# Pint automatically deals with plurals built by adding 's' to the singular form; plural +# forms that don't follow this rule should be instead explicitly listed as aliases. +# +# If a unit has no symbol and one wants to define aliases, then the symbol should be +# conventionally set to _. +# +# Example: +# millennium = 1e3 * year = _ = millennia +# +# +# Prefixes +# -------- +# <prefix>- = <amount> [= <symbol>] [= <alias>] [ = <alias> ] [...] +# +# Example: +# deca- = 1e+1 = da- = deka- +# +# +# Derived dimensions +# ------------------ +# [dimension name] = <relation to other dimensions> +# +# Example: +# [density] = [mass] / [volume] +# +# Note that primary dimensions don't need to be declared; they can be +# defined for the first time in a unit definition. +# E.g. see below `meter = [length]` +# +# +# Additional aliases +# ------------------ +# @alias <canonical name or previous alias> = <alias> [ = <alias> ] [...] +# +# Used to add aliases to already existing unit definitions. +# Particularly useful when one wants to enrich definitions +# from defaults_en.txt with custom aliases. +# +# Example: +# @alias meter = my_meter + +# See also: https://pint.readthedocs.io/en/latest/defining.html + +@defaults + group = international + system = mks +@end + + +#### PREFIXES #### + +# decimal prefixes +yocto- = 1e-24 = y- +zepto- = 1e-21 = z- +atto- = 1e-18 = a- +femto- = 1e-15 = f- +pico- = 1e-12 = p- +nano- = 1e-9 = n- +micro- = 1e-6 = µ- = u- +milli- = 1e-3 = m- +centi- = 1e-2 = c- +deci- = 1e-1 = d- +deca- = 1e+1 = da- = deka- +hecto- = 1e2 = h- +kilo- = 1e3 = k- +mega- = 1e6 = M- +giga- = 1e9 = G- +tera- = 1e12 = T- +peta- = 1e15 = P- +exa- = 1e18 = E- +zetta- = 1e21 = Z- +yotta- = 1e24 = Y- + +# binary_prefixes +kibi- = 2**10 = Ki- +mebi- = 2**20 = Mi- +gibi- = 2**30 = Gi- +tebi- = 2**40 = Ti- +pebi- = 2**50 = Pi- +exbi- = 2**60 = Ei- +zebi- = 2**70 = Zi- +yobi- = 2**80 = Yi- + +# extra_prefixes +semi- = 0.5 = _ = demi- +sesqui- = 1.5 + + +#### BASE UNITS #### + +meter = [length] = m = metre +second = [time] = s = sec +ampere = [current] = A = amp +candela = [luminosity] = cd = candle +gram = [mass] = g +mole = [substance] = mol +kelvin = [temperature]; offset: 0 = K = degK = °K = degree_Kelvin = degreeK # older names supported for compatibility +radian = [] = rad +neper = [] = Np +bit = [] +count = [] + + +#### CONSTANTS #### + +@import constants_en.txt + + +#### UNITS #### +# Common and less common, grouped by quantity. +# Conversion factors are exact (except when noted), +# although floating-point conversion may introduce inaccuracies + +# Angle +turn = 2 * π * radian = _ = revolution = cycle = circle +degree = π / 180 * radian = deg = arcdeg = arcdegree = angular_degree +arcminute = degree / 60 = arcmin = arc_minute = angular_minute +arcsecond = arcminute / 60 = arcsec = arc_second = angular_second +milliarcsecond = 1e-3 * arcsecond = mas +grade = π / 200 * radian = grad = gon +mil = π / 32000 * radian + +# Solid angle +steradian = radian ** 2 = sr +square_degree = (π / 180) ** 2 * sr = sq_deg = sqdeg + +# Logarithmic ratio +bel = 0.5 * ln10 * neper + +# Information +byte = 8 * bit = B = octet +baud = bit / second = Bd = bps + +# Length +angstrom = 1e-10 * meter = Å = ångström = Å +micron = micrometer = µ +fermi = femtometer = fm +light_year = speed_of_light * julian_year = ly = lightyear +astronomical_unit = 149597870700 * meter = au # since Aug 2012 +parsec = 1 / tansec * astronomical_unit = pc +nautical_mile = 1852 * meter = nmi +bohr = hbar / (alpha * m_e * c) = a_0 = a0 = bohr_radius = atomic_unit_of_length = a_u_length +x_unit_Cu = K_alpha_Cu_d_220 * d_220 / 1537.4 = Xu_Cu +x_unit_Mo = K_alpha_Mo_d_220 * d_220 / 707.831 = Xu_Mo +angstrom_star = K_alpha_W_d_220 * d_220 / 0.2090100 = Å_star +planck_length = (hbar * gravitational_constant / c ** 3) ** 0.5 + +# Mass +metric_ton = 1e3 * kilogram = t = tonne +unified_atomic_mass_unit = atomic_mass_constant = u = amu +dalton = atomic_mass_constant = Da +grain = 64.79891 * milligram = gr +gamma_mass = microgram +carat = 200 * milligram = ct = karat +planck_mass = (hbar * c / gravitational_constant) ** 0.5 + +# Time +minute = 60 * second = min +hour = 60 * minute = hr +day = 24 * hour = d +week = 7 * day +fortnight = 2 * week +year = 365.25 * day = a = yr = julian_year +month = year / 12 +decade = 10 * year +century = 100 * year = _ = centuries +millennium = 1e3 * year = _ = millennia +eon = 1e9 * year +shake = 1e-8 * second +svedberg = 1e-13 * second +atomic_unit_of_time = hbar / E_h = a_u_time +gregorian_year = 365.2425 * day +sidereal_year = 365.256363004 * day # approximate, as of J2000 epoch +tropical_year = 365.242190402 * day # approximate, as of J2000 epoch +common_year = 365 * day +leap_year = 366 * day +sidereal_day = day / 1.00273790935079524 # approximate +sidereal_month = 27.32166155 * day # approximate +tropical_month = 27.321582 * day # approximate +synodic_month = 29.530589 * day = _ = lunar_month # approximate +planck_time = (hbar * gravitational_constant / c ** 5) ** 0.5 + +# Temperature +degree_Celsius = kelvin; offset: 273.15 = °C = celsius = degC = degreeC +degree_Rankine = 5 / 9 * kelvin; offset: 0 = °R = rankine = degR = degreeR +degree_Fahrenheit = 5 / 9 * kelvin; offset: 233.15 + 200 / 9 = °F = fahrenheit = degF = degreeF +degree_Reaumur = 4 / 5 * kelvin; offset: 273.15 = °Re = reaumur = degRe = degreeRe = degree_Réaumur = réaumur +atomic_unit_of_temperature = E_h / k = a_u_temp +planck_temperature = (hbar * c ** 5 / gravitational_constant / k ** 2) ** 0.5 + +# Area +[area] = [length] ** 2 +are = 100 * meter ** 2 +barn = 1e-28 * meter ** 2 = b +darcy = centipoise * centimeter ** 2 / (second * atmosphere) +hectare = 100 * are = ha + +# Volume +[volume] = [length] ** 3 +liter = decimeter ** 3 = l = L = litre +cubic_centimeter = centimeter ** 3 = cc +lambda = microliter = λ +stere = meter ** 3 + +# Frequency +[frequency] = 1 / [time] +hertz = 1 / second = Hz +revolutions_per_minute = revolution / minute = rpm +revolutions_per_second = revolution / second = rps +counts_per_second = count / second = cps + +# Wavenumber +[wavenumber] = 1 / [length] +reciprocal_centimeter = 1 / cm = cm_1 = kayser + +# Velocity +[velocity] = [length] / [time] = [speed] +knot = nautical_mile / hour = kt = knot_international = international_knot +mile_per_hour = mile / hour = mph = MPH +kilometer_per_hour = kilometer / hour = kph = KPH +kilometer_per_second = kilometer / second = kps +meter_per_second = meter / second = mps +foot_per_second = foot / second = fps + +# Acceleration +[acceleration] = [velocity] / [time] +galileo = centimeter / second ** 2 = Gal + +# Force +[force] = [mass] * [acceleration] +newton = kilogram * meter / second ** 2 = N +dyne = gram * centimeter / second ** 2 = dyn +force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond +force_gram = g_0 * gram = gf = gram_force +force_metric_ton = g_0 * metric_ton = tf = metric_ton_force = force_t = t_force +atomic_unit_of_force = E_h / a_0 = a_u_force + +# Energy +[energy] = [force] * [length] +joule = newton * meter = J +erg = dyne * centimeter +watt_hour = watt * hour = Wh = watthour +electron_volt = e * volt = eV +rydberg = h * c * R_inf = Ry +hartree = 2 * rydberg = E_h = Eh = hartree_energy = atomic_unit_of_energy = a_u_energy +calorie = 4.184 * joule = cal = thermochemical_calorie = cal_th +international_calorie = 4.1868 * joule = cal_it = international_steam_table_calorie +fifteen_degree_calorie = 4.1855 * joule = cal_15 +british_thermal_unit = 1055.056 * joule = Btu = BTU = Btu_iso +international_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * international_calorie = Btu_it +thermochemical_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * calorie = Btu_th +quadrillion_Btu = 1e15 * Btu = quad +therm = 1e5 * Btu = thm = EC_therm +US_therm = 1.054804e8 * joule # approximate, no exact definition +ton_TNT = 1e9 * calorie = tTNT +tonne_of_oil_equivalent = 1e10 * international_calorie = toe +atmosphere_liter = atmosphere * liter = atm_l + +# Power +[power] = [energy] / [time] +watt = joule / second = W +volt_ampere = volt * ampere = VA +horsepower = 550 * foot * force_pound / second = hp = UK_horsepower = hydraulic_horsepower +boiler_horsepower = 33475 * Btu / hour # unclear which Btu +metric_horsepower = 75 * force_kilogram * meter / second +electrical_horsepower = 746 * watt +refrigeration_ton = 12e3 * Btu / hour = _ = ton_of_refrigeration # approximate, no exact definition +standard_liter_per_minute = atmosphere * liter / minute = slpm = slm +conventional_watt_90 = K_J90 ** 2 * R_K90 / (K_J ** 2 * R_K) * watt = W_90 + +# Momentum +[momentum] = [length] * [mass] / [time] + +# Density (as auxiliary for pressure) +[density] = [mass] / [volume] +mercury = 13.5951 * kilogram / liter = Hg = Hg_0C = Hg_32F = conventional_mercury +water = 1.0 * kilogram / liter = H2O = conventional_water +mercury_60F = 13.5568 * kilogram / liter = Hg_60F # approximate +water_39F = 0.999972 * kilogram / liter = water_4C # approximate +water_60F = 0.999001 * kilogram / liter # approximate + +# Pressure +[pressure] = [force] / [area] +pascal = newton / meter ** 2 = Pa +barye = dyne / centimeter ** 2 = Ba = barie = barad = barrie = baryd +bar = 1e5 * pascal +technical_atmosphere = kilogram * g_0 / centimeter ** 2 = at +torr = atm / 760 +pound_force_per_square_inch = force_pound / inch ** 2 = psi +kip_per_square_inch = kip / inch ** 2 = ksi +millimeter_Hg = millimeter * Hg * g_0 = mmHg = mm_Hg = millimeter_Hg_0C +centimeter_Hg = centimeter * Hg * g_0 = cmHg = cm_Hg = centimeter_Hg_0C +inch_Hg = inch * Hg * g_0 = inHg = in_Hg = inch_Hg_32F +inch_Hg_60F = inch * Hg_60F * g_0 +inch_H2O_39F = inch * water_39F * g_0 +inch_H2O_60F = inch * water_60F * g_0 +foot_H2O = foot * water * g_0 = ftH2O = feet_H2O +centimeter_H2O = centimeter * water * g_0 = cmH2O = cm_H2O + +# Torque +[torque] = [force] * [length] +foot_pound = foot * force_pound = ft_lb = footpound + +# Viscosity +[viscosity] = [pressure] * [time] +poise = 0.1 * Pa * second = P +reyn = psi * second + +# Kinematic viscosity +[kinematic_viscosity] = [area] / [time] +stokes = centimeter ** 2 / second = St + +# Fluidity +[fluidity] = 1 / [viscosity] +rhe = 1 / poise + +# Amount of substance +particle = 1 / N_A = _ = molec = molecule + +# Concentration +[concentration] = [substance] / [volume] +molar = mole / liter = M + +# Catalytic activity +[activity] = [substance] / [time] +katal = mole / second = kat +enzyme_unit = micromole / minute = U = enzymeunit + +# Entropy +[entropy] = [energy] / [temperature] +clausius = calorie / kelvin = Cl + +# Molar entropy +[molar_entropy] = [entropy] / [substance] +entropy_unit = calorie / kelvin / mole = eu + +# Radiation +becquerel = counts_per_second = Bq +curie = 3.7e10 * becquerel = Ci +rutherford = 1e6 * becquerel = Rd +gray = joule / kilogram = Gy +sievert = joule / kilogram = Sv +rads = 0.01 * gray +rem = 0.01 * sievert +roentgen = 2.58e-4 * coulomb / kilogram = _ = röntgen # approximate, depends on medium + +# Heat transimission +[heat_transmission] = [energy] / [area] +peak_sun_hour = 1e3 * watt_hour / meter ** 2 = PSH +langley = thermochemical_calorie / centimeter ** 2 = Ly + +# Luminance +[luminance] = [luminosity] / [area] +nit = candela / meter ** 2 +stilb = candela / centimeter ** 2 +lambert = 1 / π * candela / centimeter ** 2 + +# Luminous flux +[luminous_flux] = [luminosity] +lumen = candela * steradian = lm + +# Illuminance +[illuminance] = [luminous_flux] / [area] +lux = lumen / meter ** 2 = lx + +# Intensity +[intensity] = [power] / [area] +atomic_unit_of_intensity = 0.5 * ε_0 * c * atomic_unit_of_electric_field ** 2 = a_u_intensity + +# Current +biot = 10 * ampere = Bi +abampere = biot = abA +atomic_unit_of_current = e / atomic_unit_of_time = a_u_current +mean_international_ampere = mean_international_volt / mean_international_ohm = A_it +US_international_ampere = US_international_volt / US_international_ohm = A_US +conventional_ampere_90 = K_J90 * R_K90 / (K_J * R_K) * ampere = A_90 +planck_current = (c ** 6 / gravitational_constant / k_C) ** 0.5 + +# Charge +[charge] = [current] * [time] +coulomb = ampere * second = C +abcoulomb = 10 * C = abC +faraday = e * N_A * mole +conventional_coulomb_90 = K_J90 * R_K90 / (K_J * R_K) * coulomb = C_90 + +# Electric potential +[electric_potential] = [energy] / [charge] +volt = joule / coulomb = V +abvolt = 1e-8 * volt = abV +mean_international_volt = 1.00034 * volt = V_it # approximate +US_international_volt = 1.00033 * volt = V_US # approximate +conventional_volt_90 = K_J90 / K_J * volt = V_90 + +# Electric field +[electric_field] = [electric_potential] / [length] +atomic_unit_of_electric_field = e * k_C / a_0 ** 2 = a_u_electric_field + +# Electric displacement field +[electric_displacement_field] = [charge] / [area] + +# Resistance +[resistance] = [electric_potential] / [current] +ohm = volt / ampere = Ω +abohm = 1e-9 * ohm = abΩ +mean_international_ohm = 1.00049 * ohm = Ω_it = ohm_it # approximate +US_international_ohm = 1.000495 * ohm = Ω_US = ohm_US # approximate +conventional_ohm_90 = R_K / R_K90 * ohm = Ω_90 = ohm_90 + +# Resistivity +[resistivity] = [resistance] * [length] + +# Conductance +[conductance] = [current] / [electric_potential] +siemens = ampere / volt = S = mho +absiemens = 1e9 * siemens = abS = abmho + +# Capacitance +[capacitance] = [charge] / [electric_potential] +farad = coulomb / volt = F +abfarad = 1e9 * farad = abF +conventional_farad_90 = R_K90 / R_K * farad = F_90 + +# Inductance +[inductance] = [magnetic_flux] / [current] +henry = weber / ampere = H +abhenry = 1e-9 * henry = abH +conventional_henry_90 = R_K / R_K90 * henry = H_90 + +# Magnetic flux +[magnetic_flux] = [electric_potential] * [time] +weber = volt * second = Wb +unit_pole = µ_0 * biot * centimeter + +# Magnetic field +[magnetic_field] = [magnetic_flux] / [area] +tesla = weber / meter ** 2 = T +gamma = 1e-9 * tesla = γ + +# Magnetomotive force +[magnetomotive_force] = [current] +ampere_turn = ampere = At +biot_turn = biot +gilbert = 1 / (4 * π) * biot_turn = Gb + +# Magnetic field strength +[magnetic_field_strength] = [current] / [length] + +# Electric dipole moment +[electric_dipole] = [charge] * [length] +debye = 1e-9 / ζ * coulomb * angstrom = D # formally 1 D = 1e-10 Fr*Å, but we generally want to use it outside the Gaussian context + +# Electric quadrupole moment +[electric_quadrupole] = [charge] * [area] +buckingham = debye * angstrom + +# Magnetic dipole moment +[magnetic_dipole] = [current] * [area] +bohr_magneton = e * hbar / (2 * m_e) = µ_B = mu_B +nuclear_magneton = e * hbar / (2 * m_p) = µ_N = mu_N + + +#### UNIT GROUPS #### +# Mostly for length, area, volume, mass, force +# (customary or specialized units) + +@group USCSLengthInternational + thou = 1e-3 * inch = th = mil_length + inch = yard / 36 = in = international_inch = inches = international_inches + hand = 4 * inch + foot = yard / 3 = ft = international_foot = feet = international_feet + yard = 0.9144 * meter = yd = international_yard # since Jul 1959 + mile = 1760 * yard = mi = international_mile + + circular_mil = π / 4 * mil_length ** 2 = cmil + square_inch = inch ** 2 = sq_in = square_inches + square_foot = foot ** 2 = sq_ft = square_feet + square_yard = yard ** 2 = sq_yd + square_mile = mile ** 2 = sq_mi + + cubic_inch = in ** 3 = cu_in + cubic_foot = ft ** 3 = cu_ft = cubic_feet + cubic_yard = yd ** 3 = cu_yd +@end + +@group USCSLengthSurvey + link = 1e-2 * chain = li = survey_link + survey_foot = 1200 / 3937 * meter = sft + fathom = 6 * survey_foot + rod = 16.5 * survey_foot = rd = pole = perch + chain = 4 * rod + furlong = 40 * rod = fur + cables_length = 120 * fathom + survey_mile = 5280 * survey_foot = smi = us_statute_mile + league = 3 * survey_mile + + square_rod = rod ** 2 = sq_rod = sq_pole = sq_perch + acre = 10 * chain ** 2 + square_survey_mile = survey_mile ** 2 = _ = section + square_league = league ** 2 + + acre_foot = acre * survey_foot = _ = acre_feet +@end + +@group USCSDryVolume + dry_pint = bushel / 64 = dpi = US_dry_pint + dry_quart = bushel / 32 = dqt = US_dry_quart + dry_gallon = bushel / 8 = dgal = US_dry_gallon + peck = bushel / 4 = pk + bushel = 2150.42 cubic_inch = bu + dry_barrel = 7056 cubic_inch = _ = US_dry_barrel + board_foot = ft * ft * in = FBM = board_feet = BF = BDFT = super_foot = superficial_foot = super_feet = superficial_feet +@end + +@group USCSLiquidVolume + minim = pint / 7680 + fluid_dram = pint / 128 = fldr = fluidram = US_fluid_dram = US_liquid_dram + fluid_ounce = pint / 16 = floz = US_fluid_ounce = US_liquid_ounce + gill = pint / 4 = gi = liquid_gill = US_liquid_gill + pint = quart / 2 = pt = liquid_pint = US_pint + fifth = gallon / 5 = _ = US_liquid_fifth + quart = gallon / 4 = qt = liquid_quart = US_liquid_quart + gallon = 231 * cubic_inch = gal = liquid_gallon = US_liquid_gallon +@end + +@group USCSVolumeOther + teaspoon = fluid_ounce / 6 = tsp + tablespoon = fluid_ounce / 2 = tbsp + shot = 3 * tablespoon = jig = US_shot + cup = pint / 2 = cp = liquid_cup = US_liquid_cup + barrel = 31.5 * gallon = bbl + oil_barrel = 42 * gallon = oil_bbl + beer_barrel = 31 * gallon = beer_bbl + hogshead = 63 * gallon +@end + +@group Avoirdupois + dram = pound / 256 = dr = avoirdupois_dram = avdp_dram = drachm + ounce = pound / 16 = oz = avoirdupois_ounce = avdp_ounce + pound = 7e3 * grain = lb = avoirdupois_pound = avdp_pound + stone = 14 * pound + quarter = 28 * stone + bag = 94 * pound + hundredweight = 100 * pound = cwt = short_hundredweight + long_hundredweight = 112 * pound + ton = 2e3 * pound = _ = short_ton + long_ton = 2240 * pound + slug = g_0 * pound * second ** 2 / foot + slinch = g_0 * pound * second ** 2 / inch = blob = slugette + + force_ounce = g_0 * ounce = ozf = ounce_force + force_pound = g_0 * pound = lbf = pound_force + force_ton = g_0 * ton = _ = ton_force = force_short_ton = short_ton_force + force_long_ton = g_0 * long_ton = _ = long_ton_force + kip = 1e3 * force_pound + poundal = pound * foot / second ** 2 = pdl +@end + +@group AvoirdupoisUK using Avoirdupois + UK_hundredweight = long_hundredweight = UK_cwt + UK_ton = long_ton + UK_force_ton = force_long_ton = _ = UK_ton_force +@end + +@group AvoirdupoisUS using Avoirdupois + US_hundredweight = hundredweight = US_cwt + US_ton = ton + US_force_ton = force_ton = _ = US_ton_force +@end + +@group Troy + pennyweight = 24 * grain = dwt + troy_ounce = 480 * grain = toz = ozt + troy_pound = 12 * troy_ounce = tlb = lbt +@end + +@group Apothecary + scruple = 20 * grain + apothecary_dram = 3 * scruple = ap_dr + apothecary_ounce = 8 * apothecary_dram = ap_oz + apothecary_pound = 12 * apothecary_ounce = ap_lb +@end + +@group ImperialVolume + imperial_minim = imperial_fluid_ounce / 480 + imperial_fluid_scruple = imperial_fluid_ounce / 24 + imperial_fluid_drachm = imperial_fluid_ounce / 8 = imperial_fldr = imperial_fluid_dram + imperial_fluid_ounce = imperial_pint / 20 = imperial_floz = UK_fluid_ounce + imperial_gill = imperial_pint / 4 = imperial_gi = UK_gill + imperial_cup = imperial_pint / 2 = imperial_cp = UK_cup + imperial_pint = imperial_gallon / 8 = imperial_pt = UK_pint + imperial_quart = imperial_gallon / 4 = imperial_qt = UK_quart + imperial_gallon = 4.54609 * liter = imperial_gal = UK_gallon + imperial_peck = 2 * imperial_gallon = imperial_pk = UK_pk + imperial_bushel = 8 * imperial_gallon = imperial_bu = UK_bushel + imperial_barrel = 36 * imperial_gallon = imperial_bbl = UK_bbl +@end + +@group Printer + pica = inch / 6 = _ = printers_pica + point = pica / 12 = pp = printers_point = big_point = bp + didot = 1 / 2660 * m + cicero = 12 * didot + tex_point = inch / 72.27 + tex_pica = 12 * tex_point + tex_didot = 1238 / 1157 * tex_point + tex_cicero = 12 * tex_didot + scaled_point = tex_point / 65536 + css_pixel = inch / 96 = px + + pixel = [printing_unit] = _ = dot = pel = picture_element + pixels_per_centimeter = pixel / cm = PPCM + pixels_per_inch = pixel / inch = dots_per_inch = PPI = ppi = DPI = printers_dpi + bits_per_pixel = bit / pixel = bpp +@end + +@group Textile + tex = gram / kilometer = Tt + dtex = decitex + denier = gram / (9 * kilometer) = den = Td + jute = pound / (14400 * yard) = Tj + aberdeen = jute = Ta + RKM = gf / tex + + number_english = 840 * yard / pound = Ne = NeC = ECC + number_meter = kilometer / kilogram = Nm +@end + + +#### CGS ELECTROMAGNETIC UNITS #### + +# === Gaussian system of units === +@group Gaussian + franklin = erg ** 0.5 * centimeter ** 0.5 = Fr = statcoulomb = statC = esu + statvolt = erg / franklin = statV + statampere = franklin / second = statA + gauss = dyne / franklin = G + maxwell = gauss * centimeter ** 2 = Mx + oersted = dyne / maxwell = Oe = ørsted + statohm = statvolt / statampere = statΩ + statfarad = franklin / statvolt = statF + statmho = statampere / statvolt +@end +# Note this system is not commensurate with SI, as ε_0 and µ_0 disappear; +# some quantities with different dimensions in SI have the same +# dimensions in the Gaussian system (e.g. [Mx] = [Fr], but [Wb] != [C]), +# and therefore the conversion factors depend on the context (not in pint sense) +[gaussian_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] +[gaussian_current] = [gaussian_charge] / [time] +[gaussian_electric_potential] = [gaussian_charge] / [length] +[gaussian_electric_field] = [gaussian_electric_potential] / [length] +[gaussian_electric_displacement_field] = [gaussian_charge] / [area] +[gaussian_electric_flux] = [gaussian_charge] +[gaussian_electric_dipole] = [gaussian_charge] * [length] +[gaussian_electric_quadrupole] = [gaussian_charge] * [area] +[gaussian_magnetic_field] = [force] / [gaussian_charge] +[gaussian_magnetic_field_strength] = [gaussian_magnetic_field] +[gaussian_magnetic_flux] = [gaussian_magnetic_field] * [area] +[gaussian_magnetic_dipole] = [energy] / [gaussian_magnetic_field] +[gaussian_resistance] = [gaussian_electric_potential] / [gaussian_current] +[gaussian_resistivity] = [gaussian_resistance] * [length] +[gaussian_capacitance] = [gaussian_charge] / [gaussian_electric_potential] +[gaussian_inductance] = [gaussian_electric_potential] * [time] / [gaussian_current] +[gaussian_conductance] = [gaussian_current] / [gaussian_electric_potential] +@context Gaussian = Gau + [gaussian_charge] -> [charge]: value / k_C ** 0.5 + [charge] -> [gaussian_charge]: value * k_C ** 0.5 + [gaussian_current] -> [current]: value / k_C ** 0.5 + [current] -> [gaussian_current]: value * k_C ** 0.5 + [gaussian_electric_potential] -> [electric_potential]: value * k_C ** 0.5 + [electric_potential] -> [gaussian_electric_potential]: value / k_C ** 0.5 + [gaussian_electric_field] -> [electric_field]: value * k_C ** 0.5 + [electric_field] -> [gaussian_electric_field]: value / k_C ** 0.5 + [gaussian_electric_displacement_field] -> [electric_displacement_field]: value / (4 * π / ε_0) ** 0.5 + [electric_displacement_field] -> [gaussian_electric_displacement_field]: value * (4 * π / ε_0) ** 0.5 + [gaussian_electric_dipole] -> [electric_dipole]: value / k_C ** 0.5 + [electric_dipole] -> [gaussian_electric_dipole]: value * k_C ** 0.5 + [gaussian_electric_quadrupole] -> [electric_quadrupole]: value / k_C ** 0.5 + [electric_quadrupole] -> [gaussian_electric_quadrupole]: value * k_C ** 0.5 + [gaussian_magnetic_field] -> [magnetic_field]: value / (4 * π / µ_0) ** 0.5 + [magnetic_field] -> [gaussian_magnetic_field]: value * (4 * π / µ_0) ** 0.5 + [gaussian_magnetic_flux] -> [magnetic_flux]: value / (4 * π / µ_0) ** 0.5 + [magnetic_flux] -> [gaussian_magnetic_flux]: value * (4 * π / µ_0) ** 0.5 + [gaussian_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π * µ_0) ** 0.5 + [magnetic_field_strength] -> [gaussian_magnetic_field_strength]: value * (4 * π * µ_0) ** 0.5 + [gaussian_magnetic_dipole] -> [magnetic_dipole]: value * (4 * π / µ_0) ** 0.5 + [magnetic_dipole] -> [gaussian_magnetic_dipole]: value / (4 * π / µ_0) ** 0.5 + [gaussian_resistance] -> [resistance]: value * k_C + [resistance] -> [gaussian_resistance]: value / k_C + [gaussian_resistivity] -> [resistivity]: value * k_C + [resistivity] -> [gaussian_resistivity]: value / k_C + [gaussian_capacitance] -> [capacitance]: value / k_C + [capacitance] -> [gaussian_capacitance]: value * k_C + [gaussian_inductance] -> [inductance]: value * k_C + [inductance] -> [gaussian_inductance]: value / k_C + [gaussian_conductance] -> [conductance]: value / k_C + [conductance] -> [gaussian_conductance]: value * k_C +@end + +# === ESU system of units === +# (where different from Gaussian) +# See note for Gaussian system too +@group ESU using Gaussian + statweber = statvolt * second = statWb + stattesla = statweber / centimeter ** 2 = statT + stathenry = statweber / statampere = statH +@end +[esu_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] +[esu_current] = [esu_charge] / [time] +[esu_electric_potential] = [esu_charge] / [length] +[esu_magnetic_flux] = [esu_electric_potential] * [time] +[esu_magnetic_field] = [esu_magnetic_flux] / [area] +[esu_magnetic_field_strength] = [esu_current] / [length] +[esu_magnetic_dipole] = [esu_current] * [area] +@context ESU = esu + [esu_magnetic_field] -> [magnetic_field]: value * k_C ** 0.5 + [magnetic_field] -> [esu_magnetic_field]: value / k_C ** 0.5 + [esu_magnetic_flux] -> [magnetic_flux]: value * k_C ** 0.5 + [magnetic_flux] -> [esu_magnetic_flux]: value / k_C ** 0.5 + [esu_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π / ε_0) ** 0.5 + [magnetic_field_strength] -> [esu_magnetic_field_strength]: value * (4 * π / ε_0) ** 0.5 + [esu_magnetic_dipole] -> [magnetic_dipole]: value / k_C ** 0.5 + [magnetic_dipole] -> [esu_magnetic_dipole]: value * k_C ** 0.5 +@end + + +#### CONVERSION CONTEXTS #### + +@context(n=1) spectroscopy = sp + # n index of refraction of the medium. + [length] <-> [frequency]: speed_of_light / n / value + [frequency] -> [energy]: planck_constant * value + [energy] -> [frequency]: value / planck_constant + # allow wavenumber / kayser + [wavenumber] <-> [length]: 1 / value +@end + +@context boltzmann + [temperature] -> [energy]: boltzmann_constant * value + [energy] -> [temperature]: value / boltzmann_constant +@end + +@context energy + [energy] -> [energy] / [substance]: value * N_A + [energy] / [substance] -> [energy]: value / N_A + [energy] -> [mass]: value / c ** 2 + [mass] -> [energy]: value * c ** 2 +@end + +@context(mw=0,volume=0,solvent_mass=0) chemistry = chem + # mw is the molecular weight of the species + # volume is the volume of the solution + # solvent_mass is the mass of solvent in the solution + + # moles -> mass require the molecular weight + [substance] -> [mass]: value * mw + [mass] -> [substance]: value / mw + + # moles/volume -> mass/volume and moles/mass -> mass/mass + # require the molecular weight + [substance] / [volume] -> [mass] / [volume]: value * mw + [mass] / [volume] -> [substance] / [volume]: value / mw + [substance] / [mass] -> [mass] / [mass]: value * mw + [mass] / [mass] -> [substance] / [mass]: value / mw + + # moles/volume -> moles requires the solution volume + [substance] / [volume] -> [substance]: value * volume + [substance] -> [substance] / [volume]: value / volume + + # moles/mass -> moles requires the solvent (usually water) mass + [substance] / [mass] -> [substance]: value * solvent_mass + [substance] -> [substance] / [mass]: value / solvent_mass + + # moles/mass -> moles/volume require the solvent mass and the volume + [substance] / [mass] -> [substance]/[volume]: value * solvent_mass / volume + [substance] / [volume] -> [substance] / [mass]: value / solvent_mass * volume + +@end + +@context textile + # Allow switching between Direct count system (i.e. tex) and + # Indirect count system (i.e. Ne, Nm) + [mass] / [length] <-> [length] / [mass]: 1 / value +@end + + +#### SYSTEMS OF UNITS #### + +@system SI + second + meter + kilogram + ampere + kelvin + mole + candela +@end + +@system mks using international + meter + kilogram + second +@end + +@system cgs using international, Gaussian, ESU + centimeter + gram + second +@end + +@system atomic using international + # based on unit m_e, e, hbar, k_C, k + bohr: meter + electron_mass: gram + atomic_unit_of_time: second + atomic_unit_of_current: ampere + atomic_unit_of_temperature: kelvin +@end + +@system Planck using international + # based on unit c, gravitational_constant, hbar, k_C, k + planck_length: meter + planck_mass: gram + planck_time: second + planck_current: ampere + planck_temperature: kelvin +@end + +@system imperial using ImperialVolume, USCSLengthInternational, AvoirdupoisUK + yard + pound +@end + +@system US using USCSLiquidVolume, USCSDryVolume, USCSVolumeOther, USCSLengthInternational, USCSLengthSurvey, AvoirdupoisUS + yard + pound +@end diff --git a/requirements.txt b/requirements.txt index 148a49b8b3d35668a4707eee3bd32ba3d3fc3b50..73357bffa65c2b422ecd2723ed6abad8f55ea35a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -42,7 +42,7 @@ optimade==0.8.1 structlog elasticsearch==6.4.0 msgpack<0.6.0 -celery[redis] +celery[redis]==4.4.7 mongoengine==0.19.1 pymongo==3.10.1 Werkzeug==0.16.1