diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py index ca1da3adfc9837c1bc9ecdbd7d81cf99e1f01062..68c034e3348eb7a938af529f40870ec4df99b017 100644 --- a/nomad/metainfo/metainfo.py +++ b/nomad/metainfo/metainfo.py @@ -3551,12 +3551,17 @@ class PrimitiveQuantity(Quantity): # versa is not allowed for primitive types. if isinstance(value, pint.Quantity): if self.unit is None: - raise TypeError(f'The quantity {self} does not have a unit, but value {value} has.') - if self.type in MTypes.int: + if value.units.dimensionless: + value = value.magnitude + else: + raise TypeError( + f'The quantity {self} does not have a unit, but value {value} has.') + elif self.type in MTypes.int: raise TypeError( f'Cannot save data with unit conversion into the quantity {self} ' 'with integer data type due to possible precision loss.') - value = value.to(self.unit).magnitude + else: + value = value.to(self.unit).magnitude if self._list: if not isinstance(value, list): diff --git a/nomad/metainfo/util.py b/nomad/metainfo/util.py index 27cbd71228770853fa02858c0508d8739b2259e5..4a005fe5d61fa0c17f450e4d2f190886e5043f28 100644 --- a/nomad/metainfo/util.py +++ b/nomad/metainfo/util.py @@ -701,13 +701,13 @@ def to_numpy(np_type, shape: list, unit: Optional[pint.Unit], definition, value: # the stored unit would not be serialized flexible_unit = getattr(definition, 'flexible_unit', False) - if not flexible_unit and unit is None: + if not flexible_unit and not value.units.dimensionless and unit is None: raise TypeError(f'The quantity {definition} does not have a unit, but value {value} does.') if type(value.magnitude) == np.ndarray and np_type != value.dtype: value = value.astype(np_type) - if not flexible_unit: + if not flexible_unit and not value.units.dimensionless: value = value.to(unit).magnitude else: value = value.magnitude diff --git a/tests/metainfo/test_metainfo.py b/tests/metainfo/test_metainfo.py index bc95914a1ec5cb16f1d2a562cc7cbf2694d6b73c..88ce353075131e2acec6f300c23337161b3bfc0a 100644 --- a/tests/metainfo/test_metainfo.py +++ b/tests/metainfo/test_metainfo.py @@ -27,7 +27,7 @@ import pint.quantity from nomad.metainfo.metainfo import ( MSection, MCategory, Section, Quantity, SubSection, Definition, Package, DeriveError, MetainfoError, Environment, Annotation, AnnotationModel, SectionAnnotation, Context, - DefinitionAnnotation, derived) + DefinitionAnnotation, derived, MTypes) from nomad.metainfo.example import Run, VaspRun, System, SystemHash, Parsing, SCC, m_package as example_package from nomad import utils from nomad.units import ureg @@ -592,6 +592,35 @@ class TestM1: assert system.atom_positions.units == ureg.meter assert system.atom_positions[0][0] < 0.1 * ureg.meter + @pytest.mark.parametrize('dtype', MTypes.num) + @pytest.mark.parametrize('shape', [None, [1, 2]]) + def test_setting_with_dimensionless_unit(self, dtype, shape): + if dtype not in MTypes.numpy: + shape = None + class TestSection(MSection): + test_quantity = Quantity(type=dtype, shape=shape) + + test_section = TestSection() + if dtype in MTypes.int: + value = 42 + elif dtype in MTypes.float: + value = 3.14 + elif dtype in MTypes.complex: + value = 1+2j + else: + raise Exception('Unsupported type') + if shape: + value = np.full(shape, value, dtype=dtype) + test_section.test_quantity = value * ureg.dimensionless + if shape: + assert np.all(test_section.test_quantity == value) + elif dtype == np.float16: + assert test_section.test_quantity == pytest.approx(value, 1e-2) + elif dtype == np.float32: + assert test_section.test_quantity == pytest.approx(value, 1e-7) + else: + assert test_section.test_quantity == value + def test_synonym(self): system = System() system.lattice_vectors = [[1.2e-10, 0, 0], [0, 1.2e-10, 0], [0, 0, 1.2e-10]]