Commit a71d2cca authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Merge branch 'v1.0.0-metainfo-refactor-lauri' into 'v1.0.0-metainfo-refactor-markus'

GUI/Encyclopedia/Normalizer adapted to new metainfo

See merge request !377
parents 085ac6c1 dbbeb6e7
Pipeline #109184 passed with stages
in 31 minutes and 21 seconds
Subproject commit c43f397c9d65b6c3ec86c2b51b51b473576b6253
Subproject commit d8d3d64dc8c7a25018fc5d3aedaa8a9d3b6509d3
......@@ -182,8 +182,8 @@ class Api {
structures: '*',
electronic: 'include-resolved',
vibrational: 'include-resolved',
// We do not want to include the resolved trajectory in the
// response, so we explicitly specify which parts we want
// We require only the energies: trajectory, optimized
// structure, etc. are unnecessary.
geometry_optimization: {
energies: 'include-resolved'
},
......
......@@ -15,25 +15,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useMemo, useState, useCallback } from 'react'
import React, { useMemo } from 'react'
import PropTypes from 'prop-types'
import { atom, useRecoilState, useRecoilValue } from 'recoil'
import { Box, FormGroup, FormControlLabel, Checkbox, TextField, Typography, makeStyles, Tooltip, FormControl, RadioGroup, Radio } from '@material-ui/core'
import { Box, FormGroup, FormControlLabel, Checkbox, TextField, Typography, makeStyles, Tooltip } from '@material-ui/core'
import { useRouteMatch, useHistory } from 'react-router-dom'
import Autocomplete from '@material-ui/lab/Autocomplete'
import Browser, { Item, Content, Compartment, List, Adaptor, formatSubSectionName } from './Browser'
import { resolveRef, rootSections } from './metainfo'
import { Title, metainfoAdaptorFactory, DefinitionLabel } from './MetainfoBrowser'
import { Matrix, Number } from './visualizations'
import Structure from '../visualization/Structure'
import BrillouinZone from '../visualization/BrillouinZone'
import BandStructure from '../visualization/BandStructure'
import EELS from '../visualization/EELS'
import DOS from '../visualization/DOS'
import Markdown from '../Markdown'
import { getHighestOccupiedEnergy } from '../../utils'
import { Overview } from './Overview'
import { toUnitSystem, useUnits } from '../../units'
import { electronicRange } from '../../config'
export const configState = atom({
key: 'config',
......@@ -44,10 +38,6 @@ export const configState = atom({
}
})
// Contains details about the currently visualized system. Used to detect if a
// reload is needed for the StructureViewer.
const visualizedSystem = {}
export default function ArchiveBrowser({data}) {
const searchOptions = useMemo(() => archiveSearchOptions(data), [data])
......@@ -356,186 +346,6 @@ QuantityValue.propTypes = ({
units: PropTypes.object
})
/**
* An optional overview for a section displayed directly underneath the section
* title.
*/
function Overview({section, def, parent, units}) {
// States
const [mode, setMode] = useState('bs')
// Styles
const useStyles = makeStyles(
{
bands: {
width: '30rem',
height: '30rem',
margin: 'auto'
},
structure: {
width: '28rem',
margin: 'auto'
},
dos: {
width: '20rem',
height: '40rem',
margin: 'auto'
},
eels: {
width: '30rem',
height: '15rem',
margin: 'auto'
},
radio: {
display: 'flex',
justifyContent: 'center'
}
}
)
const style = useStyles()
const toggleMode = useCallback((event) => {
setMode(event.target.value)
}, [setMode])
// Structure visualization for section_system
if (def.name === 'System') {
let url = window.location.href
let name = 'section_system'
let rootIndex = url.indexOf(name) + name.length
let sectionPath = url.substring(0, rootIndex)
let tmp = url.substring(rootIndex)
let tmpIndex = tmp.indexOf('/')
let index = tmpIndex === -1 ? tmp : tmp.slice(0, tmpIndex)
// The section is incomplete, we leave the overview empty
if (!section.atom_species) {
return null
}
const nAtoms = section.atom_species.length
let system = {
'species': section.atom_species,
'cell': section.lattice_vectors ? toUnitSystem(section.lattice_vectors, 'meter', {length: 'angstrom'}) : undefined,
'positions': toUnitSystem(section.atom_positions, 'meter', {length: 'angstrom'}),
'pbc': section.configuration_periodic_dimensions
}
visualizedSystem.sectionPath = sectionPath
visualizedSystem.index = index
visualizedSystem.nAtoms = nAtoms
return <Structure
aspectRatio={4 / 3}
className={style.structure}
data={system}
></Structure>
// Structure visualization for idealized_structure
} else if (def.name === 'IdealizedStructure') {
// The section is incomplete, we leave the overview empty
if (!section.atom_labels) {
return null
}
const system = {
species: section.atom_labels,
cell: section.lattice_vectors ? toUnitSystem(section.lattice_vectors, 'meter', {length: 'angstrom'}) : undefined,
positions: section.atom_positions,
fractional: true,
pbc: section.periodicity
}
return <Structure
data={system}
className={style.structure}
aspectRatio={1}>
</Structure>
// Band structure plot for section_k_band
} else if (def.name === 'KBand') {
return section.band_structure_kind !== 'vibrational'
? <>
{mode === 'bs'
? <Box>
<BandStructure
className={style.bands}
data={{
energy_highest_occupied: getHighestOccupiedEnergy(section, parent),
segments: section.section_k_band_segment,
reciprocal_cell: section.reciprocal_cell
}}
layout={{yaxis: {autorange: false, range: toUnitSystem(electronicRange, 'electron_volt', units)}}}
aspectRatio={1}
units={units}
></BandStructure>
</Box>
: <BrillouinZone
className={style.bands}
data={section}
aspectRatio={1}
></BrillouinZone>
}
<FormControl component="fieldset" className={style.radio}>
<RadioGroup row aria-label="position" name="position" defaultValue="bs" onChange={toggleMode} className={style.radio}>
<FormControlLabel
value="bs"
control={<Radio color="primary" />}
label="Band structure"
labelPlacement="end"
/>
<FormControlLabel
value="bz"
control={<Radio color="primary" />}
label="Brillouin zone"
labelPlacement="end"
/>
</RadioGroup>
</FormControl>
</>
: <Box>
<BandStructure
className={style.bands}
data={{
segments: section.section_k_band_segment,
reciprocal_cell: section.reciprocal_cell
}}
aspectRatio={1}
units={units}
type='vibrational'
></BandStructure>
</Box>
// DOS plot for section_dos
} else if (def.name === 'Dos') {
const isVibrational = section.dos_kind === 'vibrational'
const layout = isVibrational
? undefined
: {yaxis: {autorange: false, range: toUnitSystem(electronicRange, 'electron_volt', units)}}
return <DOS
className={style.dos}
layout={layout}
data={{
energies: section.dos_energies_normalized,
densities: section.dos_values_normalized,
energy_highest_occupied: 0
}}
aspectRatio={1 / 2}
units={units}
type={isVibrational ? 'vibrational' : null}
></DOS>
// EELS data
} else if (def.name === 'Spectrum') {
return <EELS
className={style.eels}
data={section}
layout={{yaxis: {autorange: true}}}
aspectRatio={2}
units={units}
></EELS>
}
return null
}
Overview.propTypes = ({
def: PropTypes.object,
section: PropTypes.object,
parent: PropTypes.object,
units: PropTypes.object
})
function Section({section, def, parent, units}) {
const config = useRecoilValue(configState)
......@@ -554,7 +364,7 @@ function Section({section, def, parent, units}) {
return <Content>
<Title def={def} data={section} kindLabel="section" />
<Overview def={def} section={section} parent={parent} units={units}></Overview>
<Overview section={section} def={def} units={units}/>
<Compartment title="sub sections">
{sub_sections
.filter(subSectionDef => section[subSectionDef.name] || config.showAllDefined)
......
import React, { useState, useCallback, useMemo } from 'react'
import PropTypes from 'prop-types'
import {
FormControlLabel,
FormControl,
RadioGroup,
Radio
} from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
import Structure from '../visualization/Structure'
import BrillouinZone from '../visualization/BrillouinZone'
import BandStructure from '../visualization/BandStructure'
import EELS from '../visualization/EELS'
import DOS from '../visualization/DOS'
import { toUnitSystem } from '../../units'
import { electronicRange } from '../../config'
const useOverviewAtomsStyles = makeStyles({
root: {
width: '28rem',
margin: 'auto'
}
})
export const OverviewAtoms = React.memo(({def, section}) => {
const style = useOverviewAtomsStyles()
const system = useMemo(() => ({
'species': section.species,
'cell': section.lattice_vectors
? toUnitSystem(section.lattice_vectors, 'meter', {length: 'angstrom'})
: undefined,
'positions': toUnitSystem(section.positions, 'meter', {length: 'angstrom'}),
'pbc': section.periodic
}), [section])
return <Structure
aspectRatio={4 / 3}
className={style.root}
data={system}
></Structure>
})
OverviewAtoms.propTypes = ({
def: PropTypes.object,
section: PropTypes.object,
units: PropTypes.object
})
const useOverviewDOSStyles = makeStyles({
root: {
width: '20rem',
height: '40rem',
margin: 'auto'
}
})
export const OverviewDOSElectronic = React.memo(({def, section, units}) => {
const style = useOverviewDOSStyles()
const data = useMemo(() => ({
energies: section.energies,
densities: section.total.map(dos => dos.value),
energy_highest_occupied: section.channel_info
? Math.max(...section.channel_info.map(x => x.energy_highest_occupied))
: undefined
}), [section])
return <DOS
className={style.root}
data={data}
aspectRatio={1 / 2}
units={units}
type="electronic"
/>
})
OverviewDOSElectronic.propTypes = ({
def: PropTypes.object,
section: PropTypes.object,
units: PropTypes.object
})
export const OverviewDOSPhonon = React.memo(({def, section, units}) => {
const style = useOverviewDOSStyles()
const data = useMemo(() => ({
energies: section.energies,
densities: section.total.map(dos => dos.value)
}), [section])
return <DOS
className={style.root}
data={data}
aspectRatio={1 / 2}
units={units}
type="vibrational"
/>
})
OverviewDOSPhonon.propTypes = ({
def: PropTypes.object,
section: PropTypes.object,
units: PropTypes.object
})
const useOverviewBandstructurePhononStyles = makeStyles({
root: {
width: '30rem',
height: '30rem',
margin: 'auto'
}
})
export const OverviewBandstructurePhonon = React.memo(({def, section, units}) => {
const style = useOverviewBandstructurePhononStyles()
const data = useMemo(() => ({
segment: section.segment,
reciprocal_cell: section.reciprocal_cell
}), [section])
return <BandStructure
className={style.root}
data={data}
aspectRatio={1}
units={units}
type='vibrational'
/>
})
OverviewBandstructurePhonon.propTypes = ({
def: PropTypes.object,
section: PropTypes.object,
units: PropTypes.object
})
const useOverviewBandstructureElectronicStyles = makeStyles({
root: {
width: '30rem',
height: '30rem',
margin: 'auto'
},
radio: {
display: 'flex',
justifyContent: 'center'
}
})
export const OverviewBandstructureElectronic = React.memo(({def, section, units}) => {
const [mode, setMode] = useState('bs')
const toggleMode = useCallback((event) => {
setMode(event.target.value)
}, [setMode])
const style = useOverviewBandstructureElectronicStyles()
const data = useMemo(() => ({
segment: section.segment,
reciprocal_cell: section.reciprocal_cell,
energy_highest_occupied: section.channel_info
? Math.max(...section.channel_info.map(x => x.energy_highest_occupied))
: undefined
}), [section])
const layout = useMemo(() => ({
yaxis: {
autorange: false,
range: toUnitSystem(electronicRange, 'electron_volt', units)
}
}), [units])
return <>
{mode === 'bs'
? <BandStructure
className={style.root}
data={data}
layout={layout}
aspectRatio={1}
units={units}
></BandStructure>
: <BrillouinZone
className={style.root}
data={section}
aspectRatio={1}
></BrillouinZone>
}
<FormControl component="fieldset" className={style.radio}>
<RadioGroup
row
aria-label="position"
name="position"
defaultValue="bs"
onChange={toggleMode}
className={style.radio}
>
<FormControlLabel
value="bs"
control={<Radio color="primary" />}
label="Band structure"
labelPlacement="end"
/>
<FormControlLabel
value="bz"
control={<Radio color="primary" />}
label="Brillouin zone"
labelPlacement="end"
/>
</RadioGroup>
</FormControl>
</>
})
OverviewBandstructureElectronic.propTypes = ({
def: PropTypes.object,
section: PropTypes.object,
units: PropTypes.object
})
const useOverviewEELSStyles = makeStyles({
root: {
width: '30rem',
height: '15rem',
margin: 'auto'
}
})
export const OverviewEELS = React.memo(({def, section, units}) => {
const style = useOverviewEELSStyles()
return <EELS
className={style.root}
data={section}
layout={{yaxis: {autorange: true}}}
aspectRatio={2}
units={units}
/>
})
OverviewEELS.propTypes = ({
def: PropTypes.object,
section: PropTypes.object,
units: PropTypes.object
})
export const Overview = React.memo((props) => {
const {def} = props
let path = window.location.href.split('/').pop().split(':')[0]
if (def.name === 'BandStructure' && path === 'band_structure_electronic') {
return <OverviewBandstructureElectronic {...props}/>
} else if (def.name === 'BandStructure' && path === 'band_structure_phonon') {
return <OverviewBandstructurePhonon {...props}/>
} else if (def.name === 'Atoms' && path === 'atoms') {
return <OverviewAtoms {...props}/>
} else if (def.name === 'Dos' && path === 'dos_electronic') {
return <OverviewDOSElectronic {...props}/>
} else if (def.name === 'Dos' && path === 'dos_phonon') {
return <OverviewDOSPhonon {...props}/>
} else if (def.name === 'Spectrum') {
return <OverviewEELS {...props}/>
}
return null
})
Overview.propTypes = ({
def: PropTypes.object,
section: PropTypes.object,
units: PropTypes.object
})
......@@ -21,7 +21,7 @@ import { Grid } from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
import QuantityHistogram from '../search/QuantityHistogram'
import { searchContext } from '../search/SearchContext'
import { path, defsByName, resolveRef } from '../archive/metainfo'
import { resolveRef } from '../archive/metainfo'
import { nomadTheme } from '../../config'
import Markdown from '../Markdown'
......@@ -106,55 +106,6 @@ DFTSystemVisualizations.propTypes = {
info: PropTypes.object
}
const electronic_quantities = [
'electronic_band_structure',
'electronic_dos',
'eigenvalues_values'
]
const mechanical_quantities = [
'stress_tensor'
]
const thermal_quantities = [
'thermodynamical_property_heat_capacity_C_v',
'vibrational_free_energy_at_constant_volume',
'phonon_band_structure',
'phonon_dos'
]
const magnetic_quantities = [
'spin_S2'
]
const optical_quantities = [
'oscillator_strengths',
'transition_dipole_moments'
]
const labels = {
'eigenvalues_values': 'eigenvalues',
'stress_tensor': 'stress tensor',
'electronic_band_structure': 'electronic band structure',
'electronic_dos': 'electronic density of states',
'phonon_band_structure': 'phonon dispersion',
'phonon_dos': 'phonon density of states',
'thermodynamical_property_heat_capacity_C_v': 'heat capacity',
'vibrational_free_energy_at_constant_volume': 'helmholtz free energy',
'spin_S2': 'angular spin momentum squared',
'oscillator_strengths': 'oscillator strengths',
'transition_dipole_moments': 'transition dipole moments'
}
const metainfoPaths = {
'eigenvalues_values': path('eigenvalues_values'),
'stress_tensor': path('stress_tensor'),
'electronic_band_structure': 'EntryArchive/section_run/section_single_configuration_calculation/section_k_band',
'electronic_dos': 'EntryArchive/section_run/section_single_configuration_calculation/section_dos',
'phonon_band_structure': 'EntryArchive/section_run/section_single_configuration_calculation/section_k_band',
'phonon_dos': 'EntryArchive/section_run/section_single_configuration_calculation/section_dos',
'thermodynamical_property_heat_capacity_C_v': path('thermodynamical_property_heat_capacity_C_v'),
'vibrational_free_energy_at_constant_volume': path('vibrational_free_energy_at_constant_volume'),
'spin_S2': path('spin_S2'),
'oscillator_strengths': path('oscillator_strengths'),
'transition_dipole_moments': path('transition_dipole_moments')
}
const useMetainfoTooltipStyles = makeStyles(theme => ({
root: {
display: 'flex',
......@@ -188,20 +139,6 @@ MetaInfoTooltip.propTypes = {
path: PropTypes.string
}
const tooltips = {}
for (const label in labels) {
const path = metainfoPaths[label]
console.assert(path, `The metainfo for ${label} does not exist.`)
if (path) {
const realName = path.split('/').slice(-1)[0]
const metainfoDef = defsByName[realName]?.[0]
console.assert(metainfoDef, `No metainfo definition called ${realName} does exist.`)
if (metainfoDef) {
tooltips[label] = <MetaInfoTooltip def={metainfoDef} path={path}></MetaInfoTooltip>