def test_pad_cell(null_lattice_vector_structure): """Make sure None values in lattice_vectors are converted to padding float value""" lattice_vectors, padded_cell = pad_cell( null_lattice_vector_structure.attributes.lattice_vectors ) assert not any(value is None for vector in lattice_vectors for value in vector) assert padded_cell lattice_vectors, padded_cell = pad_cell(lattice_vectors) assert not any(value is None for vector in lattice_vectors for value in vector) assert not padded_cell
def get_aiida_structure_data( optimade_structure: OptimadeStructure) -> StructureData: """Get AiiDA `StructureData` from OPTIMADE structure. Parameters: optimade_structure: OPTIMADE structure. Returns: AiiDA `StructureData` Node. """ if "optimade.adapters" in repr(globals().get("StructureData")): warn(AIIDA_NOT_FOUND) return None attributes = optimade_structure.attributes # Convert null/None values to float("nan") lattice_vectors, adjust_cell = pad_cell(attributes.lattice_vectors) structure = StructureData(cell=lattice_vectors) # Add Kinds for kind in attributes.species: symbols = [] concentration = [] for index, chemical_symbol in enumerate(kind.chemical_symbols): # NOTE: The non-chemical element identifier "X" is identical to how AiiDA handles this, # so it will be treated the same as any other true chemical identifier. if chemical_symbol == "vacancy": # Skip. This is how AiiDA handles vacancies; # to not include them, while keeping the concentration in a site less than 1. continue else: symbols.append(chemical_symbol) concentration.append(kind.concentration[index]) # AiiDA needs a definition for the mass, and for it to be > 0 # mass is OPTIONAL for OPTIMADE structures mass = kind.mass if kind.mass else 1 structure.append_kind( Kind(symbols=symbols, weights=concentration, mass=mass, name=kind.name)) # Add Sites for index in range(attributes.nsites): # range() to ensure 1-to-1 between kind and site structure.append_site( Site( kind_name=attributes.species_at_sites[index], position=attributes.cartesian_site_positions[index], )) if adjust_cell: structure._adjust_default_cell( pbc=[bool(dim.value) for dim in attributes.dimension_types]) return structure
def test__pad_iter_of_iters(): """Test _pad_iter_of_iters""" iterable = [(0.0, ) * 3, (0.0, ) * 3, (None, ) * 3] padded_iterable, padded_iterable_bool = pad_cell(iterable) assert padded_iterable_bool assert all(math.isnan(_) for _ in padded_iterable[-1]) for i in range(2): assert padded_iterable[i] == (0.0, ) * 3 for valid_padding_value in (3.0, 3, "3", "3.0"): padded_iterable, padded_iterable_bool = pad_cell( iterable, valid_padding_value) assert padded_iterable_bool assert padded_iterable[-1] == (float(valid_padding_value), ) * 3 for i in range(2): assert padded_iterable[i] == (0.0, ) * 3 # Since nan != nan, the above for-loop cannot be used for nan valid_padding_value = "nan" padded_iterable, padded_iterable_bool = pad_cell(iterable, valid_padding_value) assert padded_iterable_bool assert all(math.isnan(_) for _ in padded_iterable[-1]) assert all(math.isnan(_) for _ in (float(valid_padding_value), ) * 3) for i in range(2): assert padded_iterable[i] == (0.0, ) * 3 invalid_padding_value = "x" padded_iterable, padded_iterable_bool = pad_cell(iterable, invalid_padding_value) assert padded_iterable_bool assert all(math.isnan(_) for _ in padded_iterable[-1]) for i in range(2): assert padded_iterable[i] == (0.0, ) * 3