Commit 3b67fefb authored by Lauri Himanen's avatar Lauri Himanen
Browse files

Moved all functions related to extracting structural information from the...

Moved all functions related to extracting structural information from the archive into Structure.js.
parent 6392c158
Pipeline #135452 passed with stages
in 43 minutes and 27 seconds
/*
* Copyright The NOMAD Authors.
*
* This file is part of NOMAD. See https://nomad-lab.eu for further info.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Quantity } from './units'
import { isEmpty, isNil, merge, cloneDeep } from 'lodash'
/**
* Converts the given structure in the format used by 'results' into the format
* used by the materia-library.
*
* @param {object} structure.
*
* @return {undefined|object} If the given structure cannot be converted,
* returns an empty object.
*/
export function toMateriaStructure(structure) {
if (!structure) {
return undefined
}
try {
// Resolve atomic species using the labels and their mapping to chemical
// elements.
const speciesMap = new Map(structure.species.map(s => [s.name, s.chemical_symbols[0]]))
const structMateria = {
species: structure.species_at_sites.map(x => speciesMap.get(x)),
cell: structure.lattice_vectors
? new Quantity(structure.lattice_vectors, 'meter').to('angstrom').value()
: undefined,
positions: new Quantity(structure.cartesian_site_positions, 'meter').to('angstrom').value(),
fractional: false,
pbc: structure.dimension_types ? structure.dimension_types.map((x) => !!x) : undefined
}
return structMateria
} catch (error) {
return {}
}
}
/**
* Retrieves the topology for a calculation given the index and archive.
*
* @param {object} index
* @param {object} archive
*
* @return {undefined|object} If the given structure cannot be converted,
* returns an empty object.
*/
export function getTopology(index, archive) {
// If topology is explicitly stored, use it.
let topology
if (index?.results?.material?.topology) {
topology = merge(
cloneDeep(index?.results?.material?.topology),
archive?.results?.material?.topology
)
}
// Create topology map
let id = 0
const topologyMap = Object.fromEntries(topology.map(top => {
const node_id = `/results/material/topology/${id++}`
return [node_id, top]
}))
// Create topology tree by finding the root node and then recursively
// replacing its children with the actual child instances.
const root = topology.find(top => isNil(top.parent_system))
const traverse = (node) => {
if (!isEmpty(node?.child_systems)) {
node.child_systems = node.child_systems.map(id => topologyMap[id])
node.child_systems.forEach(child => traverse(child))
}
}
traverse(root)
return [root, topologyMap]
}
......@@ -22,10 +22,9 @@ import { Select, FormControl, MenuItem } from '@material-ui/core'
import { PropertyCard, PropertyGrid, PropertyItem, PropertyCardActions } from './PropertyCard'
import Quantity, { QuantityTable, QuantityRow, QuantityCell } from '../../Quantity'
import { MaterialButton } from '../../nav/Routes'
import Structure from '../../visualization/Structure'
import Structure, { toMateriaStructure } from '../../visualization/Structure'
import NoData from '../../visualization/NoData'
import searchQuantities from '../../../searchQuantities'
import { toMateriaStructure } from '../../../archive'
import { encyclopediaBase, guiBase } from '../../../config'
/**
......
......@@ -21,13 +21,12 @@ import { isEmpty, range, flattenDeep, isEqual } from 'lodash'
import { PropertyCard, PropertyGrid, PropertySubGrid, PropertyItem } from './PropertyCard'
import { Tab, Tabs, Typography, Box } from '@material-ui/core'
import { makeStyles, useTheme } from '@material-ui/core/styles'
import Structure from '../../visualization/Structure'
import Structure, { getTopology, toMateriaStructure } from '../../visualization/Structure'
import NoData from '../../visualization/NoData'
import TreeView from '@material-ui/lab/TreeView'
import TreeItem from '@material-ui/lab/TreeItem'
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
import ChevronRightIcon from '@material-ui/icons/ChevronRight'
import { toMateriaStructure, getTopology } from '../../../archive'
import { QuantityTable, QuantityRow, QuantityCell } from '../../Quantity'
import { resolveRef } from '../../archive/metainfo'
......
......@@ -43,7 +43,8 @@ import { Actions, Action } from '../Actions'
import { delay } from '../../utils'
import { withErrorHandler, withWebGLErrorHandler } from '../ErrorHandler'
import { useHistory } from 'react-router-dom'
import { isEmpty, flattenDeep, isNil } from 'lodash'
import { isEmpty, flattenDeep, isNil, merge, cloneDeep } from 'lodash'
import { Quantity } from '../../units'
import clsx from 'clsx'
/**
......@@ -690,3 +691,77 @@ Species.propTypes = {
className: PropTypes.string,
'data-testid': PropTypes.string
}
/**
* Converts the given structure in the format used by 'results' into the format
* used by the materia-library.
*
* @param {object} structure.
*
* @return {undefined|object} If the given structure cannot be converted,
* returns an empty object.
*/
export function toMateriaStructure(structure) {
if (!structure) {
return undefined
}
try {
// Resolve atomic species using the labels and their mapping to chemical
// elements.
const speciesMap = new Map(structure.species.map(s => [s.name, s.chemical_symbols[0]]))
const structMateria = {
species: structure.species_at_sites.map(x => speciesMap.get(x)),
cell: structure.lattice_vectors
? new Quantity(structure.lattice_vectors, 'meter').to('angstrom').value()
: undefined,
positions: new Quantity(structure.cartesian_site_positions, 'meter').to('angstrom').value(),
fractional: false,
pbc: structure.dimension_types ? structure.dimension_types.map((x) => !!x) : undefined
}
return structMateria
} catch (error) {
return {}
}
}
/**
* Retrieves the topology for a calculation given the index and archive.
*
* @param {object} index
* @param {object} archive
*
* @return {undefined|object} If the given structure cannot be converted,
* returns an empty object.
*/
export function getTopology(index, archive) {
// If topology is explicitly stored, use it.
let topology
if (index?.results?.material?.topology) {
topology = merge(
cloneDeep(index?.results?.material?.topology),
archive?.results?.material?.topology
)
}
// Create topology map
let id = 0
const topologyMap = Object.fromEntries(topology.map(top => {
const node_id = `/results/material/topology/${id++}`
return [node_id, top]
}))
// Create topology tree by finding the root node and then recursively
// replacing its children with the actual child instances.
const root = topology.find(top => isNil(top.parent_system))
const traverse = (node) => {
if (!isEmpty(node?.child_systems)) {
node.child_systems = node.child_systems.map(id => topologyMap[id])
node.child_systems.forEach(child => traverse(child))
}
}
traverse(root)
return [root, topologyMap]
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment