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

Integrated the mpes parser and adapted the GUI to latest experimental data.

parent 6fa0ece4
Subproject commit c76dab1e28847bac58b247d9995fdf40d970bf41 Subproject commit 51a05bdb71586485ba3cf5e365289ee42e2a9885
Subproject commit aa26d45aafc2e19dda14da1523913eb480092218 Subproject commit ef3fe75d150b13d35abc5d9af9555708fbf3903f
...@@ -191,7 +191,6 @@ class Api { ...@@ -191,7 +191,6 @@ class Api {
})) }))
.catch(this.handleApiError) .catch(this.handleApiError)
.then(response => { .then(response => {
console.log(response)
const result = response.body || response.text || response.data const result = response.body || response.text || response.data
if (typeof result === 'string') { if (typeof result === 'string') {
try { try {
......
...@@ -23,6 +23,8 @@ class DomainProviderBase extends React.Component { ...@@ -23,6 +23,8 @@ class DomainProviderBase extends React.Component {
domains = { domains = {
DFT: { DFT: {
name: 'DFT', name: 'DFT',
entryLabel: 'calculation',
searchPlaceholder: 'enter atoms, codes, functionals, or other quantity values',
/** /**
* A component that is used to render the search aggregations. The components needs * A component that is used to render the search aggregations. The components needs
* to work with props: aggregations (the aggregation data from the api), * to work with props: aggregations (the aggregation data from the api),
...@@ -99,6 +101,8 @@ class DomainProviderBase extends React.Component { ...@@ -99,6 +101,8 @@ class DomainProviderBase extends React.Component {
}, },
EMS: { EMS: {
name: 'EMS', name: 'EMS',
entryLabel: 'experiment',
searchPlaceholder: 'enter atoms, experimental methods, or other quantity values',
/** /**
* A component that is used to render the search aggregations. The components needs * A component that is used to render the search aggregations. The components needs
* to work with props: aggregations (the aggregation data from the api), * to work with props: aggregations (the aggregation data from the api),
......
...@@ -2,6 +2,7 @@ import React from 'react' ...@@ -2,6 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { withStyles, Card, CardHeader, CardContent } from '@material-ui/core' import { withStyles, Card, CardHeader, CardContent } from '@material-ui/core'
import RawFiles from '../entry/RawFiles' import RawFiles from '../entry/RawFiles'
import Markdown from '../Markdown'
class EMSEntryCards extends React.Component { class EMSEntryCards extends React.Component {
static propTypes = { static propTypes = {
...@@ -11,7 +12,10 @@ class EMSEntryCards extends React.Component { ...@@ -11,7 +12,10 @@ class EMSEntryCards extends React.Component {
} }
static styles = theme => ({ static styles = theme => ({
root: {} root: {},
description: {
marginBottom: theme.spacing.unit * 3
}
}) })
render() { render() {
...@@ -19,8 +23,16 @@ class EMSEntryCards extends React.Component { ...@@ -19,8 +23,16 @@ class EMSEntryCards extends React.Component {
return ( return (
<Card className={classes.root}> <Card className={classes.root}>
<CardHeader title="Raw files" /> <CardHeader title="Raw Data and Meta Data Files" />
<CardContent classes={{root: classes.cardContent}}> <CardContent classes={{root: classes.cardContent}}>
<Markdown classes={{root: classes.description}}>{`
The data for this experiment was uploaded to [xenodo.org](https://xenodo.org).
Visit the xenodo entry to download the raw experiment data:
[${data.repository_url}](${data.repository_url}).
The meta data describing this experiment in its original format, can be
downloaded here directly:
`}</Markdown>
<RawFiles data={data} /> <RawFiles data={data} />
</CardContent> </CardContent>
</Card> </Card>
......
...@@ -2,6 +2,7 @@ import React from 'react' ...@@ -2,6 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Quantity from '../Quantity' import Quantity from '../Quantity'
import { Typography } from '@material-ui/core' import { Typography } from '@material-ui/core'
import { apiBase } from '../../config'
export default class EMSEntryOverview extends React.Component { export default class EMSEntryOverview extends React.Component {
static propTypes = { static propTypes = {
...@@ -11,30 +12,44 @@ export default class EMSEntryOverview extends React.Component { ...@@ -11,30 +12,44 @@ export default class EMSEntryOverview extends React.Component {
render() { render() {
const { data } = this.props const { data } = this.props
const { preview_url } = data
let relative_preview_url = null
if (!preview_url) {
relative_preview_url = 'broken'
} else if (preview_url.indexOf('http://') === 0 || preview_url.indexOf('https://') === 0) {
relative_preview_url = preview_url
} else {
const dirname = data.mainfile.substring(0, data.mainfile.lastIndexOf('/') + 1)
relative_preview_url = `${apiBase}/raw/${data.upload_id}/${dirname ? dirname + '/' : ''}${preview_url}`
}
return ( return (
<Quantity row> <Quantity column>
<Quantity column> <Quantity quantity="experiment_summary" label="summary" noWrap {...this.props} />
<Quantity row> <Quantity row>
<Quantity quantity="formula" label="sample formula" noWrap {...this.props} /> <Quantity column>
<Quantity quantity="chemical" label="sample chemical" noWrap {...this.props} /> <Quantity row>
</Quantity> <Quantity quantity="formula" label="sample formula" noWrap {...this.props} />
<Quantity quantity="method" label="experimental method" noWrap {...this.props} /> <Quantity quantity="chemical" label="sample chemical" noWrap {...this.props} />
<Quantity quantity="experiment_location" label="experiment location" noWrap {...this.props} /> </Quantity>
<Quantity label="experiment time" {...this.props}> <Quantity quantity="method" label="experimental method" noWrap {...this.props} />
<Typography noWrap> <Quantity quantity="experiment_location" label="experiment location" noWrap {...this.props} />
{new Date(data.experiment_time * 1000).toLocaleString()} <Quantity label="experiment time" {...this.props}>
</Typography> <Typography noWrap>
{new Date(data.experiment_time * 1000).toLocaleString()}
</Typography>
</Quantity>
<Quantity label="data" {...this.props}>
<Typography noWrap>
<a href={data.repository_url}>{data.repository_name}</a>
</Typography>
</Quantity>
</Quantity> </Quantity>
<Quantity label="data" {...this.props}> <Quantity label="preview" {...this.props}>
<Typography noWrap> <img alt="preview" style={{maxWidth: '100%', height: 'auto'}} src={relative_preview_url}></img>
<a href={data.repository_url}>{data.repository_name}</a>
</Typography>
</Quantity> </Quantity>
</Quantity> </Quantity>
<Quantity label="preview" {...this.props}>
<img alt="preview" style={{maxWidth: '100%', height: 'auto'}} src={data.preview_url}></img>
</Quantity>
</Quantity> </Quantity>
) )
} }
......
...@@ -66,9 +66,11 @@ class EMSSearchAggregations extends React.Component { ...@@ -66,9 +66,11 @@ class EMSSearchAggregations extends React.Component {
<Grid container spacing={24} className={classes.quantityGrid}> <Grid container spacing={24} className={classes.quantityGrid}>
<Grid item xs={6}> <Grid item xs={6}>
{quantity('method', 'Method')} {quantity('method', 'Method')}
{quantity('probing_method', 'Probing')}
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
{quantity('experiment_location', 'Location')} {quantity('sample_microstructure', 'Sample structure')}
{quantity('sample_constituents', 'Sample constituents')}
</Grid> </Grid>
</Grid> </Grid>
</div> </div>
......
...@@ -85,10 +85,12 @@ class ArchiveEntryView extends React.Component { ...@@ -85,10 +85,12 @@ class ArchiveEntryView extends React.Component {
this.props.raiseError(error) this.props.raiseError(error)
}) })
api.getMetaInfo().then(metaInfo => { api.getInfo().then(info => {
if (!this.unmounted) { this.props.api.getMetaInfo(info.domain.metainfo.all_package).then(metaInfo => {
this.setState({metaInfo: metaInfo}) if (!this.unmounted) {
} this.setState({metaInfo: metaInfo})
}
})
}).catch(error => { }).catch(error => {
this.props.raiseError(error) this.props.raiseError(error)
}) })
......
...@@ -131,9 +131,9 @@ class RepoEntryView extends React.Component { ...@@ -131,9 +131,9 @@ class RepoEntryView extends React.Component {
{new Date(calcData.upload_time * 1000).toLocaleString()} {new Date(calcData.upload_time * 1000).toLocaleString()}
</Typography> </Typography>
</Quantity> </Quantity>
<Quantity quantity="calc_id" label='calculation id' noWrap {...quantityProps} /> <Quantity quantity="calc_id" label={`${domain.entryLabel} id`} noWrap {...quantityProps} />
<Quantity quantity='mainfile' loading={loading} noWrap {...quantityProps} /> <Quantity quantity='mainfile' loading={loading} noWrap {...quantityProps} />
<Quantity quantity="calc_hash" label='calculation hash' loading={loading} noWrap {...quantityProps} /> <Quantity quantity="calc_hash" label={`${domain.entryLabel} hash`} loading={loading} noWrap {...quantityProps} />
<Quantity quantity="last_processing" label='last processing' loading={loading} placeholder="not processed" noWrap {...quantityProps}> <Quantity quantity="last_processing" label='last processing' loading={loading} placeholder="not processed" noWrap {...quantityProps}>
<Typography noWrap> <Typography noWrap>
{new Date(calcData.last_processing * 1000).toLocaleString()} {new Date(calcData.last_processing * 1000).toLocaleString()}
......
...@@ -216,7 +216,7 @@ class SearchPage extends React.Component { ...@@ -216,7 +216,7 @@ class SearchPage extends React.Component {
<SearchBar classes={{autosuggestRoot: classes.searchBar}} <SearchBar classes={{autosuggestRoot: classes.searchBar}}
fullWidth fullWidthInput={false} helperText={helperText} fullWidth fullWidthInput={false} helperText={helperText}
label="search" label="search"
placeholder="enter atoms, codes, functionals, or other quantity values" placeholder={domain.searchPlaceholder}
data={data} searchValues={searchValues} data={data} searchValues={searchValues}
InputLabelProps={{ InputLabelProps={{
shrink: true shrink: true
......
...@@ -22,6 +22,7 @@ import os.path ...@@ -22,6 +22,7 @@ import os.path
from flask import send_file from flask import send_file
from flask_restplus import abort, Resource from flask_restplus import abort, Resource
import json import json
import importlib
import nomad_meta_info import nomad_meta_info
...@@ -125,11 +126,11 @@ class MetainfoResource(Resource): ...@@ -125,11 +126,11 @@ class MetainfoResource(Resource):
return load_metainfo(metainfo_package_name), 200 return load_metainfo(metainfo_package_name), 200
except FileNotFoundError: except FileNotFoundError:
parser_prefix = metainfo_package_name[:-len('.nomadmetainfo.json')] parser_prefix = metainfo_package_name[:-len('.nomadmetainfo.json')]
alternative_path = os.path.join(
metainfo_main_path,
'../{0}parser/{0}.nomadmetainfo.json'.format(parser_prefix))
try: try:
return load_metainfo(alternative_path, is_path=True), 200 return load_metainfo(dict(
parser='%sparser' % parser_prefix,
path='%s.nomadmetainfo.json' % parser_prefix)), 200
except FileNotFoundError: except FileNotFoundError:
abort(404, message='The metainfo %s does not exist.' % metainfo_package_name) abort(404, message='The metainfo %s does not exist.' % metainfo_package_name)
...@@ -137,24 +138,53 @@ class MetainfoResource(Resource): ...@@ -137,24 +138,53 @@ class MetainfoResource(Resource):
metainfo_main_path = os.path.dirname(os.path.abspath(nomad_meta_info.__file__)) metainfo_main_path = os.path.dirname(os.path.abspath(nomad_meta_info.__file__))
def load_metainfo(package_name: str, is_path: bool = False, loaded_packages: Dict[str, Any] = None) -> Dict[str, Any]: def load_metainfo(
package_name_or_dependency: str, dependency_source: str = None,
loaded_packages: Dict[str, Any] = None) -> Dict[str, Any]:
""" """
Loads the given metainfo package and all its dependencies. Returns a dict with Loads the given metainfo package and all its dependencies. Returns a dict with
all loaded package_names and respective packages. all loaded package_names and respective packages.
Arguments: Arguments:
package_name: The name of the package, or a path to .nomadmetainfo.json file. package_name_or_dependency: The name of the package, or a nomadmetainfo dependency object.
is_path: True will interpret package_name as (relative) path. dependency_source: The path of the metainfo that uses this function to load a relative dependency.
loaded_packages: Give a dict and the function will added freshly loaded packages loaded_packages: Give a dict and the function will added freshly loaded packages
to it and return it. to it and return it.
""" """
if loaded_packages is None: if loaded_packages is None:
loaded_packages = {} loaded_packages = {}
if is_path: if isinstance(package_name_or_dependency, str):
metainfo_path = package_name package_name = package_name_or_dependency
else:
metainfo_path = os.path.join(metainfo_main_path, package_name) metainfo_path = os.path.join(metainfo_main_path, package_name)
else:
dependency = package_name_or_dependency
if 'relativePath' in dependency:
if dependency_source is None:
raise Exception(
'Can only load relative dependency from within another metainfo package')
metainfo_path = os.path.join(
os.path.dirname(dependency_source), dependency['relativePath'])
elif 'metainfoPath' in dependency:
metainfo_path = os.path.join(metainfo_main_path, dependency['metainfoPath'])
elif 'parser' in dependency:
parser = dependency['parser']
path = dependency['path']
try:
parser_module = importlib.import_module(parser).__file__
except Exception:
raise Exception('Parser not installed %s for metainfo path %s' % (parser, metainfo_path))
parser_directory = os.path.dirname(parser_module)
metainfo_path = os.path.join(parser_directory, path)
else:
raise Exception('Invalid dependency type in metainfo package %s' % metainfo_path)
package_name = os.path.basename(metainfo_path)
package_name = os.path.basename(package_name) package_name = os.path.basename(package_name)
...@@ -167,15 +197,6 @@ def load_metainfo(package_name: str, is_path: bool = False, loaded_packages: Dic ...@@ -167,15 +197,6 @@ def load_metainfo(package_name: str, is_path: bool = False, loaded_packages: Dic
loaded_packages[package_name] = metainfo_json loaded_packages[package_name] = metainfo_json
for dependency in metainfo_json.get('dependencies', []): for dependency in metainfo_json.get('dependencies', []):
if 'relativePath' in dependency: load_metainfo(dependency, dependency_source=metainfo_path, loaded_packages=loaded_packages)
dependency_path = os.path.join(
os.path.dirname(metainfo_path), dependency['relativePath'])
elif 'metainfoPath' in dependency:
dependency_path = os.path.join(metainfo_main_path, dependency['metainfoPath'])
else:
raise Exception(
'Invalid dependency type in metainfo package %s' % metainfo_path)
load_metainfo(dependency_path, is_path=True, loaded_packages=loaded_packages)
return loaded_packages return loaded_packages
...@@ -65,8 +65,14 @@ class RawFileFromPathResource(Resource): ...@@ -65,8 +65,14 @@ class RawFileFromPathResource(Resource):
""" """
upload_filepath = path upload_filepath = path
upload_files = UploadFiles.get( # TODO find a better way to all access to certain files
upload_id, create_authorization_predicate(upload_id)) if os.path.basename(path).endswith('.png'):
def authorization_predicate(*args, **kwargs):
return True
else:
authorization_predicate = create_authorization_predicate(upload_id)
upload_files = UploadFiles.get(upload_id, authorization_predicate)
if upload_files is None: if upload_files is None:
abort(404, message='The upload with id %s does not exist.' % upload_id) abort(404, message='The upload with id %s does not exist.' % upload_id)
......
...@@ -32,11 +32,17 @@ class EMSEntryWithMetadata(CalcWithMetadata): ...@@ -32,11 +32,17 @@ class EMSEntryWithMetadata(CalcWithMetadata):
self.atoms: List[str] = [] self.atoms: List[str] = []
self.n_atoms: int = 0 self.n_atoms: int = 0
self.chemical: str = None self.chemical: str = None
self.sample_constituents: str = None
self.sample_microstructure: str = None
# general metadata # general metadata
self.experiment_summary: str = None
self.experiment_location: str = None self.experiment_location: str = None
self.experiment_time: str = None self.experiment_time: str = None
# method
self.method: str = None self.method: str = None
self.probing_method: str = None
# data metadata # data metadata
self.repository_name: str = None self.repository_name: str = None
...@@ -63,13 +69,22 @@ class EMSEntryWithMetadata(CalcWithMetadata): ...@@ -63,13 +69,22 @@ class EMSEntryWithMetadata(CalcWithMetadata):
self.atoms.sort() self.atoms.sort()
self.chemical = get_optional_backend_value( self.chemical = get_optional_backend_value(
backend, 'sample_chemical_name', 'section_sample', logger=logger) backend, 'sample_chemical_name', 'section_sample', logger=logger)
self.sample_microstructure = get_optional_backend_value(
backend, 'sample_microstructure', 'section_sample', logger=logger)
self.sample_constituents = get_optional_backend_value(
backend, 'sample_constituents', 'section_sample', logger=logger)
self.experiment_summary = get_optional_backend_value(
backend, 'experiment_summary', 'section_experiment', logger=logger)
self.experiment_location = get_optional_backend_value( self.experiment_location = get_optional_backend_value(
backend, 'experiment_location', 'section_experiment', logger=logger) backend, 'experiment_location', 'section_experiment', logger=logger)
self.experiment_time = get_optional_backend_value( self.experiment_time = get_optional_backend_value(
backend, 'experiment_time', 'section_experiment', logger=logger) backend, 'experiment_time', 'section_experiment', logger=logger)
self.method = get_optional_backend_value( self.method = get_optional_backend_value(
backend, 'experiment_method_name', 'section_experiment', logger=logger) backend, 'experiment_method_name', 'section_method', logger=logger)
self.probing_method = get_optional_backend_value(
backend, 'probing_method', 'section_method', logger=logger)
self.repository_name = get_optional_backend_value( self.repository_name = get_optional_backend_value(
backend, 'data_repository_name', 'section_data', logger=logger) backend, 'data_repository_name', 'section_data', logger=logger)
...@@ -109,8 +124,12 @@ Domain( ...@@ -109,8 +124,12 @@ Domain(
aggregations=len(ase.data.chemical_symbols)), aggregations=len(ase.data.chemical_symbols)),
method=DomainQuantity( method=DomainQuantity(
'The experimental method used.', aggregations=20), 'The experimental method used.', aggregations=20),
experiment_location=DomainQuantity( probing_method=DomainQuantity(
'The used basis set functions.', aggregations=10), 'The used probing method.', aggregations=10),
sample_microstructure=DomainQuantity(
'The sample micro structure.', aggregations=10),
sample_constituents=DomainQuantity(
'The sample constituents.', aggregations=10),
quantities=DomainQuantity( quantities=DomainQuantity(
'All quantities that are used by this calculation', 'All quantities that are used by this calculation',
metric=('quantities', 'value_count') metric=('quantities', 'value_count')
......
...@@ -370,7 +370,7 @@ parsers = [ ...@@ -370,7 +370,7 @@ parsers = [
name='parsers/mpes', code_name='mpes', domain='EMS', name='parsers/mpes', code_name='mpes', domain='EMS',
parser_class_name='mpesparser.MPESParserInterface', parser_class_name='mpesparser.MPESParserInterface',
mainfile_mime_re=r'(application/json)|(text/.*)', mainfile_mime_re=r'(application/json)|(text/.*)',
mainfile_name_re=(r'.*') mainfile_name_re=(r'.*_data.meta')
) )
] ]
......
...@@ -587,8 +587,13 @@ class TestArchive(UploadFilesBasedTests): ...@@ -587,8 +587,13 @@ class TestArchive(UploadFilesBasedTests):
rv = client.get('/archive/%s' % 'doesnt/exist', headers=auth_headers) rv = client.get('/archive/%s' % 'doesnt/exist', headers=auth_headers)
assert rv.status_code == 404 assert rv.status_code == 404
def test_get_metainfo(self, client): @pytest.mark.parametrize('info', [
rv = client.get('/archive/metainfo/all.nomadmetainfo.json') 'all.nomadmetainfo.json',
'all.experimental.nomadmetainfo.json',
'vasp.nomadmetainfo.json',
'mpes.nomadmetainfo.json'])
def test_get_metainfo(self, client, info):
rv = client.get('/archive/metainfo/%s' % info)
assert rv.status_code == 200 assert rv.status_code == 200
metainfo = json.loads((rv.data)) metainfo = json.loads((rv.data))
assert len(metainfo) > 0 assert len(metainfo) > 0
......
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