From 8580a6aca93cf5a687a810d7c9329a8bde0b1c09 Mon Sep 17 00:00:00 2001 From: Alvin Noe Ladines Date: Tue, 30 Aug 2022 21:57:03 +0200 Subject: [PATCH 01/15] Implement related resources card in overview #789 --- gui/src/components/entry/OverviewView.js | 4 + .../entry/properties/RelatedResourcesCard.js | 205 ++++++ nomad/app/v1/main.py | 3 +- nomad/app/v1/routers/related_resources.py | 636 ++++++++++++++++++ nomad/config.py | 11 + .../app/v1/routers/test_related_resources.py | 46 ++ 6 files changed, 904 insertions(+), 1 deletion(-) create mode 100644 gui/src/components/entry/properties/RelatedResourcesCard.js create mode 100644 nomad/app/v1/routers/related_resources.py create mode 100644 tests/app/v1/routers/test_related_resources.py diff --git a/gui/src/components/entry/OverviewView.js b/gui/src/components/entry/OverviewView.js index 286f298d5..82907d4b3 100644 --- a/gui/src/components/entry/OverviewView.js +++ b/gui/src/components/entry/OverviewView.js @@ -31,6 +31,7 @@ import ThermodynamicPropertiesCard from '../entry/properties/ThermodynamicProper import StructuralProperties from '../entry/properties/StructuralPropertiesCard' import GeometryOptimizationCard from '../entry/properties/GeometryOptimizationCard' import SpectroscopyCard from './properties/SpectroscopyCard' +import RelatedResourcesCard from '../entry/properties/RelatedResourcesCard' import { MethodMetadata } from './EntryDetails' import Page from '../Page' import { SourceApiCall, SourceApiDialogButton, SourceDialogDivider } from '../buttons/SourceDialogButton' @@ -268,6 +269,9 @@ const OverviewView = React.memo((props) => { + + + diff --git a/gui/src/components/entry/properties/RelatedResourcesCard.js b/gui/src/components/entry/properties/RelatedResourcesCard.js new file mode 100644 index 000000000..5aa2d1d60 --- /dev/null +++ b/gui/src/components/entry/properties/RelatedResourcesCard.js @@ -0,0 +1,205 @@ +/* + * 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 React, { useState, useEffect } from 'react' +import PropTypes from 'prop-types' +import { Link, IconButton, Typography, makeStyles } from '@material-ui/core' +import TooltipButton from '../../utils/TooltipButton' +import NavigateNextIcon from '@material-ui/icons/NavigateNext' +import { useApi } from '../../api' +import { useErrors } from '../../errors' +import { Datatable, DatatableToolbar, DatatableTable, DatatableLoadMorePagination } from '../../datatable/Datatable' +import { sleep, formatTimestamp } from '../../../utils' +import Quantity from '../../Quantity' + +const searchArchive = (source, path) => { + const path_array = typeof path === 'string' ? path.split('.') : path + if (!source || path_array.length === 0) { + return source + } + + if (Array.isArray(source)) { + return searchArchive(source[source.length - 1][path_array[0]], path_array.slice(1, path.length)) + } + + return searchArchive(source[path_array[0]], path_array.slice(1, path.length)) +} + +const useResourceDetailsStyles = makeStyles(theme => ({ + resourceDetails: { + paddingTop: theme.spacing(2), + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(2) + }, + resourceDetailsContents: { + display: 'flex', + width: '100%', + margin: '0' + }, + resourceDetailsRow: { + paddingRight: theme.spacing(3) + }, + resourceDetailsActions: { + display: 'flex', + flexBasis: 'auto', + flexGrow: 0, + flexShrink: 0, + justifyContent: 'flex-end', + marginBottom: theme.spacing(1), + marginTop: theme.spacing(2) + }, + resourceURL: { + overflow: 'hidden', + textOverflow: 'ellipsis', + width: '11rem' + }, + ellipsis: { + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + width: '11rem' + }, + ellipsisFront: { + direction: 'rtl', + textAlign: 'left' + } +})) + +function ResourceDetails({data}) { + const classes = useResourceDetailsStyles() + const availableData = {data_keys: Object.keys(data.data)} + const downloadTime = {download_time: formatTimestamp(data?.download_time)} + + return
+
+
+ + +
+
+ +
+
+ +
+
+
+} + +ResourceDetails.propTypes = { + data: PropTypes.object.isRequired +} + +function ResourceActions({data}) { + return { window.location = data.url }} + > + + +} +ResourceActions.propTypes = { + data: PropTypes.object.isRequired +} + +const RelatedResourcesCard = React.memo(({index, archive}) => { + const material = archive?.results?.material + const classes = useResourceDetailsStyles() + const [externalResource, setExternalResource] = useState([[], []]) + const {api} = useApi() + const {raiseError} = useErrors() + + const system = searchArchive(archive, 'run.system.symmetry.system_primitive') + useEffect(() => { + const params = [ + `space_group_number=${material ? material.symmetry?.space_group_number : 0}`, + `wyckoff_letters=${system ? system[0].wyckoff_letters.join('&wyckoff_letters=') : null}`, + `n_sites=${system ? system[0].positions.length : 0}`, + `chemical_formula_reduced=${material ? material?.chemical_formula_reduced : ''}` + ] + api.get( + `/related_resources/?${params.join('&')}` + ).then(response => { + setExternalResource([response.data, response?.metadata?.sources]) + }).catch(raiseError) + }, [material, system, api, raiseError]) + + const columns = [ + { + key: 'id', + // sortable: true, + align: 'left', + render: data => ( +
+ {data.id} +
+ ) + }, + { + key: 'url', + // sortable: true, + render: data => ( +
+ {data.url} +
+ ) + }, + { + key: 'database', + sortable: true, + render: data => data.database_name + } + ] + + const [pagination, setPagination] = useState({ + total: externalResource[0].length | 100, page_size: 10 + }) + + const [data, setData] = useState([]) + + useEffect(() => { + sleep(100).then(() => { + const nextPageAfterValueInt = parseInt(pagination.page_after_value || 0) + pagination.page_size + setData(externalResource[0].slice(0, nextPageAfterValueInt)) + setPagination(pagination => ({ + ...pagination, + next_page_after_value: nextPageAfterValueInt > externalResource[0].length ? null : String(nextPageAfterValueInt) + })) + }) + }, [pagination.page_after_value, pagination.page_size, externalResource]) + + return + + + + + load more + + + +}) + +RelatedResourcesCard.propTypes = { + index: PropTypes.object.isRequired, + archive: PropTypes.object +} + +export default RelatedResourcesCard diff --git a/nomad/app/v1/main.py b/nomad/app/v1/main.py index b8695e2a4..469468ca5 100644 --- a/nomad/app/v1/main.py +++ b/nomad/app/v1/main.py @@ -26,7 +26,7 @@ import orjson from nomad import config, utils from .common import root_path -from .routers import users, entries, materials, auth, info, datasets, uploads, suggestions, metainfo +from .routers import users, entries, materials, auth, info, datasets, uploads, suggestions, metainfo, related_resources logger = utils.get_logger(__name__) @@ -93,3 +93,4 @@ app.include_router(uploads.router, prefix='/uploads') app.include_router(metainfo.router, prefix='/metainfo') app.include_router(users.router, prefix='/users') app.include_router(suggestions.router, prefix='/suggestions') +app.include_router(related_resources.router, prefix='/related_resources') diff --git a/nomad/app/v1/routers/related_resources.py b/nomad/app/v1/routers/related_resources.py new file mode 100644 index 000000000..f96599620 --- /dev/null +++ b/nomad/app/v1/routers/related_resources.py @@ -0,0 +1,636 @@ +# +# 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 re +import os +import io +import json +import bs4 +import asyncio +import httpx +from fastapi import APIRouter, Query as FastApiQuery +from pydantic import BaseModel, Field +from typing import List, Any, Dict, Optional, Union +from datetime import datetime +import ase.io +from mongoengine import Document, StringField, DateTimeField, IntField, DictField, ListField +from mongoengine.queryset.visitor import Q + +from nomad import utils, config, atomutils + + +logger = utils.get_logger(__name__) + +router = APIRouter() + +default_tag = 'related_resources' + +# TODO generate list from optimade api +optimade_providers = { + 'https://www.crystallography.net/cod/optimade/v1/': dict( + name='Crystallography Open Database', + ref_url=lambda x: f'https://www.crystallography.net/cod/{x["entry_id"]}.html' + ), + 'https://optimade.materialsproject.org/v1/': dict( + name='The Materials Project', + ref_url=lambda x: f'https://materialsproject.org/materials/{x["entry_id"]}' + ), + 'https://aiida.materialscloud.org/mc3d-structures/optimade/v1/': dict( + name='Materials Cloud', + ref_url=lambda x: f'https://www.materialscloud.org/discover/mc3d/details/{x["chemical_formula_reduced"]}' + ), + 'https://oqmd.org/optimade/v1/': dict( + name='OQMD', + ref_url=lambda x: None if x.get('oqmd_id') is None else f'https://oqmd.org/materials/entry/{x["oqmd_id"]}' + ), + # jarvis search does not seem to work, it gives out all structures + # 'https://jarvis.nist.gov/optimade/jarvisdft/v1/': dict( + # name='Joint Automated Repository for Various Integrated Simulations', + # ref_url=lambda x: x['entry'].get('attributes', {}).get('reference') + # ), + 'https://api.mpds.io/v1/': dict( + name='Materials Platform for Data Science', + ref_url=lambda x: f'https://mpds.io/#entry/{x["entry_id"]}' + ), + 'https://optimade.odbx.science/v1/': dict( + name='Open Database of Xtals', + ref_url=lambda x: f'https://odbx.science/structures/{x["entry_id"]}' + ), + 'https://www.crystallography.net/tcod/optimade/v1/': dict( + name='Theoretical Crystallography Open Database', + ref_url=lambda x: f'https://www.crystallography.net/tcod/{x["entry_id"]}.html' + ), + 'http://optimade.2dmatpedia.org/v1/': dict( + name='2DMatpedia', + ref_url=lambda x: f'http://2dmatpedia.org/2dmaterials/doc/{x["entry_id"]}' + ), + # aflow does not seem to work + # 'https://aflow.org/API/optimade/v1/': dict( + # name='Automatic-FLOW Computational Materials Data Repository', + # ref_url=lambda x: None + # ) +} + +no_url_found = '__no_url_found' + +aflow_prototypes_db = 'Aflow prototypes' + +springer_materials_db = 'Springer Materials' + +aflow_home_url = 'http://aflowlib.org/prototype-encyclopedia' + +springer_materials_home_url = 'http://materials.springer.com' + +springer_required_items = { + 'Alphabetic Formula:': 'alphabetic_formula', + 'Classification by Properties:': 'classification', + 'Compound Class(es):': 'compound_classes', + 'Dataset ID': 'id', + 'Space Group:': 'space_group_number', + 'Phase Label(s):': 'phase_labels' +} + + +space_groups = ['triclinic'] * 2 + ['monoclinic'] * 13 + ['orthorhombic'] * 59 + [ + 'tetragonal'] * 68 + ['trigonal'] * 25 + ['hexagonal'] * 27 + ['cubic'] * 36 + + +spaces_re = re.compile(r'\s+') +search_re = re.compile(" href=\"(/isp/[^\"]+)") +formula_re = re.compile(r'([A-Z][a-z]?)([0-9.]*)|\[(.*?)\]([0-9]+)') +elements_re = re.compile(r'[A-Z][a-z]*') +prototype_re = re.compile(r'\') +wyckoff_re = re.compile(r'\\left\(\d+([a-z])\\right\)') + + +class Reference(Document): + id = StringField(primary_key=True) + url = StringField() + database_name = StringField() + database_version = StringField() + chemical_formula = StringField() + wyckoff_letters = ListField() + download_time = DateTimeField() + data = DictField() + space_group_number = IntField() + n_sites = IntField() + meta = {'indexes': ['chemical_formula']} + + +class ReferenceModel(BaseModel): + data: Dict[str, Any] = Field( + {}, description=''' Value of the data referenced by the entry. + ''') + url: str = Field( + None, description=''' + URL of the entry in the database. + ''') + id: str = Field( + None, description=''' + Name to identify the referenced data. + ''') + download_time: datetime = Field( + None, description=''' + Date the data was downloaded. + ''') + database_name: Optional[str] = Field( + None, description=''' + Name to identify the referenced data. + ''') + kind: Optional[str] = Field( + description=''' + Kind of the reference data, e.g. journal, online, book. + ''') + comment: Optional[str] = Field( + description=''' + Annotations on the reference. + ''') + database_version: Optional[str] = Field( + description=''' + Version of the database. + ''') + # TODO include homepage, assign version and comment + + @classmethod + def _get_value(cls, v: Any, to_dict: bool, **kwargs) -> Any: + if to_dict: + return dict(v) if isinstance(v, dict) else v + return super()._get_value(v, to_dict=to_dict, **kwargs) + + +class ReferencesResponseModel(BaseModel): + metadata: Dict[str, Any] = Field(None) + data: List[ReferenceModel] = Field(None) + + +async def _download(session: httpx.AsyncClient, path: str) -> httpx.Response: + n_retries = 0 + while True: + try: + response = await session.get(path, follow_redirects=True) + if response.status_code == 200: + return response + except Exception: + pass + n_retries += 1 + if n_retries > config.related_resources.download_retries: + break + await asyncio.sleep(config.related_resources.download_retry_delay) + return None + + +def _update_dict(target: Dict[str, float], source: Dict[str, float]): + for key, val in source.items(): + if key in target: + target[key] += val + else: + target[key] = val + + +def _components(formula_str: str, multiplier: float = 1.0) -> Dict[str, float]: + # match atoms and molecules (in brackets) + components = formula_re.findall(formula_str) + + symbol_amount: Dict[str, float] = {} + for component in components: + element, amount_e, molecule, amount_m = component + if element: + if not amount_e: + amount_e = 1.0 + _update_dict(symbol_amount, {element: float(amount_e) * multiplier}) + + elif molecule: + if not amount_m: + amount_m = 1.0 + _update_dict(symbol_amount, _components(molecule, float(amount_m) * multiplier)) + + return symbol_amount + + +def _normalize_formula(formula_str: str) -> str: + symbol_amount = _components(formula_str) + + total = sum(symbol_amount.values()) + symbol_normamount = {e: round(a / total * 100.) for e, a in symbol_amount.items()} + + formula_sorted = [ + '%s%d' % (s, symbol_normamount[s]) for s in sorted(list(symbol_normamount.keys()))] + + return ''.join(formula_sorted) + + +def parse_springer_entry(htmltext: str) -> Dict[str, str]: + ''' + Parse the springer entry quantities in required_items from an html text. + ''' + soup = bs4.BeautifulSoup(htmltext, "html.parser") + results = {} + for item in soup.find_all(attrs={"class": "data-list__item"}): + key = item.find(attrs={"class": "data-list__item-key"}) + if not key: + continue + + key_str = key.string.strip() + if key_str not in springer_required_items: + continue + + value = item.find(attrs={"class": "data-list__item-value"}) + value = spaces_re.sub(' ', value.get_text()).strip() + results[springer_required_items[key_str]] = value + + if len(results) >= len(springer_required_items): + break + + if 'classification' in results: + results['classification'] = [x.strip() for x in results['classification'].split(",")] + results['classification'] = [x for x in results['classification'] if x != '–'] + if 'compound_classes' in results: + results['compound_classes'] = [x.strip() for x in results['compound_classes'].split(",")] + results['compound_classes'] = [x for x in results['compound_classes'] if x != '–'] + + normalized_formula = None + for formula_type in ['alphabetic_formula', 'phase_labels']: + formula = results.get(formula_type, None) + if formula: + try: + normalized_formula = _normalize_formula(formula) + break + except Exception: + pass + + results['normalized_formula'] = normalized_formula + + # get database version + for item in soup.find_all(attrs={"class": "about_content_comments"}): + version_match = re.search(r'Version (.+)\.', item.string.strip()) + if version_match: + results['version'] = version_match.group(1) + break + + return results + + +def parse_aflow_prototype(text: str) -> Dict[str, Any]: + ''' + Parse information from aflow prototype structure entry. + ''' + soup = bs4.BeautifulSoup(text, 'html.parser') + results = dict() + tds = soup.find_all('td') + for n, item in enumerate(tds): + if item.find_all('strong'): + results[item.get_text()] = tds[n + 2].get_text() + return results + + +async def _get_urls_aflow_prototypes(session: httpx.AsyncClient, space_group_number: int) -> List[str]: + if space_group_number is None or space_group_number == 0: + return [] + + response = await _download(session, f'{aflow_home_url}/{space_groups[space_group_number - 1]}_spacegroup.html') + if response is None: + return [] + + urls = [] + for path in prototype_re.findall(response.text): + match = re.search(r'_(\d+)_', path) + space_group_number_path = int(match.group(1)) if match else 0 + if space_group_number_path != space_group_number: + continue + urls.append(f'{aflow_home_url}/{path}.html') + return urls + + +async def _get_reference_aflow_prototypes(session: httpx.AsyncClient, path: str) -> Reference: + response = await _download(session, path) + if response is None: + return None + + reference = Reference() + reference.database_name = aflow_prototypes_db + wyckoff_letters_data = wyckoff_re.findall(response.text) + reference.n_sites = len(wyckoff_letters_data) + wyckoff_letters_data = list(set(wyckoff_letters_data)) + wyckoff_letters_data.sort() + # compare wyckoff with input + reference.url = path + data = parse_aflow_prototype(response.text) + prototype_label = data.get('AFLOW prototype label', '') + reference.id = prototype_label + reference.space_group_number = int(data.get('Space group number', 0)) + reference.wyckoff_letters = wyckoff_letters_data + # chemical formula should correspond to the chemical formula of the entry not the prototype + reference.chemical_formula = None + # generate structure info + response = await _download(session, f'{aflow_home_url}/CIF/{prototype_label}.cif') + if response is not None: + structure_file = io.StringIO() + structure_file.write(response.text) + structure_file.seek(0) + atoms = ase.io.read(structure_file, format='cif') + data['lattice_vectors'] = atoms.get_cell().tolist() + data['atom_positions'] = atoms.get_positions().tolist() + data['atom_labels'] = atoms.get_chemical_symbols() + # else: + # return None + reference.data = data + reference.download_time = datetime.now() + # push to mongo db + reference.save() + return reference + + +async def _get_urls_springer_materials(session: httpx.AsyncClient, chemical_formula: str) -> List[str]: + if chemical_formula is None: + return [] + + elements = list(set(elements_re.findall(chemical_formula))) + elements.sort() + elements_str = '-'.join(elements) + page = 1 + urls = [] + while True: + url = f'{springer_materials_home_url}/search?searchTerm=es:{elements_str}&pageNumber={page}&datasourceFacet=sm_isp&substanceId=' + response = await _download(session, url) + if response is None: + logger.error('Error accessing urls from springer materials.', url) + break + page += 1 + paths = search_re.findall(response.text) + if not paths: + break + for path in paths: + urls.append(f'{springer_materials_home_url}{path}') + + return urls + + +async def _get_reference_springer_materials(session: httpx.AsyncClient, path: str) -> Reference: + reference = Reference() + reference.url = path + reference.id = os.path.basename(path) + reference.database_name = springer_materials_db + response = await _download(session, path) + if response is None: + logger.error(f'Error accessing springer materials reference.') + return reference + try: + # we need to query individual entry ONLY to get spacegroup! + # TODO find a way to limit springer search to particular spacegroup so + # we do not need to access individual entries + data = parse_springer_entry(response.text) + except Exception: + data = dict() + space_group_number = data.get('space_group_number', '0') + reference.space_group_number = int(space_group_number) if space_group_number.isdecimal() else space_group_number + reference.chemical_formula = data.get('normalized_formula') + reference.data = data + reference.database_version = data.get('version') + reference.download_time = datetime.now() + # push to mongo db + reference.save() + return reference + + +async def _get_urls_optimade(chemical_formula_hill: str, chemical_formula_reduced: str, providers: List[str] = None) -> List[str]: + filter_hill = f'chemical_formula_hill = "{chemical_formula_hill}"' if chemical_formula_hill is not None else None + filter_reduced = f'chemical_formula_reduced = "{chemical_formula_reduced}"' if chemical_formula_reduced is not None else None + + if providers is None: + providers = list(optimade_providers.keys()) + else: + providers = [key for key, val in optimade_providers.items() if val['name'] in providers] + + urls = [] + for base_url in providers: + query = filter_hill if base_url.startswith('https://www.crystallography.net/') else filter_reduced + if query is None: + continue + urls.append(f'{base_url}structures?filter={query}&response_format=json') + return urls + + +async def _get_references_optimade(session: httpx.AsyncClient, path: str) -> Union[List[Reference], None]: + response = await _download(session, path) + if response is None: + logger.error(f'Error accessing optimade references.') + return [] + data = response.json() + references: List[Reference] = [] + meta = data.get('meta', dict()) + provider = meta.get('provider', dict()).get('name', '') + base_url = path.split('structures?filter')[0] + ref_url = optimade_providers[base_url]['ref_url'] + for entry in data.get('data', []): + entry_id = entry.get('id') + params = dict( + entry_id=entry.get('id'), chemical_formula_reduced=data.get('chemical_formula_reduced', ''), + oqmd_id=entry.get('attributes', {}).get('_oqmd_entry_id'), entry=entry) + reference = Reference() + # resolve provider-specific path to entry in respective database + reference.url = ref_url(params) # type: ignore + reference.database_name = provider + reference.id = f'{entry_id}' + attributes = entry.get('attributes', dict()) + chemical_formula = attributes.get('chemical_formula_hill') + if chemical_formula is None: + chemical_formula = attributes.get('chemical_formula_reduced', '') + reference.chemical_formula = _normalize_formula(chemical_formula) + reference.download_time = datetime.now() + reference.database_version = meta.get('api_version') + # flatten entry data + entry.update({key: val for key, val in attributes.items()}) + reference.data = entry + # push to mongo database + reference.save() + references.append(reference) + return references + + +@router.get( + '/', + tags=[default_tag], + summary='Get a list of external references.', + response_model=ReferencesResponseModel, + response_model_exclude_unset=True, + response_model_exclude_none=True) +async def get_references( + space_group_number: int = FastApiQuery(None), + wyckoff_letters: List[str] = FastApiQuery(None), + n_sites: int = FastApiQuery(None), + chemical_formula_reduced: str = FastApiQuery(None)): + ''' + Get all external references that match a specific query + ''' + data: List[Any] = [] + metadata: Dict[str, Any] = dict(sources=[]) + sources: Dict[str, int] = dict() + + chemical_formula_hill, chemical_formula = None, None + if chemical_formula_reduced is not None: + chemical_formula_hill = atomutils.get_formula_hill(chemical_formula_reduced) + chemical_formula = _normalize_formula(chemical_formula_hill) + else: + chemical_formula_hill = None + chemical_formula = None + if wyckoff_letters is not None: + wyckoff_letters = list(set(wyckoff_letters)) + wyckoff_letters.sort() + + def equal(quantity, input_quantity): + if quantity and input_quantity is not None: + if quantity != input_quantity: + return False + return True + + optimade_dbs: List[str] = [str(details['name']) for details in optimade_providers.values()] + comments = { + aflow_prototypes_db: ''' + Reference to the prototype structure in the Aflow encyclopedia of crystallographic + prototypes. + ''', + springer_materials_db: ''' + Reference to the entry in the Springer Materials Inorganic Solid Phases database. + ''' + } + comments.update({db: f''' + Reference to the entry in the {db} database queried using the Optimade API. + ''' for db in optimade_dbs}) + + def convert_to_model(references): + additional_data = [] + for reference in references: + if isinstance(reference, list): + convert_to_model(reference) + continue + elif reference.url is None: + continue + elif reference is None or not reference.id: + continue + elif reference.id.startswith(no_url_found): + continue + database = reference.database_name + # filter reference if matches query + if not equal(reference.space_group_number, space_group_number): + continue + if not equal(reference.wyckoff_letters, wyckoff_letters): + continue + if not equal(reference.n_sites, n_sites): + continue + if not equal(reference.chemical_formula, chemical_formula): + continue + sources.setdefault(database, 0) + sources[database] += 1 + # show the first five results from each resource and the rest we append later + model = ReferenceModel( + url=reference.url, id=reference.id, data=reference.data, + database_name=reference.database_name, download_time=reference.download_time, + database_version=reference.database_version, comment=comments.get(database)) + if sources[database] <= 5: + data.append(model) + else: + additional_data.append(model) + + data.extend(additional_data) + + def set_empty_reference(database_name: str, **kwargs) -> None: + reference = Reference() + reference.id = f'{no_url_found}_{database_name}_{json.dumps(kwargs, sort_keys=True)}' + reference.database_name = database_name + for key, val in kwargs.items(): + setattr(reference, key, val) + reference.download_time = datetime.now() + reference.save() + + query_aflow = Q( + chemical_formula=None, space_group_number=space_group_number, wyckoff_letters=wyckoff_letters, + n_sites=n_sites, database_name=aflow_prototypes_db) + query_springer = Q( + chemical_formula=chemical_formula, space_group_number=space_group_number, + database_name=springer_materials_db) + query_optimade = Q(chemical_formula=chemical_formula, database_name__in=optimade_dbs) + query_results = Reference.objects(query_aflow | query_springer | query_optimade) + + # we cannot set entries in query_results to None + valid_queries_index = [] + space_group_number_query = space_group_number + chemical_formula_query = chemical_formula + optimade_dbs_query = list(optimade_dbs) + for n, reference in enumerate(query_results): + # filter reference if recent + delta_time_db = datetime.now() - reference.download_time + if delta_time_db.total_seconds() > config.related_resources.max_time_external_db: + continue + # set query parameters to None to turn off external db query + database = reference.database_name + if database == aflow_prototypes_db: + space_group_number_query = None + elif database == springer_materials_db: + chemical_formula_query = None + elif database in optimade_dbs_query: + optimade_dbs_query.remove(database) + valid_queries_index.append(n) + + # TODO is this necessary + done_urls = [reference.url for reference in data] + limits = httpx.Limits(max_connections=config.related_resources.max_connections) + async with httpx.AsyncClient(limits=limits) as session: + # get urls from sources + tasks = [] + tasks.append(asyncio.create_task(_get_urls_aflow_prototypes(session, space_group_number_query))) + tasks.append(asyncio.create_task(_get_urls_springer_materials(session, chemical_formula_query))) + tasks.append(asyncio.create_task(_get_urls_optimade(chemical_formula_hill, chemical_formula_reduced, optimade_dbs_query))) + urls = await asyncio.gather(*tasks) + # get reference(s) corresponding to each url + tasks = [] + tasks.extend([asyncio.create_task( + _get_reference_aflow_prototypes(session, url)) for url in urls[0] if url not in done_urls]) + tasks.extend([asyncio.create_task( + _get_reference_springer_materials(session, url)) for url in urls[1] if url not in done_urls]) + tasks.extend([asyncio.create_task( + _get_references_optimade(session, url)) for url in urls[2] if url not in done_urls]) + references = await asyncio.gather(*tasks) + + # filter references to match query and convert to model + convert_to_model([query_results[n] for n in valid_queries_index] + references) + + # if no references are found, record this in mongodb so as not do perform query again + # queried_databases = [reference.database_name for reference in data] + queried_databases = [query_results[n].database_name for n in valid_queries_index] + for reference in references: + if isinstance(reference, list): + queried_databases.extend([ref.database_name for ref in reference]) + else: + queried_databases.append(reference.database_name) + queried_databases = list(set(queried_databases)) + if aflow_prototypes_db not in queried_databases: + set_empty_reference( + aflow_prototypes_db, chemical_formula=None, space_group_number=space_group_number, + wyckoff_letters=wyckoff_letters, n_sites=n_sites) + if springer_materials_db not in queried_databases: + set_empty_reference( + springer_materials_db, chemical_formula=chemical_formula, + space_group_number=space_group_number) + for optimade_db in optimade_dbs: + if optimade_db not in queried_databases: + set_empty_reference(optimade_db, chemical_formula=chemical_formula) + + metadata['sources'] = list(sources.keys()) + metadata['n_references'] = list(sources.values()) + + return dict(data=data, metadata=metadata) diff --git a/nomad/config.py b/nomad/config.py index eba40159b..6f3680829 100644 --- a/nomad/config.py +++ b/nomad/config.py @@ -323,6 +323,17 @@ normalize = NomadConfig( ) ) +related_resources = NomadConfig( + # Maxmimum time a reference is stored in mongodb before being updated. + max_time_external_db=60 * 60 * 24 * 365., + # Number of download retries + download_retries=2, + # Delay in seconds before each successive retry + download_retry_delay=30, + # Maximum number of httpx connections + max_connections=10 +) + paths = NomadConfig( similarity="", ) diff --git a/tests/app/v1/routers/test_related_resources.py b/tests/app/v1/routers/test_related_resources.py new file mode 100644 index 000000000..0a3fcc787 --- /dev/null +++ b/tests/app/v1/routers/test_related_resources.py @@ -0,0 +1,46 @@ +# +# 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 pytest +from urllib.parse import urlencode + +''' +These are the tests for all API operations below ``references``. The tests are organized +using the following type of methods: fixtures, ``perfrom_*_test``, ``assert_*``, and +``test_*``. While some ``test_*`` methods test individual API operations, some +test methods will test multiple API operations that use common aspects like +supporting queries, pagination, or the owner parameter. The test methods will use +``perform_*_test`` methods as an parameter. Similarely, the ``assert_*`` methods allow +to assert for certain aspects in the responses. +''' + + +@pytest.mark.skip(reason='can take very long and depends on live external services') +def test_related_resources(client, example_data): + query = { + 'space_group_number': 1, + 'wyckoff_letters': ['a'], + 'n_atoms_primitive': 26, + 'chemical_formula': 'AlBFeNi', + 'chemical_formula_hill': 'AlBFeNi', + 'chemical_formula_reduced': 'AlBFeNi', + } + + response = client.get(f'related_resources?{urlencode(query, doseq=True)}') + assert response.status_code == 200 + data = response.json() + assert len(data['data']) > 0 -- GitLab From bb87d2b9f64b1abcb09b700c124186ee50fdb35d Mon Sep 17 00:00:00 2001 From: Alvin Noe Ladines Date: Wed, 31 Aug 2022 16:18:37 +0200 Subject: [PATCH 02/15] Fix external query --- .../entry/properties/RelatedResourcesCard.js | 29 ++++-- nomad/app/v1/routers/related_resources.py | 89 +++++++++---------- 2 files changed, 61 insertions(+), 57 deletions(-) diff --git a/gui/src/components/entry/properties/RelatedResourcesCard.js b/gui/src/components/entry/properties/RelatedResourcesCard.js index 5aa2d1d60..8b69311e2 100644 --- a/gui/src/components/entry/properties/RelatedResourcesCard.js +++ b/gui/src/components/entry/properties/RelatedResourcesCard.js @@ -125,12 +125,23 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { const system = searchArchive(archive, 'run.system.symmetry.system_primitive') useEffect(() => { - const params = [ - `space_group_number=${material ? material.symmetry?.space_group_number : 0}`, - `wyckoff_letters=${system ? system[0].wyckoff_letters.join('&wyckoff_letters=') : null}`, - `n_sites=${system ? system[0].positions.length : 0}`, - `chemical_formula_reduced=${material ? material?.chemical_formula_reduced : ''}` - ] + const spg = material.symmetry?.space_group_number + const wyckoff = system ? system[0]?.wyckoff_letters : null + const nsites = system ? system[0]?.positions.length : null + const formula = material?.chemical_formula_reduced + const params = [] + if (spg) { + params.push(`space_group_number=${spg}`) + } + if (wyckoff) { + params.push(`wyckoff_letters=${wyckoff.join('&wyckoff_letters=')}`) + } + if (nsites) { + params.push(`n_sites=${nsites}`) + } + if (formula) { + params.push(`chemical_formula_reduced=${formula}`) + } api.get( `/related_resources/?${params.join('&')}` ).then(response => { @@ -141,7 +152,7 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { const columns = [ { key: 'id', - // sortable: true, + sortable: true, align: 'left', render: data => (
@@ -151,7 +162,7 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { }, { key: 'url', - // sortable: true, + sortable: true, render: data => (
{data.url} @@ -182,7 +193,7 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { }) }, [pagination.page_after_value, pagination.page_size, externalResource]) - return Reference: +async def _get_reference_aflow_prototypes(session: httpx.AsyncClient, path: str, chemical_formula: str) -> List[Reference]: response = await _download(session, path) if response is None: - return None + return [] reference = Reference() reference.database_name = aflow_prototypes_db @@ -335,7 +335,7 @@ async def _get_reference_aflow_prototypes(session: httpx.AsyncClient, path: str) reference.space_group_number = int(data.get('Space group number', 0)) reference.wyckoff_letters = wyckoff_letters_data # chemical formula should correspond to the chemical formula of the entry not the prototype - reference.chemical_formula = None + reference.chemical_formula = chemical_formula # generate structure info response = await _download(session, f'{aflow_home_url}/CIF/{prototype_label}.cif') if response is not None: @@ -352,7 +352,7 @@ async def _get_reference_aflow_prototypes(session: httpx.AsyncClient, path: str) reference.download_time = datetime.now() # push to mongo db reference.save() - return reference + return [reference] async def _get_urls_springer_materials(session: httpx.AsyncClient, chemical_formula: str) -> List[str]: @@ -380,7 +380,7 @@ async def _get_urls_springer_materials(session: httpx.AsyncClient, chemical_form return urls -async def _get_reference_springer_materials(session: httpx.AsyncClient, path: str) -> Reference: +async def _get_reference_springer_materials(session: httpx.AsyncClient, path: str) -> List[Reference]: reference = Reference() reference.url = path reference.id = os.path.basename(path) @@ -388,7 +388,7 @@ async def _get_reference_springer_materials(session: httpx.AsyncClient, path: st response = await _download(session, path) if response is None: logger.error(f'Error accessing springer materials reference.') - return reference + return [reference] try: # we need to query individual entry ONLY to get spacegroup! # TODO find a way to limit springer search to particular spacegroup so @@ -397,14 +397,14 @@ async def _get_reference_springer_materials(session: httpx.AsyncClient, path: st except Exception: data = dict() space_group_number = data.get('space_group_number', '0') - reference.space_group_number = int(space_group_number) if space_group_number.isdecimal() else space_group_number + reference.space_group_number = int(space_group_number) if space_group_number.isdecimal() else None reference.chemical_formula = data.get('normalized_formula') reference.data = data reference.database_version = data.get('version') reference.download_time = datetime.now() # push to mongo db reference.save() - return reference + return [reference] async def _get_urls_optimade(chemical_formula_hill: str, chemical_formula_reduced: str, providers: List[str] = None) -> List[str]: @@ -425,7 +425,7 @@ async def _get_urls_optimade(chemical_formula_hill: str, chemical_formula_reduce return urls -async def _get_references_optimade(session: httpx.AsyncClient, path: str) -> Union[List[Reference], None]: +async def _get_references_optimade(session: httpx.AsyncClient, path: str) -> List[Reference]: response = await _download(session, path) if response is None: logger.error(f'Error accessing optimade references.') @@ -493,10 +493,9 @@ async def get_references( wyckoff_letters.sort() def equal(quantity, input_quantity): - if quantity and input_quantity is not None: - if quantity != input_quantity: - return False - return True + if input_quantity is None: + return True + return quantity == input_quantity optimade_dbs: List[str] = [str(details['name']) for details in optimade_providers.values()] comments = { @@ -512,28 +511,25 @@ async def get_references( Reference to the entry in the {db} database queried using the Optimade API. ''' for db in optimade_dbs}) - def convert_to_model(references): + def convert_to_model(references, filter=False): additional_data = [] for reference in references: - if isinstance(reference, list): - convert_to_model(reference) - continue - elif reference.url is None: - continue - elif reference is None or not reference.id: - continue - elif reference.id.startswith(no_url_found): + if reference is None or reference.url is None or reference.id is None or reference.id.startswith(no_url_found): continue database = reference.database_name - # filter reference if matches query - if not equal(reference.space_group_number, space_group_number): - continue - if not equal(reference.wyckoff_letters, wyckoff_letters): - continue - if not equal(reference.n_sites, n_sites): - continue - if not equal(reference.chemical_formula, chemical_formula): - continue + if filter: + # filter reference if matches query for results of external database query + # we do not want to redo mongo query + if not equal(reference.chemical_formula, chemical_formula): + continue + if database == aflow_prototypes_db or database == springer_materials_db: + if not equal(reference.space_group_number, space_group_number): + continue + if database == aflow_prototypes_db: + if not equal(reference.wyckoff_letters, wyckoff_letters): + continue + if not equal(reference.n_sites, n_sites): + continue sources.setdefault(database, 0) sources[database] += 1 # show the first five results from each resource and the rest we append later @@ -558,7 +554,7 @@ async def get_references( reference.save() query_aflow = Q( - chemical_formula=None, space_group_number=space_group_number, wyckoff_letters=wyckoff_letters, + chemical_formula=chemical_formula, space_group_number=space_group_number, wyckoff_letters=wyckoff_letters, n_sites=n_sites, database_name=aflow_prototypes_db) query_springer = Q( chemical_formula=chemical_formula, space_group_number=space_group_number, @@ -586,41 +582,38 @@ async def get_references( optimade_dbs_query.remove(database) valid_queries_index.append(n) + convert_to_model([query_results[n] for n in valid_queries_index], filter=False) # TODO is this necessary done_urls = [reference.url for reference in data] limits = httpx.Limits(max_connections=config.related_resources.max_connections) async with httpx.AsyncClient(limits=limits) as session: # get urls from sources - tasks = [] - tasks.append(asyncio.create_task(_get_urls_aflow_prototypes(session, space_group_number_query))) - tasks.append(asyncio.create_task(_get_urls_springer_materials(session, chemical_formula_query))) - tasks.append(asyncio.create_task(_get_urls_optimade(chemical_formula_hill, chemical_formula_reduced, optimade_dbs_query))) - urls = await asyncio.gather(*tasks) + aflow_task = asyncio.create_task(_get_urls_aflow_prototypes(session, space_group_number_query)) + springer_task = asyncio.create_task(_get_urls_springer_materials(session, chemical_formula_query)) + optimade_task = asyncio.create_task(_get_urls_optimade(chemical_formula_hill, chemical_formula_reduced, optimade_dbs_query)) + aflow_urls, springer_urls, optimade_urls = await asyncio.gather(aflow_task, springer_task, optimade_task) # get reference(s) corresponding to each url tasks = [] tasks.extend([asyncio.create_task( - _get_reference_aflow_prototypes(session, url)) for url in urls[0] if url not in done_urls]) + _get_reference_aflow_prototypes(session, url, chemical_formula)) for url in aflow_urls if url not in done_urls]) tasks.extend([asyncio.create_task( - _get_reference_springer_materials(session, url)) for url in urls[1] if url not in done_urls]) + _get_reference_springer_materials(session, url)) for url in springer_urls if url not in done_urls]) tasks.extend([asyncio.create_task( - _get_references_optimade(session, url)) for url in urls[2] if url not in done_urls]) + _get_references_optimade(session, url)) for url in optimade_urls if url not in done_urls]) references = await asyncio.gather(*tasks) + # flatten list + references = [ref for reference in references for ref in reference] # filter references to match query and convert to model - convert_to_model([query_results[n] for n in valid_queries_index] + references) + convert_to_model(references, filter=True) # if no references are found, record this in mongodb so as not do perform query again - # queried_databases = [reference.database_name for reference in data] queried_databases = [query_results[n].database_name for n in valid_queries_index] - for reference in references: - if isinstance(reference, list): - queried_databases.extend([ref.database_name for ref in reference]) - else: - queried_databases.append(reference.database_name) + queried_databases.extend([ref.database_name for ref in references]) queried_databases = list(set(queried_databases)) if aflow_prototypes_db not in queried_databases: set_empty_reference( - aflow_prototypes_db, chemical_formula=None, space_group_number=space_group_number, + aflow_prototypes_db, chemical_formula=chemical_formula, space_group_number=space_group_number, wyckoff_letters=wyckoff_letters, n_sites=n_sites) if springer_materials_db not in queried_databases: set_empty_reference( -- GitLab From 8c2c8d2799b0a5fe71911a4aec1793fa6577390c Mon Sep 17 00:00:00 2001 From: Alvin Noe Ladines Date: Wed, 31 Aug 2022 17:41:40 +0200 Subject: [PATCH 03/15] Fix linting --- nomad/app/v1/routers/related_resources.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nomad/app/v1/routers/related_resources.py b/nomad/app/v1/routers/related_resources.py index 96abf73be..67e5bb2b5 100644 --- a/nomad/app/v1/routers/related_resources.py +++ b/nomad/app/v1/routers/related_resources.py @@ -25,7 +25,7 @@ import asyncio import httpx from fastapi import APIRouter, Query as FastApiQuery from pydantic import BaseModel, Field -from typing import List, Any, Dict, Optional, Union +from typing import List, Any, Dict, Optional from datetime import datetime import ase.io from mongoengine import Document, StringField, DateTimeField, IntField, DictField, ListField -- GitLab From eb2bed2bba7f89b819c017175c715c7b5deebea6 Mon Sep 17 00:00:00 2001 From: Alvin Noe Ladines Date: Thu, 1 Sep 2022 16:29:59 +0200 Subject: [PATCH 04/15] Remove archive search --- .../entry/properties/RelatedResourcesCard.js | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/gui/src/components/entry/properties/RelatedResourcesCard.js b/gui/src/components/entry/properties/RelatedResourcesCard.js index 8b69311e2..7fa746d47 100644 --- a/gui/src/components/entry/properties/RelatedResourcesCard.js +++ b/gui/src/components/entry/properties/RelatedResourcesCard.js @@ -26,19 +26,6 @@ import { Datatable, DatatableToolbar, DatatableTable, DatatableLoadMorePaginatio import { sleep, formatTimestamp } from '../../../utils' import Quantity from '../../Quantity' -const searchArchive = (source, path) => { - const path_array = typeof path === 'string' ? path.split('.') : path - if (!source || path_array.length === 0) { - return source - } - - if (Array.isArray(source)) { - return searchArchive(source[source.length - 1][path_array[0]], path_array.slice(1, path.length)) - } - - return searchArchive(source[path_array[0]], path_array.slice(1, path.length)) -} - const useResourceDetailsStyles = makeStyles(theme => ({ resourceDetails: { paddingTop: theme.spacing(2), @@ -118,16 +105,17 @@ ResourceActions.propTypes = { const RelatedResourcesCard = React.memo(({index, archive}) => { const material = archive?.results?.material + const structures = archive?.results?.properties?.structures const classes = useResourceDetailsStyles() const [externalResource, setExternalResource] = useState([[], []]) const {api} = useApi() const {raiseError} = useErrors() - const system = searchArchive(archive, 'run.system.symmetry.system_primitive') useEffect(() => { const spg = material.symmetry?.space_group_number - const wyckoff = system ? system[0]?.wyckoff_letters : null - const nsites = system ? system[0]?.positions.length : null + const wyckoffSets = structures?.structure_conventional?.wyckoff_sets || null + const wyckoff = wyckoffSets ? wyckoffSets.map((set) => set?.wyckoff_letter || '') : null + const nsites = structures?.structure_original?.species_at_sites.length || null const formula = material?.chemical_formula_reduced const params = [] if (spg) { @@ -147,7 +135,7 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { ).then(response => { setExternalResource([response.data, response?.metadata?.sources]) }).catch(raiseError) - }, [material, system, api, raiseError]) + }, [material, structures, api, raiseError]) const columns = [ { @@ -193,7 +181,11 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { }) }, [pagination.page_after_value, pagination.page_size, externalResource]) - return data && Date: Wed, 7 Sep 2022 13:29:38 +0200 Subject: [PATCH 05/15] Fix commit --- gui/src/components/entry/properties/RelatedResourcesCard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/src/components/entry/properties/RelatedResourcesCard.js b/gui/src/components/entry/properties/RelatedResourcesCard.js index 7fa746d47..f6cb21bdd 100644 --- a/gui/src/components/entry/properties/RelatedResourcesCard.js +++ b/gui/src/components/entry/properties/RelatedResourcesCard.js @@ -112,7 +112,7 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { const {raiseError} = useErrors() useEffect(() => { - const spg = material.symmetry?.space_group_number + const spg = material?.symmetry?.space_group_number const wyckoffSets = structures?.structure_conventional?.wyckoff_sets || null const wyckoff = wyckoffSets ? wyckoffSets.map((set) => set?.wyckoff_letter || '') : null const nsites = structures?.structure_original?.species_at_sites.length || null -- GitLab From 6273c4f94af425a8d2f964a3c77f176e4df604c5 Mon Sep 17 00:00:00 2001 From: Alvin Noe Ladines Date: Wed, 7 Sep 2022 19:40:46 +0200 Subject: [PATCH 06/15] Fix linting --- nomad/app/v1/routers/related_resources.py | 3 +++ nomad/config.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/nomad/app/v1/routers/related_resources.py b/nomad/app/v1/routers/related_resources.py index 67e5bb2b5..e3000834c 100644 --- a/nomad/app/v1/routers/related_resources.py +++ b/nomad/app/v1/routers/related_resources.py @@ -591,6 +591,9 @@ async def get_references( aflow_task = asyncio.create_task(_get_urls_aflow_prototypes(session, space_group_number_query)) springer_task = asyncio.create_task(_get_urls_springer_materials(session, chemical_formula_query)) optimade_task = asyncio.create_task(_get_urls_optimade(chemical_formula_hill, chemical_formula_reduced, optimade_dbs_query)) + aflow_urls: List[str] + springer_urls: List[str] + optimade_urls: List[str] aflow_urls, springer_urls, optimade_urls = await asyncio.gather(aflow_task, springer_task, optimade_task) # get reference(s) corresponding to each url tasks = [] diff --git a/nomad/config.py b/nomad/config.py index 6f3680829..c76d31eb8 100644 --- a/nomad/config.py +++ b/nomad/config.py @@ -329,7 +329,7 @@ related_resources = NomadConfig( # Number of download retries download_retries=2, # Delay in seconds before each successive retry - download_retry_delay=30, + download_retry_delay=10, # Maximum number of httpx connections max_connections=10 ) -- GitLab From cccc25bd3c8b214065b77b8b5de1a1cde871c49b Mon Sep 17 00:00:00 2001 From: Alvin Noe Ladines Date: Thu, 8 Sep 2022 14:48:12 +0200 Subject: [PATCH 07/15] Fix gui test error --- .../entry/properties/RelatedResourcesCard.js | 3 +- gui/tests/data/entry/eln-author.json | 34 +++++++++++++++++-- gui/tests/data/entry/eln-coauthor.json | 34 +++++++++++++++++-- gui/tests/data/entry/eln-concurrent.json | 22 +++++++++--- gui/tests/data/entry/eln-reviewer.json | 34 +++++++++++++++++-- tests/states/archives/dft.json | 6 ++-- 6 files changed, 119 insertions(+), 14 deletions(-) diff --git a/gui/src/components/entry/properties/RelatedResourcesCard.js b/gui/src/components/entry/properties/RelatedResourcesCard.js index f6cb21bdd..7c49d76d7 100644 --- a/gui/src/components/entry/properties/RelatedResourcesCard.js +++ b/gui/src/components/entry/properties/RelatedResourcesCard.js @@ -115,7 +115,8 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { const spg = material?.symmetry?.space_group_number const wyckoffSets = structures?.structure_conventional?.wyckoff_sets || null const wyckoff = wyckoffSets ? wyckoffSets.map((set) => set?.wyckoff_letter || '') : null - const nsites = structures?.structure_original?.species_at_sites.length || null + const species = structures?.structure_original?.species_at_sites || null + const nsites = species ? species.length : null const formula = material?.chemical_formula_reduced const params = [] if (spg) { diff --git a/gui/tests/data/entry/eln-author.json b/gui/tests/data/entry/eln-author.json index 51987ea0c..fa7845b70 100644 --- a/gui/tests/data/entry/eln-author.json +++ b/gui/tests/data/entry/eln-author.json @@ -187,7 +187,7 @@ }, "headers": { "connection": "close", - "content-length": "5457", + "content-length": "5498", "content-type": "application/json", "server": "uvicorn" } @@ -29352,7 +29352,37 @@ }, "headers": { "connection": "close", - "content-length": "657637", + "content-length": "657686", + "content-type": "application/json", + "server": "uvicorn" + } + } + } + ], + "60e8ee7960994a17dba75907439a8103": [ + { + "request": { + "url": "http://localhost:8000/fairdi/nomad/latest/api/v1/related_resources/?", + "method": "GET", + "body": "", + "headers": { + "accept": "application/json", + "authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSWFFIV1YxSEJ6cmh5U3h3UmRDdkhCcUF1WVNKRzZWSEJSZXg0TW5oX293In0.eyJqdGkiOiJjNGZmODhhOC1hM2RkLTQzNmItYTM3Yy1lMTViZmU0YTQ1NzAiLCJleHAiOjE2NjI2NzY4NTEsIm5iZiI6MCwiaWF0IjoxNjYyNjQwODY1LCJpc3MiOiJodHRwczovL25vbWFkLWxhYi5ldS9mYWlyZGkva2V5Y2xvYWsvYXV0aC9yZWFsbXMvZmFpcmRpX25vbWFkX3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNjg4NzhhZjctNjg0NS00NmMwLWIyYzEtMjUwZDRkOGViNDcwIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibm9tYWRfZ3VpX2RldiIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjJjZDY4ZmMxLTU3OGEtNDYyMC1hZDkxLTI2ZTc1ZTg4YTk5YyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoiZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoiTWFya3VzIFNjaGVpZGdlbiIsInByZWZlcnJlZF91c2VybmFtZSI6InRlc3QiLCJnaXZlbl9uYW1lIjoiTWFya3VzIiwiZmFtaWx5X25hbWUiOiJTY2hlaWRnZW4iLCJlbWFpbCI6Im1hcmt1cy5zY2hlaWRnZW5AZmhpLWJlcmxpbi5kZSJ9.T5lqR2G8JryTbSAZwee21zPu1vv84yGCATqo-guAdxD56pR6m3TUO9dvnotaDwABI1UYKl3X20IcegMnTkEBlmNo4nObMmTPw0rePDCnpeSGYP90aGmZKoEUDg4JvfD11xK6tNvkReMa_YGADsgz6Kfp1JfvaUN7H55TnaQ4QdJcBa7ow5WxAnTKomkDgZrmDH9pqJXl01JWeQ6fFXx9nBA8JiXpzJTADMTld6rl9olgR0z8zzCaaIVFy77KnUtdd_BGe5W7x7xhchekNdct1tt7TFasacOzXxGBqgeQa0aXgaldKFGOb7XX_rH3hCNRCO1wSzdij-3ZYhhYgym-EA", + "cookie": null + } + }, + "response": { + "status": 200, + "body": { + "metadata": { + "sources": [], + "n_references": [] + }, + "data": [] + }, + "headers": { + "connection": "close", + "content-length": "79", "content-type": "application/json", "server": "uvicorn" } diff --git a/gui/tests/data/entry/eln-coauthor.json b/gui/tests/data/entry/eln-coauthor.json index 8b009d699..cb6be211f 100644 --- a/gui/tests/data/entry/eln-coauthor.json +++ b/gui/tests/data/entry/eln-coauthor.json @@ -187,7 +187,7 @@ }, "headers": { "connection": "close", - "content-length": "5457", + "content-length": "5498", "content-type": "application/json", "server": "uvicorn" } @@ -29352,7 +29352,37 @@ }, "headers": { "connection": "close", - "content-length": "657637", + "content-length": "657686", + "content-type": "application/json", + "server": "uvicorn" + } + } + } + ], + "60e8ee7960994a17dba75907439a8103": [ + { + "request": { + "url": "http://localhost:8000/fairdi/nomad/latest/api/v1/related_resources/?", + "method": "GET", + "body": "", + "headers": { + "accept": "application/json", + "authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSWFFIV1YxSEJ6cmh5U3h3UmRDdkhCcUF1WVNKRzZWSEJSZXg0TW5oX293In0.eyJqdGkiOiJjMTc4ZDRhYi1hODUzLTQ0YTUtYjhhNS1kYWY5MWJkNWVjNWMiLCJleHAiOjE2NjI2NzY4NzQsIm5iZiI6MCwiaWF0IjoxNjYyNjQwODg5LCJpc3MiOiJodHRwczovL25vbWFkLWxhYi5ldS9mYWlyZGkva2V5Y2xvYWsvYXV0aC9yZWFsbXMvZmFpcmRpX25vbWFkX3Rlc3QiLCJhdWQiOlsicmVhbG0tbWFuYWdlbWVudCIsImFjY291bnQiXSwic3ViIjoiYTAzYWY4YjYtM2FhNy00MjhhLWIzYjEtNGE2MzE3ZTU3NmI2IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibm9tYWRfZ3VpX2RldiIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6Ijk2NDE5MmYyLTJkN2QtNDQ0Yy05YjAyLTMyNWU1NjVhZWU0NyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InJlYWxtLW1hbmFnZW1lbnQiOnsicm9sZXMiOlsidmlldy11c2VycyIsInF1ZXJ5LWdyb3VwcyIsInF1ZXJ5LXVzZXJzIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IlNoZWxkb24gQ29vcGVyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2Nvb3BlciIsImdpdmVuX25hbWUiOiJTaGVsZG9uIiwiZmFtaWx5X25hbWUiOiJDb29wZXIiLCJlbWFpbCI6InNoZWxkb24uY29vcGVyQG5vbWFkLWNvZS5ldSJ9.MRv13WV0TpnvD2qZLdP08kWYvbP0AelVhjzMY_uu1RykPUyx6rUxnVpOZAAvpeWhH4qJ51A_gcdpna1XLe9x7KEDc2HeEg5IbPjWeDLWhdEMksFoczXUtC47DXX7Sw81ASU_MJwInFeHt_5NDr6xkbfoZkHKqrsFrFNGL8Mp1zLramU3CGsz4kqsjunOkmduUinaEr4MtaNNln8HFh-__yF5akCeVnMpEu5A76IGQPX1NHi11lNkaekMfsBMU-3iXLBjiOGDQgQZjT2TWPL1F71X7WNr51oB7ZzHHx45nJnam0L4-njBtVNiXGcrmcJLKztsBPlyivf6KVM6g0pCgw", + "cookie": null + } + }, + "response": { + "status": 200, + "body": { + "metadata": { + "sources": [], + "n_references": [] + }, + "data": [] + }, + "headers": { + "connection": "close", + "content-length": "79", "content-type": "application/json", "server": "uvicorn" } diff --git a/gui/tests/data/entry/eln-concurrent.json b/gui/tests/data/entry/eln-concurrent.json index 2bf85d462..f39261dc7 100644 --- a/gui/tests/data/entry/eln-concurrent.json +++ b/gui/tests/data/entry/eln-concurrent.json @@ -187,7 +187,7 @@ }, "headers": { "connection": "close", - "content-length": "5457", + "content-length": "5498", "content-type": "application/json", "server": "uvicorn" } @@ -380,7 +380,7 @@ }, "headers": { "connection": "close", - "content-length": "5457", + "content-length": "5498", "content-type": "application/json", "server": "uvicorn" } @@ -573,7 +573,7 @@ }, "headers": { "connection": "close", - "content-length": "5457", + "content-length": "5498", "content-type": "application/json", "server": "uvicorn" } @@ -29762,7 +29762,7 @@ }, "headers": { "connection": "close", - "content-length": "657637", + "content-length": "657686", "content-type": "application/json", "server": "uvicorn" } @@ -29842,6 +29842,20 @@ "timestamp": "2022-09-13 13:54.35", "level": "INFO" }, + { + "normalizer": "MetainfoNormalizer", + "section": "Sample", + "event": "could not normalize section", + "proc": "Entry", + "process": "process_entry", + "process_worker_id": "R7a8cjjAQgqdAmJ5tSYBGw", + "parser": "parsers/archive", + "step": "MetainfoNormalizer", + "logger": "nomad.processing", + "exception": "Traceback (most recent call last):\n File \"/home/alvin/work/nomad2/nomad/nomad/normalizing/metainfo.py\", line 35, in normalize_section\n normalize(self.entry_archive, logger)\n File \"/home/alvin/work/nomad2/nomad/nomad/datamodel/metainfo/eln/__init__.py\", line 145, in normalize\n from pymatgen.core import Composition\n File \"/home/alvin/work/nomad2/nomad/.nomadenv/lib/python3.8/site-packages/pymatgen/core/__init__.py\", line 20, in \n from .lattice import Lattice # noqa\n File \"/home/alvin/work/nomad2/nomad/.nomadenv/lib/python3.8/site-packages/pymatgen/core/lattice.py\", line 22, in \n from pymatgen.util.coord import pbc_shortest_vectors\n File \"/home/alvin/work/nomad2/nomad/.nomadenv/lib/python3.8/site-packages/pymatgen/util/coord.py\", line 17, in \n from . import coord_cython as cuc\n File \"pymatgen/util/coord_cython.pyx\", line 1, in init pymatgen.util.coord_cython\nValueError: numpy.ndarray size changed, may indicate binary incompatibility. Expected 96 from C header, got 88 from PyObject", + "timestamp": "2022-09-08 14:41.56", + "level": "ERROR" + }, { "normalizer": "MetainfoNormalizer", "step": "MetainfoNormalizer", diff --git a/gui/tests/data/entry/eln-reviewer.json b/gui/tests/data/entry/eln-reviewer.json index 916aab44a..1df7cf415 100644 --- a/gui/tests/data/entry/eln-reviewer.json +++ b/gui/tests/data/entry/eln-reviewer.json @@ -187,7 +187,7 @@ }, "headers": { "connection": "close", - "content-length": "5457", + "content-length": "5498", "content-type": "application/json", "server": "uvicorn" } @@ -29352,7 +29352,37 @@ }, "headers": { "connection": "close", - "content-length": "657637", + "content-length": "657686", + "content-type": "application/json", + "server": "uvicorn" + } + } + } + ], + "60e8ee7960994a17dba75907439a8103": [ + { + "request": { + "url": "http://localhost:8000/fairdi/nomad/latest/api/v1/related_resources/?", + "method": "GET", + "body": "", + "headers": { + "accept": "application/json", + "authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSWFFIV1YxSEJ6cmh5U3h3UmRDdkhCcUF1WVNKRzZWSEJSZXg0TW5oX293In0.eyJqdGkiOiI4NzE0OGFmNi01Yzg5LTQ1ZmEtYTdkNi1lOTU5NjJjMjZlYWEiLCJleHAiOjE2NjI2NzY4MjcsIm5iZiI6MCwiaWF0IjoxNjYyNjQwODQyLCJpc3MiOiJodHRwczovL25vbWFkLWxhYi5ldS9mYWlyZGkva2V5Y2xvYWsvYXV0aC9yZWFsbXMvZmFpcmRpX25vbWFkX3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNTRjYjFmNjQtZjg0ZS00ODE1LTlhZGUtNDQwY2UwYjU0MzBmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibm9tYWRfZ3VpX2RldiIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjQ0YzRkYjMxLTNmNjEtNDkwOC05Y2NiLTUxMWM5ZTk3ZmY0YiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoiZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoiVGVzdCBUZXN0ZXIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0dGVzdGVyIiwiZ2l2ZW5fbmFtZSI6IlRlc3QiLCJmYW1pbHlfbmFtZSI6IlRlc3RlciIsImVtYWlsIjoidGVzdEBub21hZC1jb2UuZXUifQ.iGmN1qaG0OScK6EWj_1oHAa-xFM1TcTikJLiHgPUHSi91VqzsWklp8tbGGmxmKIASmVc3wnlERLRAQ18j4M_a8l6Vgq5lHvH0muc62uAvKie63onbUgUzweuLRy6Po0LUgfkM0wrKMMCcvaTmbS4VTVnep2fNaJpXkcS-eT_YBMwPh137O8JQ9rD-nfn4J9FDMzDlNV7CEsQqKdKBZJ-Z4wBQfIusDtCsryffTcsF69Wctl2KjQJ_BGPt54juXUOHI3ifom2k50r-5pr_0rKf6t8-DP15X2QJiZ527cqFP4MNtGX4OZ8J6aXZO2JFniix4zhx7vLCc3pSI-O1BMLQg", + "cookie": null + } + }, + "response": { + "status": 200, + "body": { + "metadata": { + "sources": [], + "n_references": [] + }, + "data": [] + }, + "headers": { + "connection": "close", + "content-length": "79", "content-type": "application/json", "server": "uvicorn" } diff --git a/tests/states/archives/dft.json b/tests/states/archives/dft.json index b41aa679e..4899fa39b 100644 --- a/tests/states/archives/dft.json +++ b/tests/states/archives/dft.json @@ -280,15 +280,15 @@ ], "metadata": { "upload_id": "dft_upload", - "upload_create_time": "2022-08-25T18:43:53.051019+00:00", + "upload_create_time": "2022-09-08T12:40:10.552344+00:00", "entry_id": "dft_bulk", "calc_id": "dft_bulk", "entry_hash": "dummy_hash_dft_bulk", - "entry_create_time": "2022-08-25T18:43:53.055019+00:00", + "entry_create_time": "2022-09-08T12:40:10.556344+00:00", "parser_name": "parsers/vasp", "mainfile": "vasp.xml", "published": true, - "publish_time": "2022-08-25T18:43:53.054019+00:00", + "publish_time": "2022-09-08T12:40:10.555344+00:00", "with_embargo": false, "embargo_length": 0, "license": "CC BY 4.0", -- GitLab From d0b9afbe1511352fa4e7fde7c599db4be65cc3b4 Mon Sep 17 00:00:00 2001 From: Alvin Noe Ladines Date: Thu, 15 Sep 2022 18:03:07 +0200 Subject: [PATCH 08/15] Move resources into own app, add test --- gui/src/components/APIs.js | 9 + gui/src/components/api.js | 18 +- .../entry/properties/RelatedResourcesCard.js | 41 +- nomad/app/main.py | 2 + nomad/app/resources/__init__.py | 0 nomad/app/resources/common.py | 23 + nomad/app/resources/main.py | 93 + nomad/app/resources/routers/__init__.py | 0 .../routers/resources.py} | 237 +- nomad/app/v1/main.py | 3 +- nomad/config.py | 7 +- tests/app/test_resources.py | 94 + .../app/v1/routers/test_related_resources.py | 46 - tests/data/api/responses.json | 9830 +++++++++++++++++ 14 files changed, 10210 insertions(+), 193 deletions(-) create mode 100644 nomad/app/resources/__init__.py create mode 100644 nomad/app/resources/common.py create mode 100644 nomad/app/resources/main.py create mode 100644 nomad/app/resources/routers/__init__.py rename nomad/app/{v1/routers/related_resources.py => resources/routers/resources.py} (75%) create mode 100644 tests/app/test_resources.py delete mode 100644 tests/app/v1/routers/test_related_resources.py create mode 100644 tests/data/api/responses.json diff --git a/gui/src/components/APIs.js b/gui/src/components/APIs.js index 4427d6a7d..3a2699f63 100644 --- a/gui/src/components/APIs.js +++ b/gui/src/components/APIs.js @@ -79,6 +79,15 @@ export default function About() { interoperability between data catalogs published on the Web. This API allows you access to NOMAD via RDF documents following DCAT. You can access NOMAD entries as DCAT Datasets or all NOMAD entries as a DCAT Catalog. + + ## Resources + + - [Resources API dashboard](${appBase}/resources/extensions/docs) + + The resources API provides links from NOMAD entries to related external resources. + These include the [Aflow Encyclopedia of Crystallographic Prototypes](https://www.aflowlib.org/prototype-encyclopedia/), + [Springer Materials Database of Inorganic Solid Phases](https://materials.springer.com) + and [OPTIMADE providers](https://providers.optimade.org/). `}
} diff --git a/gui/src/components/api.js b/gui/src/components/api.js index 1d44de321..018c62237 100644 --- a/gui/src/components/api.js +++ b/gui/src/components/api.js @@ -24,7 +24,7 @@ import { } from 'recoil' import PropTypes from 'prop-types' import Cookies from 'universal-cookie' -import { apiBase, globalLoginRequired } from '../config' +import { apiBase, globalLoginRequired, appBase } from '../config' import { Box, makeStyles, Typography } from '@material-ui/core' import LoginLogout from './LoginLogout' import { useKeycloak } from '@react-keycloak/web' @@ -94,6 +94,21 @@ function handleApiError(e) { throw error } +class ResourcesApi { + constructor(api) { + this.api = api + this.apiKey = null + this.axios = axios.create({ + baseURL: `${appBase}/resources` + }) + } + + async get(path, query, config) { + const GET = (path, body, config) => this.axios.get(path, config) + return this.api.doHttpRequest(GET, path, null, {params: query, methodName: 'GET', ...config}) + } +} + class Api { constructor(keycloak, setLoading) { this.keycloak = keycloak @@ -387,6 +402,7 @@ export const APIProvider = React.memo(({ const value = useMemo(() => ({ api: api, northApi: user ? new NorthApi(api, `users/${user.preferred_username}`) : null, + resourcesApi: new ResourcesApi(api), user: user }), [api, user]) diff --git a/gui/src/components/entry/properties/RelatedResourcesCard.js b/gui/src/components/entry/properties/RelatedResourcesCard.js index 7c49d76d7..f32b3a9b8 100644 --- a/gui/src/components/entry/properties/RelatedResourcesCard.js +++ b/gui/src/components/entry/properties/RelatedResourcesCard.js @@ -66,16 +66,15 @@ const useResourceDetailsStyles = makeStyles(theme => ({ } })) -function ResourceDetails({data}) { +const ResourceDetails = React.memo(({data}) => { const classes = useResourceDetailsStyles() - const availableData = {data_keys: Object.keys(data.data)} const downloadTime = {download_time: formatTimestamp(data?.download_time)} return
- +
@@ -85,35 +84,36 @@ function ResourceDetails({data}) {
-} +}) ResourceDetails.propTypes = { data: PropTypes.object.isRequired } -function ResourceActions({data}) { +const ResourceActions = React.memo(({data}) => { return { window.location = data.url }} > -} +}) + ResourceActions.propTypes = { data: PropTypes.object.isRequired } const RelatedResourcesCard = React.memo(({index, archive}) => { - const material = archive?.results?.material - const structures = archive?.results?.properties?.structures const classes = useResourceDetailsStyles() - const [externalResource, setExternalResource] = useState([[], []]) - const {api} = useApi() + const [externalResources, setExternalResources] = useState([]) + const {resourcesApi} = useApi() const {raiseError} = useErrors() useEffect(() => { + const material = archive?.results?.material const spg = material?.symmetry?.space_group_number - const wyckoffSets = structures?.structure_conventional?.wyckoff_sets || null + const structures = archive?.results?.properties?.structures + const wyckoffSets = structures?.structure_conventional?.wyckoff_sets const wyckoff = wyckoffSets ? wyckoffSets.map((set) => set?.wyckoff_letter || '') : null const species = structures?.structure_original?.species_at_sites || null const nsites = species ? species.length : null @@ -131,12 +131,11 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { if (formula) { params.push(`chemical_formula_reduced=${formula}`) } - api.get( - `/related_resources/?${params.join('&')}` - ).then(response => { - setExternalResource([response.data, response?.metadata?.sources]) - }).catch(raiseError) - }, [material, structures, api, raiseError]) + resourcesApi.get(`/?${params.join('&')}`) + .then(response => { + setExternalResources(response) + }).catch(raiseError) + }, [archive, resourcesApi, raiseError]) const columns = [ { @@ -166,7 +165,7 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { ] const [pagination, setPagination] = useState({ - total: externalResource[0].length | 100, page_size: 10 + total: externalResources.length | 100, page_size: 10 }) const [data, setData] = useState([]) @@ -174,13 +173,13 @@ const RelatedResourcesCard = React.memo(({index, archive}) => { useEffect(() => { sleep(100).then(() => { const nextPageAfterValueInt = parseInt(pagination.page_after_value || 0) + pagination.page_size - setData(externalResource[0].slice(0, nextPageAfterValueInt)) + setData(externalResources.slice(0, nextPageAfterValueInt)) setPagination(pagination => ({ ...pagination, - next_page_after_value: nextPageAfterValueInt > externalResource[0].length ? null : String(nextPageAfterValueInt) + next_page_after_value: nextPageAfterValueInt > externalResources.length ? null : String(nextPageAfterValueInt) })) }) - }, [pagination.page_after_value, pagination.page_size, externalResource]) + }, [pagination.page_after_value, pagination.page_size, externalResources]) if (data.length === 0) { return '' diff --git a/nomad/app/main.py b/nomad/app/main.py index 04b2a1067..1e767727d 100644 --- a/nomad/app/main.py +++ b/nomad/app/main.py @@ -30,6 +30,7 @@ from .dcat.main import app as dcat_app from .optimade import optimade_app from .v1.main import app as v1_app from .h5grove_app import app as h5grove_app +from .resources.main import app as resources_app class OasisAuthenticationMiddleware(BaseHTTPMiddleware): @@ -63,6 +64,7 @@ app.mount(f'{app_base}/api/v1', v1_app) app.mount(f'{app_base}/dcat', dcat_app) app.mount(f'{app_base}/optimade', optimade_app) app.mount(f'{app_base}/h5grove', h5grove_app) +app.mount(f'{app_base}/resources', resources_app) dist_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../dist')) docs_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../docs/build')) diff --git a/nomad/app/resources/__init__.py b/nomad/app/resources/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nomad/app/resources/common.py b/nomad/app/resources/common.py new file mode 100644 index 000000000..652ac9500 --- /dev/null +++ b/nomad/app/resources/common.py @@ -0,0 +1,23 @@ +# +# 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. +# + +from nomad import config + + +root_path = f'{config.services.api_base_path}/resources' +base_url = config.api_url(api='resources') diff --git a/nomad/app/resources/main.py b/nomad/app/resources/main.py new file mode 100644 index 000000000..b4d8bd425 --- /dev/null +++ b/nomad/app/resources/main.py @@ -0,0 +1,93 @@ +# +# 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. +# + +from fastapi import FastAPI, status, Request +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse +import traceback + +from nomad import config, utils + +from .routers import resources + + +logger = utils.get_logger(__name__) + +mongo_client_resources = None + +app = FastAPI( + openapi_url='/openapi.json', + docs_url='/extensions/docs', + redoc_url='/extensions/redoc', + swagger_ui_oauth2_redirect_url='/extensions/docs/oauth2-redirect', + title='Resources API', + version='v1, NOMAD %s@%s' % (config.meta.version, config.meta.commit), + description='NOMAD\'s API for serving related external resources') + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.exception_handler(Exception) +async def unicorn_exception_handler(request: Request, e: Exception): + logger.error('unexpected exception in API', url=request.url, exc_info=e) + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + 'detail': { + 'reason': 'Unexpected exception while handling your request', + 'exception': str(e), + 'exception_class': e.__class__.__name__, + 'exception_traceback': traceback.format_exc() + } + } + ) + + +@app.middleware('http') +async def setup(request: Request, callback): + + setup_mongo() + + response = await callback(request) + return response + + +def setup_mongo(): + global mongo_client_resources + + if mongo_client_resources is None: + from mongoengine import connect + mongo_client_resources = connect( + db=config.resources.db_name, alias='resources', host=config.mongo.host, port=config.mongo.port) + + +def remove_mongo(): + global mongo_client_resources + + setup_mongo() + + mongo_client_resources.drop_database(config.resources.db_name) + + +app.include_router(resources.router) diff --git a/nomad/app/resources/routers/__init__.py b/nomad/app/resources/routers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nomad/app/v1/routers/related_resources.py b/nomad/app/resources/routers/resources.py similarity index 75% rename from nomad/app/v1/routers/related_resources.py rename to nomad/app/resources/routers/resources.py index e3000834c..e9cb1aa63 100644 --- a/nomad/app/v1/routers/related_resources.py +++ b/nomad/app/resources/routers/resources.py @@ -28,7 +28,7 @@ from pydantic import BaseModel, Field from typing import List, Any, Dict, Optional from datetime import datetime import ase.io -from mongoengine import Document, StringField, DateTimeField, IntField, DictField, ListField +from mongoengine import Document, StringField, DateTimeField, IntField, ListField from mongoengine.queryset.visitor import Q from nomad import utils, config, atomutils @@ -38,7 +38,7 @@ logger = utils.get_logger(__name__) router = APIRouter() -default_tag = 'related_resources' +default_tag = 'resources' # TODO generate list from optimade api optimade_providers = { @@ -111,14 +111,14 @@ space_groups = ['triclinic'] * 2 + ['monoclinic'] * 13 + ['orthorhombic'] * 59 + spaces_re = re.compile(r'\s+') -search_re = re.compile(" href=\"(/isp/[^\"]+)") +search_re = re.compile(' href=\"(/isp/[^\"]+)') formula_re = re.compile(r'([A-Z][a-z]?)([0-9.]*)|\[(.*?)\]([0-9]+)') elements_re = re.compile(r'[A-Z][a-z]*') prototype_re = re.compile(r'\
') wyckoff_re = re.compile(r'\\left\(\d+([a-z])\\right\)') -class Reference(Document): +class Resource(Document): id = StringField(primary_key=True) url = StringField() database_name = StringField() @@ -126,16 +126,20 @@ class Reference(Document): chemical_formula = StringField() wyckoff_letters = ListField() download_time = DateTimeField() - data = DictField() + # TODO determine if saving the data is necessary, it is too much for the mongo db + # data = DictField() + available_data = ListField() space_group_number = IntField() n_sites = IntField() - meta = {'indexes': ['chemical_formula']} + meta = {'db_alias': 'resources', 'indexes': ['chemical_formula']} -class ReferenceModel(BaseModel): - data: Dict[str, Any] = Field( - {}, description=''' Value of the data referenced by the entry. - ''') +class ResourceModel(BaseModel): + # data: Dict[str, Any] = Field( + # {}, description=''' Value of the data referenced by the entry. + # ''') + available_data: List[str] = Field( + [], description='''List of available data referenced by the entry''') url: str = Field( None, description=''' URL of the entry in the database. @@ -173,11 +177,6 @@ class ReferenceModel(BaseModel): return super()._get_value(v, to_dict=to_dict, **kwargs) -class ReferencesResponseModel(BaseModel): - metadata: Dict[str, Any] = Field(None) - data: List[ReferenceModel] = Field(None) - - async def _download(session: httpx.AsyncClient, path: str) -> httpx.Response: n_retries = 0 while True: @@ -188,9 +187,9 @@ async def _download(session: httpx.AsyncClient, path: str) -> httpx.Response: except Exception: pass n_retries += 1 - if n_retries > config.related_resources.download_retries: + if n_retries > config.resources.download_retries: break - await asyncio.sleep(config.related_resources.download_retry_delay) + await asyncio.sleep(config.resources.download_retry_delay) return None @@ -229,7 +228,7 @@ def _normalize_formula(formula_str: str) -> str: symbol_normamount = {e: round(a / total * 100.) for e, a in symbol_amount.items()} formula_sorted = [ - '%s%d' % (s, symbol_normamount[s]) for s in sorted(list(symbol_normamount.keys()))] + f'{s}{symbol_normamount[s]}' for s in sorted(list(symbol_normamount.keys()))] return ''.join(formula_sorted) @@ -238,10 +237,10 @@ def parse_springer_entry(htmltext: str) -> Dict[str, str]: ''' Parse the springer entry quantities in required_items from an html text. ''' - soup = bs4.BeautifulSoup(htmltext, "html.parser") + soup = bs4.BeautifulSoup(htmltext, 'html.parser') results = {} - for item in soup.find_all(attrs={"class": "data-list__item"}): - key = item.find(attrs={"class": "data-list__item-key"}) + for item in soup.find_all(attrs={'class': 'data-list__item'}): + key = item.find(attrs={'class': 'data-list__item-key'}) if not key: continue @@ -249,7 +248,7 @@ def parse_springer_entry(htmltext: str) -> Dict[str, str]: if key_str not in springer_required_items: continue - value = item.find(attrs={"class": "data-list__item-value"}) + value = item.find(attrs={'class': 'data-list__item-value'}) value = spaces_re.sub(' ', value.get_text()).strip() results[springer_required_items[key_str]] = value @@ -257,10 +256,10 @@ def parse_springer_entry(htmltext: str) -> Dict[str, str]: break if 'classification' in results: - results['classification'] = [x.strip() for x in results['classification'].split(",")] + results['classification'] = [x.strip() for x in results['classification'].split(',')] results['classification'] = [x for x in results['classification'] if x != '–'] if 'compound_classes' in results: - results['compound_classes'] = [x.strip() for x in results['compound_classes'].split(",")] + results['compound_classes'] = [x.strip() for x in results['compound_classes'].split(',')] results['compound_classes'] = [x for x in results['compound_classes'] if x != '–'] normalized_formula = None @@ -276,7 +275,7 @@ def parse_springer_entry(htmltext: str) -> Dict[str, str]: results['normalized_formula'] = normalized_formula # get database version - for item in soup.find_all(attrs={"class": "about_content_comments"}): + for item in soup.find_all(attrs={'class': 'about_content_comments'}): version_match = re.search(r'Version (.+)\.', item.string.strip()) if version_match: results['version'] = version_match.group(1) @@ -316,26 +315,26 @@ async def _get_urls_aflow_prototypes(session: httpx.AsyncClient, space_group_num return urls -async def _get_reference_aflow_prototypes(session: httpx.AsyncClient, path: str, chemical_formula: str) -> List[Reference]: +async def _get_resources_aflow_prototypes(session: httpx.AsyncClient, path: str, chemical_formula: str) -> List[Resource]: response = await _download(session, path) if response is None: return [] - reference = Reference() - reference.database_name = aflow_prototypes_db + resource = Resource() + resource.database_name = aflow_prototypes_db wyckoff_letters_data = wyckoff_re.findall(response.text) - reference.n_sites = len(wyckoff_letters_data) + resource.n_sites = len(wyckoff_letters_data) wyckoff_letters_data = list(set(wyckoff_letters_data)) wyckoff_letters_data.sort() # compare wyckoff with input - reference.url = path + resource.url = path data = parse_aflow_prototype(response.text) prototype_label = data.get('AFLOW prototype label', '') - reference.id = prototype_label - reference.space_group_number = int(data.get('Space group number', 0)) - reference.wyckoff_letters = wyckoff_letters_data + resource.id = prototype_label + resource.space_group_number = int(data.get('Space group number', 0)) + resource.wyckoff_letters = wyckoff_letters_data # chemical formula should correspond to the chemical formula of the entry not the prototype - reference.chemical_formula = chemical_formula + resource.chemical_formula = chemical_formula # generate structure info response = await _download(session, f'{aflow_home_url}/CIF/{prototype_label}.cif') if response is not None: @@ -346,13 +345,12 @@ async def _get_reference_aflow_prototypes(session: httpx.AsyncClient, path: str, data['lattice_vectors'] = atoms.get_cell().tolist() data['atom_positions'] = atoms.get_positions().tolist() data['atom_labels'] = atoms.get_chemical_symbols() - # else: - # return None - reference.data = data - reference.download_time = datetime.now() + # resource.data = data + resource.available_data = list(data.keys()) + resource.download_time = datetime.now() # push to mongo db - reference.save() - return [reference] + resource.save() + return [resource] async def _get_urls_springer_materials(session: httpx.AsyncClient, chemical_formula: str) -> List[str]: @@ -380,15 +378,15 @@ async def _get_urls_springer_materials(session: httpx.AsyncClient, chemical_form return urls -async def _get_reference_springer_materials(session: httpx.AsyncClient, path: str) -> List[Reference]: - reference = Reference() - reference.url = path - reference.id = os.path.basename(path) - reference.database_name = springer_materials_db +async def _get_resources_springer_materials(session: httpx.AsyncClient, path: str) -> List[Resource]: + resource = Resource() + resource.url = path + resource.id = os.path.basename(path) + resource.database_name = springer_materials_db response = await _download(session, path) if response is None: - logger.error(f'Error accessing springer materials reference.') - return [reference] + logger.error(f'Error accessing springer materials resource.') + return [resource] try: # we need to query individual entry ONLY to get spacegroup! # TODO find a way to limit springer search to particular spacegroup so @@ -397,14 +395,15 @@ async def _get_reference_springer_materials(session: httpx.AsyncClient, path: st except Exception: data = dict() space_group_number = data.get('space_group_number', '0') - reference.space_group_number = int(space_group_number) if space_group_number.isdecimal() else None - reference.chemical_formula = data.get('normalized_formula') - reference.data = data - reference.database_version = data.get('version') - reference.download_time = datetime.now() + resource.space_group_number = int(space_group_number) if space_group_number.isdecimal() else None + resource.chemical_formula = data.get('normalized_formula') + # resource.data = data + resource.available_data = list(data.keys()) + resource.database_version = data.get('version') + resource.download_time = datetime.now() # push to mongo db - reference.save() - return [reference] + resource.save() + return [resource] async def _get_urls_optimade(chemical_formula_hill: str, chemical_formula_reduced: str, providers: List[str] = None) -> List[str]: @@ -425,13 +424,13 @@ async def _get_urls_optimade(chemical_formula_hill: str, chemical_formula_reduce return urls -async def _get_references_optimade(session: httpx.AsyncClient, path: str) -> List[Reference]: +async def _get_resources_optimade(session: httpx.AsyncClient, path: str) -> List[Resource]: response = await _download(session, path) if response is None: - logger.error(f'Error accessing optimade references.') + logger.error(f'Error accessing optimade resources.') return [] data = response.json() - references: List[Reference] = [] + resources: List[Resource] = [] meta = data.get('meta', dict()) provider = meta.get('provider', dict()).get('name', '') base_url = path.split('structures?filter')[0] @@ -441,44 +440,45 @@ async def _get_references_optimade(session: httpx.AsyncClient, path: str) -> Lis params = dict( entry_id=entry.get('id'), chemical_formula_reduced=data.get('chemical_formula_reduced', ''), oqmd_id=entry.get('attributes', {}).get('_oqmd_entry_id'), entry=entry) - reference = Reference() + resource = Resource() # resolve provider-specific path to entry in respective database - reference.url = ref_url(params) # type: ignore - reference.database_name = provider - reference.id = f'{entry_id}' - attributes = entry.get('attributes', dict()) + resource.url = ref_url(params) # type: ignore + resource.database_name = provider + resource.id = f'{entry_id}' + attributes = entry.pop('attributes', dict()) chemical_formula = attributes.get('chemical_formula_hill') if chemical_formula is None: chemical_formula = attributes.get('chemical_formula_reduced', '') - reference.chemical_formula = _normalize_formula(chemical_formula) - reference.download_time = datetime.now() - reference.database_version = meta.get('api_version') + resource.chemical_formula = _normalize_formula(chemical_formula) + resource.download_time = datetime.now() + resource.database_version = meta.get('api_version') # flatten entry data entry.update({key: val for key, val in attributes.items()}) - reference.data = entry + # resource.data = entry + resource.available_data = list(entry.keys()) # push to mongo database - reference.save() - references.append(reference) - return references + resource.save() + resources.append(resource) + return resources @router.get( '/', tags=[default_tag], - summary='Get a list of external references.', - response_model=ReferencesResponseModel, + summary='Get a list of external resources.', + response_model=List[ResourceModel], response_model_exclude_unset=True, response_model_exclude_none=True) -async def get_references( +async def get_resources( space_group_number: int = FastApiQuery(None), wyckoff_letters: List[str] = FastApiQuery(None), n_sites: int = FastApiQuery(None), chemical_formula_reduced: str = FastApiQuery(None)): ''' - Get all external references that match a specific query + Get all external resources that match a specific query ''' - data: List[Any] = [] - metadata: Dict[str, Any] = dict(sources=[]) + data: List[ResourceModel] = [] + # metadata: Dict[str, Any] = dict(sources=[]) sources: Dict[str, int] = dict() chemical_formula_hill, chemical_formula = None, None @@ -511,32 +511,32 @@ async def get_references( Reference to the entry in the {db} database queried using the Optimade API. ''' for db in optimade_dbs}) - def convert_to_model(references, filter=False): + def convert_to_model(resources, filter=False): additional_data = [] - for reference in references: - if reference is None or reference.url is None or reference.id is None or reference.id.startswith(no_url_found): + for resource in resources: + if resource is None or resource.url is None or resource.id is None or resource.id.startswith(no_url_found): continue - database = reference.database_name + database = resource.database_name if filter: - # filter reference if matches query for results of external database query + # filter resource if matches query for results of external database query # we do not want to redo mongo query - if not equal(reference.chemical_formula, chemical_formula): + if not equal(resource.chemical_formula, chemical_formula): continue if database == aflow_prototypes_db or database == springer_materials_db: - if not equal(reference.space_group_number, space_group_number): + if not equal(resource.space_group_number, space_group_number): continue if database == aflow_prototypes_db: - if not equal(reference.wyckoff_letters, wyckoff_letters): + if not equal(resource.wyckoff_letters, wyckoff_letters): continue - if not equal(reference.n_sites, n_sites): + if not equal(resource.n_sites, n_sites): continue sources.setdefault(database, 0) sources[database] += 1 # show the first five results from each resource and the rest we append later - model = ReferenceModel( - url=reference.url, id=reference.id, data=reference.data, - database_name=reference.database_name, download_time=reference.download_time, - database_version=reference.database_version, comment=comments.get(database)) + model = ResourceModel( + url=resource.url, id=resource.id, available_data=resource.available_data, + database_name=resource.database_name, download_time=resource.download_time, + database_version=resource.database_version, comment=comments.get(database)) if sources[database] <= 5: data.append(model) else: @@ -544,14 +544,14 @@ async def get_references( data.extend(additional_data) - def set_empty_reference(database_name: str, **kwargs) -> None: - reference = Reference() - reference.id = f'{no_url_found}_{database_name}_{json.dumps(kwargs, sort_keys=True)}' - reference.database_name = database_name + def set_empty_resource(database_name: str, **kwargs) -> None: + resource = Resource() + resource.id = f'{no_url_found}_{database_name}_{json.dumps(kwargs, sort_keys=True)}' + resource.database_name = database_name for key, val in kwargs.items(): - setattr(reference, key, val) - reference.download_time = datetime.now() - reference.save() + setattr(resource, key, val) + resource.download_time = datetime.now() + resource.save() query_aflow = Q( chemical_formula=chemical_formula, space_group_number=space_group_number, wyckoff_letters=wyckoff_letters, @@ -560,20 +560,20 @@ async def get_references( chemical_formula=chemical_formula, space_group_number=space_group_number, database_name=springer_materials_db) query_optimade = Q(chemical_formula=chemical_formula, database_name__in=optimade_dbs) - query_results = Reference.objects(query_aflow | query_springer | query_optimade) + query_results = Resource.objects(query_aflow | query_springer | query_optimade) # we cannot set entries in query_results to None valid_queries_index = [] space_group_number_query = space_group_number chemical_formula_query = chemical_formula optimade_dbs_query = list(optimade_dbs) - for n, reference in enumerate(query_results): - # filter reference if recent - delta_time_db = datetime.now() - reference.download_time - if delta_time_db.total_seconds() > config.related_resources.max_time_external_db: + for n, resource in enumerate(query_results): + # filter resource if recent + delta_time_db = datetime.now() - resource.download_time + if delta_time_db.total_seconds() > config.resources.max_time_in_mongo: continue # set query parameters to None to turn off external db query - database = reference.database_name + database = resource.database_name if database == aflow_prototypes_db: space_group_number_query = None elif database == springer_materials_db: @@ -584,8 +584,8 @@ async def get_references( convert_to_model([query_results[n] for n in valid_queries_index], filter=False) # TODO is this necessary - done_urls = [reference.url for reference in data] - limits = httpx.Limits(max_connections=config.related_resources.max_connections) + done_urls = [resource.url for resource in data] + limits = httpx.Limits(max_connections=config.resources.max_connections) async with httpx.AsyncClient(limits=limits) as session: # get urls from sources aflow_task = asyncio.create_task(_get_urls_aflow_prototypes(session, space_group_number_query)) @@ -595,38 +595,35 @@ async def get_references( springer_urls: List[str] optimade_urls: List[str] aflow_urls, springer_urls, optimade_urls = await asyncio.gather(aflow_task, springer_task, optimade_task) - # get reference(s) corresponding to each url + # get resource(s) corresponding to each url tasks = [] tasks.extend([asyncio.create_task( - _get_reference_aflow_prototypes(session, url, chemical_formula)) for url in aflow_urls if url not in done_urls]) + _get_resources_aflow_prototypes(session, url, chemical_formula)) for url in aflow_urls if url not in done_urls]) tasks.extend([asyncio.create_task( - _get_reference_springer_materials(session, url)) for url in springer_urls if url not in done_urls]) + _get_resources_springer_materials(session, url)) for url in springer_urls if url not in done_urls]) tasks.extend([asyncio.create_task( - _get_references_optimade(session, url)) for url in optimade_urls if url not in done_urls]) - references = await asyncio.gather(*tasks) + _get_resources_optimade(session, url)) for url in optimade_urls if url not in done_urls]) + resources = await asyncio.gather(*tasks) # flatten list - references = [ref for reference in references for ref in reference] + resources = [res for resource in resources for res in resource] - # filter references to match query and convert to model - convert_to_model(references, filter=True) + # filter resources to match query and convert to model + convert_to_model(resources, filter=True) - # if no references are found, record this in mongodb so as not do perform query again + # if no resources are found, record this in mongodb so as not do perform query again queried_databases = [query_results[n].database_name for n in valid_queries_index] - queried_databases.extend([ref.database_name for ref in references]) + queried_databases.extend([res.database_name for res in resources]) queried_databases = list(set(queried_databases)) if aflow_prototypes_db not in queried_databases: - set_empty_reference( + set_empty_resource( aflow_prototypes_db, chemical_formula=chemical_formula, space_group_number=space_group_number, wyckoff_letters=wyckoff_letters, n_sites=n_sites) if springer_materials_db not in queried_databases: - set_empty_reference( + set_empty_resource( springer_materials_db, chemical_formula=chemical_formula, space_group_number=space_group_number) for optimade_db in optimade_dbs: if optimade_db not in queried_databases: - set_empty_reference(optimade_db, chemical_formula=chemical_formula) - - metadata['sources'] = list(sources.keys()) - metadata['n_references'] = list(sources.values()) + set_empty_resource(optimade_db, chemical_formula=chemical_formula) - return dict(data=data, metadata=metadata) + return data diff --git a/nomad/app/v1/main.py b/nomad/app/v1/main.py index 469468ca5..b8695e2a4 100644 --- a/nomad/app/v1/main.py +++ b/nomad/app/v1/main.py @@ -26,7 +26,7 @@ import orjson from nomad import config, utils from .common import root_path -from .routers import users, entries, materials, auth, info, datasets, uploads, suggestions, metainfo, related_resources +from .routers import users, entries, materials, auth, info, datasets, uploads, suggestions, metainfo logger = utils.get_logger(__name__) @@ -93,4 +93,3 @@ app.include_router(uploads.router, prefix='/uploads') app.include_router(metainfo.router, prefix='/metainfo') app.include_router(users.router, prefix='/users') app.include_router(suggestions.router, prefix='/suggestions') -app.include_router(related_resources.router, prefix='/related_resources') diff --git a/nomad/config.py b/nomad/config.py index c76d31eb8..06c299b27 100644 --- a/nomad/config.py +++ b/nomad/config.py @@ -323,9 +323,10 @@ normalize = NomadConfig( ) ) -related_resources = NomadConfig( - # Maxmimum time a reference is stored in mongodb before being updated. - max_time_external_db=60 * 60 * 24 * 365., +resources = NomadConfig( + db_name='resources', + # Maxmimum time a resource is stored in mongodb before being updated. + max_time_in_mongo=60 * 60 * 24 * 365., # Number of download retries download_retries=2, # Delay in seconds before each successive retry diff --git a/tests/app/test_resources.py b/tests/app/test_resources.py new file mode 100644 index 000000000..c8c45fcdf --- /dev/null +++ b/tests/app/test_resources.py @@ -0,0 +1,94 @@ +# +# 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 pytest +import json +from fastapi.testclient import TestClient +import httpx +from urllib.parse import urlencode + +from nomad.app.resources.main import app, remove_mongo +from nomad.app.resources.routers.resources import aflow_prototypes_db, springer_materials_db, optimade_providers + + +@pytest.fixture(scope='session') +def api(): + return TestClient(app, base_url='http://testserver/') + + +@pytest.fixture +def mocked_httpx_responses(respx_mock): + path = 'tests/data/api/responses.json' + with open(path) as f: + responses = json.load(f) + for url, response in responses.items(): + if response is None: + responses[url] = dict(status_code=404) + continue + respx_mock.get(url).mock(return_value=httpx.Response( + text=response.get('text'), json=response.get('json'), status_code=response.get('status_code'))) + + +@pytest.fixture(scope='session') +def mongo_infra_resources(monkeysession): + monkeysession.setattr('nomad.config.resources.db_name', 'test_db_resources') + + +def test_get_resources(api, mocked_httpx_responses, mongo, mongo_infra_resources, monkeysession): + params = dict(chemical_formula_reduced='AcAg', wyckoff_sites=['a', 'b'], space_group_number=225, n_sites=2) + + response = api.get(f'/?{urlencode(params, doseq=True)}') + + data = response.json() + assert len(data) == 7 + + aflow_data = [d for d in data if d['database_name'] == aflow_prototypes_db] + assert len(aflow_data) == 1 + assert 'Space group symbol' in aflow_data[0]['available_data'] + assert aflow_data[0]['id'] == 'AB_cF8_225_a_b' + + springer_data = [d for d in data if d['database_name'] == springer_materials_db] + assert len(springer_data) == 0 + + optimade_dbs = [provider['name'] for provider in optimade_providers.values()] + optimade_data = [d for d in data if d['database_name'] in optimade_dbs] + assert len(optimade_data) == 6 + assert optimade_data[0]['database_version'] == '1.0.1' + assert optimade_data[1]['url'] == 'https://oqmd.org/materials/entry/675163' + assert optimade_data[2]['id'] == '4815195' + + # test if mongo db works + params = dict(chemical_formula_reduced='Mg', wyckoff_sites=['a'], space_group_number=229, n_sites=1) + # do initial request + response = api.get(f'/?{urlencode(params, doseq=True)}') + data = response.json() + assert len(data) == 88 + # repeat request + response = api.get(f'/?{urlencode(params, doseq=True)}') + data_repeat = response.json() + assert len(data) == len(data_repeat) + # check if download_time is the same + assert data[0]['download_time'] == data_repeat[0]['download_time'] + # mimic mongo update by setting max_time_in_mongo to 0 + monkeysession.setattr('nomad.config.resources.max_time_in_mongo', 0.) + # repeat request, expect that resources are downloaded again + response = api.get(f'/?{urlencode(params, doseq=True)}') + data_repeat = response.json() + assert data[0]['download_time'] < data[1]['download_time'] + + # clean up + remove_mongo() diff --git a/tests/app/v1/routers/test_related_resources.py b/tests/app/v1/routers/test_related_resources.py deleted file mode 100644 index 0a3fcc787..000000000 --- a/tests/app/v1/routers/test_related_resources.py +++ /dev/null @@ -1,46 +0,0 @@ -# -# 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 pytest -from urllib.parse import urlencode - -''' -These are the tests for all API operations below ``references``. The tests are organized -using the following type of methods: fixtures, ``perfrom_*_test``, ``assert_*``, and -``test_*``. While some ``test_*`` methods test individual API operations, some -test methods will test multiple API operations that use common aspects like -supporting queries, pagination, or the owner parameter. The test methods will use -``perform_*_test`` methods as an parameter. Similarely, the ``assert_*`` methods allow -to assert for certain aspects in the responses. -''' - - -@pytest.mark.skip(reason='can take very long and depends on live external services') -def test_related_resources(client, example_data): - query = { - 'space_group_number': 1, - 'wyckoff_letters': ['a'], - 'n_atoms_primitive': 26, - 'chemical_formula': 'AlBFeNi', - 'chemical_formula_hill': 'AlBFeNi', - 'chemical_formula_reduced': 'AlBFeNi', - } - - response = client.get(f'related_resources?{urlencode(query, doseq=True)}') - assert response.status_code == 200 - data = response.json() - assert len(data['data']) > 0 diff --git a/tests/data/api/responses.json b/tests/data/api/responses.json new file mode 100644 index 000000000..bc9d799ad --- /dev/null +++ b/tests/data/api/responses.json @@ -0,0 +1,9830 @@ +{ + "http://materials.springer.com/search?searchTerm=es:Mg&pageNumber=1&datasourceFacet=sm_isp&substanceId=": { + "status_code": 200, + "json": null, + "text": "\n\n\n\n \n\n \n \n \n \n \n \n Search Results - SpringerMaterials\n \n \n \n \n \n \n \n \n \n\n\n \n
\n
\n \n \n
\n \n
\n
\n
\n\n
\n
\n
\n \n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n Filtered by:\n \n
\n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
\n
\n

Properties

\n
\n
\n
\n
\n \n
\n
\n
    \n \n
  1. \n \n \n \n \"\"/\n
  2. \n
  3. \n \n \n \n \"\"/\n
  4. \n
  5. \n \n \n \n \"\"/\n
  6. \n
  7. \n \n \n \n \"\"/\n
  8. \n
  9. \n \n \n \n \"\"/\n
  10. \n
  11. \n \n \n \n \"\"/\n
  12. \n
  13. \n \n \n \n \"\"/\n
  14. \n
  15. \n \n \n \n \"\"/\n
  16. \n
  17. \n \n \n \n \"\"/\n
  18. \n
  19. \n \n \n \n \"\"/\n
  20. \n
  21. \n \n \n \n \"\"/\n
  22. \n
  23. \n \n \n \n \"\"/\n
  24. \n
  25. \n \n \n \n \"\"/\n
  26. \n
  27. \n \n \n \n \"\"/\n
  28. \n
  29. \n \n \n \n \"\"/\n
  30. \n
  31. \n \n \n \n \"\"/\n
  32. \n
  33. \n \n \n \n \"\"/\n
  34. \n
  35. \n \n \n \n \"\"/\n
  36. \n
  37. \n \n \n \n \"\"/\n
  38. \n
  39. \n \n \n \n \"\"/\n
  40. \n
  41. \n \n \n \n \"\"/\n
  42. \n
  43. \n \n \n \n \"\"/\n
  44. \n
  45. \n \n \n \n \"\"/\n
  46. \n
  47. \n \n \n \n \"\"/\n
  48. \n
  49. \n \n \n \n \"\"/\n
  50. \n
  51. \n \n \n \n \"\"/\n
  52. \n
  53. \n \n \n \n \"\"/\n
  54. \n
  55. \n \n \n \n \"\"/\n
  56. \n
  57. \n \n \n \n \"\"/\n
  58. \n
  59. \n \n \n \n \"\"/\n
  60. \n
  61. \n \n \n \n \"\"/\n
  62. \n
  63. \n \n \n \n \"\"/\n
  64. \n
  65. \n \n \n \n \"\"/\n
  66. \n
  67. \n \n \n \n \"\"/\n
  68. \n
  69. \n \n \n \n \"\"/\n
  70. \n
  71. \n \n \n \n \"\"/\n
  72. \n
  73. \n \n \n \n \"\"/\n
  74. \n
  75. \n \n \n \n \"\"/\n
  76. \n
  77. \n \n \n \n \"\"/\n
  78. \n
  79. \n \n \n \n \"\"/\n
  80. \n
  81. \n \n \n \n \"\"/\n
  82. \n\n
\n
\n
\n
\n
\n

Data collections

\n
\n
\n
    \n
  1. \n \n \n 220\n \"\"/\n
  2. \n\n
  3. \n \n \n 218\n \"\"/\n
  4. \n
  5. \n \n \n 225\n \"\"/\n
  6. \n
  7. \n \n \n 1\n \"\"/\n
  8. \n
  9. \n \n \n 59\n \"\"/\n
  10. \n\n
\n
\n
\n
\n
\n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n
\n Filtered by:\n \n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
    \n
  1. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg reflectivity\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 6; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  2. \n\n
  3. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg hyp elastic moduli\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Cu; Pearson symbol: cF4; Space group: 225; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  4. \n\n
  5. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg hyp Debye/Einstein temperature\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Cu; Pearson symbol: cF4; Space group: 225; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  6. \n\n
  7. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg superconducting transition temperature\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 2; Samples: 2; Journal references: 2\n
    • \n
    \n
    \n
    \n
  8. \n\n
  9. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg plasma edge\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 2; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  10. \n\n
  11. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg entropy\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  12. \n\n
  13. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg heat capacity (specific heat)\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 3; Samples: 2; Journal references: 2\n
    • \n
    \n
    \n
    \n
  14. \n\n
  15. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg residual resistivity\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  16. \n\n
  17. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg magnetic susceptibility\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  18. \n\n
  19. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg hyp electron-phonon interaction parameter\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Cu; Pearson symbol: cF4; Space group: 225; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  20. \n\n
  21. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg charge carrier concentration\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  22. \n\n
  23. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg elastic moduli\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 13; Samples: 6; Journal references: 6\n
    • \n
    \n
    \n
    \n
  24. \n\n
  25. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg thermal expansion\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 5; Samples: 2; Journal references: 2\n
    • \n
    \n
    \n
    \n
  26. \n\n
  27. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg compressibility\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  28. \n\n
  29. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg hp compressibility\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: W; Pearson symbol: cI2; Space group: 229; Data points: 3; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  30. \n\n
  31. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg heat capacity coefficients\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  32. \n\n
  33. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg hp structural transitions\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: W; Pearson symbol: cI2; Space group: 229; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  34. \n\n
  35. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg work function\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 8; Samples: 6; Journal references: 6\n
    • \n
    \n
    \n
    \n
  36. \n\n
  37. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg enthalpy change at phase transition\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  38. \n\n
  39. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg hyp electron density of states\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Cu; Pearson symbol: cF4; Space group: 225; Data points: 2; Samples: 2; Journal references: 2\n
    • \n
    \n
    \n
    \n
  40. \n\n
\n
\n
\n \n \n Page\n \n \n \n \n \n \n \n is not a valid page number. Please enter a number between\n \n 1\n \n and\n \n 11\n \n \n \n of\n \n 11\n \n \n \n \n \n \n \n \n
\n\n
\n
\n
\n\n \n
\n
\n \n\n \n \n \n \n \n
\n

\n While using an institutional account for this website we don\u2019t track any personal, performance, functional or 1st or 3rd party related information. We only use essential cookies necessary for it to function correctly. Please read our\n privacy policy\n and\n California Privacy Statement\n for more information.\n

\n Okay\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" + }, + "http://aflowlib.org/prototype-encyclopedia/cubic_spacegroup.html": { + "status_code": 200, + "json": null, + "text": " Space Group Classes

Encyclopedia of Crystallographic Prototypes

Cubic Space Groups (#195-#230)

  • M. J. Mehl, D. Hicks, C. Toher, O. Levy, R. M. Hanson, G. L. W. Hart, and S. Curtarolo, The AFLOW Library of Crystallographic Prototypes: Part 1, Comp. Mat. Sci. 136, S1-S828 (2017). (doi=10.1016/j.commatsci.2017.01.017)
  • D. Hicks, M. J. Mehl, E. Gossett, C. Toher, O. Levy, R. M. Hanson, G. L. W. Hart, and S. Curtarolo, The AFLOW Library of Crystallographic Prototypes: Part 2, Comp. Mat. Sci. 161, S1-S1011 (2019). (doi=10.1016/j.commatsci.2018.10.043)
  • D. Hicks, M.J. Mehl, M. Esters, C. Oses, O. Levy, G.L.W. Hart, C. Toher, and S. Curtarolo, The AFLOW Library of Crystallographic Prototypes: Part 3, Comp. Mat. Sci. 199, 110450 (2021). (doi=10.1016/j.commatsci.2021.110450)

$P23$ (#195)

$F23$ (#196)

$I23$ (#197)

$P2_{1}3$ (#198)

$I2_{1}3$ (#199)

$Pm\\bar{3}$ (#200)

$Pn\\bar{3}$ (#201)

$Fm\\bar{3}$ (#202)

$Fd\\bar{3}$ (#203)

$Im\\bar{3}$ (#204)

$Pa\\bar{3}$ (#205)

$Ia\\bar{3}$ (#206)

$P432$ (#207)

$P4_{2}32$ (#208)

$F432$ (#209)

$F4_{1}32$ (#210)

$I432$ (#211)

$P4_{3}32$ (#212)

$P4_{1}32$ (#213)

$I4_{1}32$ (#214)

$P\\bar{4}3m$ (#215)

$F\\bar{4}3m$ (#216)

$I\\bar{4}3m$ (#217)

$P\\bar{4}3n$ (#218)

$F\\bar{4}3c$ (#219)

$I\\bar{4}3d$ (#220)

$Pm\\bar{3}m$ (#221)

$Pn\\bar{3}n$ (#222)

$Pm\\bar{3}n$ (#223)

$Pn\\bar{3}m$ (#224)

$Fm\\bar{3}m$ (#225)

$Fm\\bar{3}c$ (#226)

$Fd\\bar{3}m$ (#227)

$Fd\\bar{3}c$ (#228)

$Im\\bar{3}m$ (#229)

$Ia\\bar{3}d$ (#230)

" + }, + "http://materials.springer.com/search?searchTerm=es:Mg&pageNumber=2&datasourceFacet=sm_isp&substanceId=": { + "status_code": 200, + "json": null, + "text": "\n\n\n\n \n\n \n \n \n \n \n \n Search Results - SpringerMaterials\n \n \n \n \n \n \n \n \n \n\n\n \n
\n
\n
\n \n \"SpringerMaterials\"\n \n
\n \n
\n \n
\n
\n
\n\n
\n
\n
\n \n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n Filtered by:\n \n
\n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
\n
\n

Properties

\n
\n
\n
\n
\n \n
\n
\n
    \n \n
  1. \n \n \n \n \"\"/\n
  2. \n
  3. \n \n \n \n \"\"/\n
  4. \n
  5. \n \n \n \n \"\"/\n
  6. \n
  7. \n \n \n \n \"\"/\n
  8. \n
  9. \n \n \n \n \"\"/\n
  10. \n
  11. \n \n \n \n \"\"/\n
  12. \n
  13. \n \n \n \n \"\"/\n
  14. \n
  15. \n \n \n \n \"\"/\n
  16. \n
  17. \n \n \n \n \"\"/\n
  18. \n
  19. \n \n \n \n \"\"/\n
  20. \n
  21. \n \n \n \n \"\"/\n
  22. \n
  23. \n \n \n \n \"\"/\n
  24. \n
  25. \n \n \n \n \"\"/\n
  26. \n
  27. \n \n \n \n \"\"/\n
  28. \n
  29. \n \n \n \n \"\"/\n
  30. \n
  31. \n \n \n \n \"\"/\n
  32. \n
  33. \n \n \n \n \"\"/\n
  34. \n
  35. \n \n \n \n \"\"/\n
  36. \n
  37. \n \n \n \n \"\"/\n
  38. \n
  39. \n \n \n \n \"\"/\n
  40. \n
  41. \n \n \n \n \"\"/\n
  42. \n
  43. \n \n \n \n \"\"/\n
  44. \n
  45. \n \n \n \n \"\"/\n
  46. \n
  47. \n \n \n \n \"\"/\n
  48. \n
  49. \n \n \n \n \"\"/\n
  50. \n
  51. \n \n \n \n \"\"/\n
  52. \n
  53. \n \n \n \n \"\"/\n
  54. \n
  55. \n \n \n \n \"\"/\n
  56. \n
  57. \n \n \n \n \"\"/\n
  58. \n
  59. \n \n \n \n \"\"/\n
  60. \n
  61. \n \n \n \n \"\"/\n
  62. \n
  63. \n \n \n \n \"\"/\n
  64. \n
  65. \n \n \n \n \"\"/\n
  66. \n
  67. \n \n \n \n \"\"/\n
  68. \n
  69. \n \n \n \n \"\"/\n
  70. \n
  71. \n \n \n \n \"\"/\n
  72. \n
  73. \n \n \n \n \"\"/\n
  74. \n
  75. \n \n \n \n \"\"/\n
  76. \n
  77. \n \n \n \n \"\"/\n
  78. \n
  79. \n \n \n \n \"\"/\n
  80. \n
  81. \n \n \n \n \"\"/\n
  82. \n\n
\n
\n
\n
\n
\n

Data collections

\n
\n
\n
    \n
  1. \n \n \n 220\n \"\"/\n
  2. \n\n
  3. \n \n \n 218\n \"\"/\n
  4. \n
  5. \n \n \n 225\n \"\"/\n
  6. \n
  7. \n \n \n 1\n \"\"/\n
  8. \n
  9. \n \n \n 59\n \"\"/\n
  10. \n\n
\n
\n
\n
\n
\n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n
\n Filtered by:\n \n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
    \n
  1. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg activation energy\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  2. \n\n
  3. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg valence/charge transfer\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  4. \n\n
  5. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg structural transitions\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  6. \n\n
  7. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Debye/Einstein temperature\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 7; Samples: 4; Journal references: 4\n
    • \n
    \n
    \n
    \n
  8. \n\n
  9. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg hyp superconducting transition temperature\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Cu; Pearson symbol: cF4; Space group: 225; Data points: 1; Samples: 1; Journal references: 1\n
    • \n
    \n
    \n
    \n
  10. \n\n
  11. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg conductivity/resistivity\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 22; Samples: 2; Journal references: 2\n
    • \n
    \n
    \n
    \n
  12. \n\n
  13. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg elasticity\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 50; Samples: 7; Journal references: 7\n
    • \n
    \n
    \n
    \n
  14. \n\n
  15. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg fusion\n \n

    \n
    \n
      \n
    • \n Element system: Mg; Phase prototype: Mg; Pearson symbol: hP2; Space group: 194; Data points: 3; Samples: 3; Journal references: 3\n
    • \n
    \n
    \n
    \n
  16. \n\n
  17. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 90-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 450\u2026650 \u00b0C (723\u2026923 K); Partial composition: 90-100 at.% Mg; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  18. \n\n
  19. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 72-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026700 \u00b0C (273\u2026973 K); Partial composition: 0-10 wt.% Li; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  20. \n\n
  21. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  22. \n\n
  23. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  24. \n\n
  25. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  26. \n\n
  27. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  28. \n\n
  29. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  30. \n\n
  31. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  32. \n\n
  33. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  34. \n\n
  35. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  36. \n\n
  37. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  38. \n\n
  39. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  40. \n\n
\n
\n
\n \n \n Page\n \n \n \n \n \n \n \n is not a valid page number. Please enter a number between\n \n 1\n \n and\n \n 11\n \n \n \n of\n \n 11\n \n \n \n \n \n \n \n \n
\n\n
\n
\n
\n\n \n
\n
\n \n\n \n \n \n \n \n
\n

\n While using an institutional account for this website we don\u2019t track any personal, performance, functional or 1st or 3rd party related information. We only use essential cookies necessary for it to function correctly. Please read our\n privacy policy\n and\n California Privacy Statement\n for more information.\n

\n Okay\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" + }, + "http://materials.springer.com/search?searchTerm=es:Mg&pageNumber=3&datasourceFacet=sm_isp&substanceId=": { + "status_code": 200, + "json": null, + "text": "\n\n\n\n \n\n \n \n \n \n \n \n Search Results - SpringerMaterials\n \n \n \n \n \n \n \n \n \n\n\n \n
\n
\n
\n \n \"SpringerMaterials\"\n \n
\n \n
\n \n
\n
\n
\n\n
\n
\n
\n \n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n Filtered by:\n \n
\n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
\n
\n

Properties

\n
\n
\n
\n
\n \n
\n
\n
    \n \n
  1. \n \n \n \n \"\"/\n
  2. \n
  3. \n \n \n \n \"\"/\n
  4. \n
  5. \n \n \n \n \"\"/\n
  6. \n
  7. \n \n \n \n \"\"/\n
  8. \n
  9. \n \n \n \n \"\"/\n
  10. \n
  11. \n \n \n \n \"\"/\n
  12. \n
  13. \n \n \n \n \"\"/\n
  14. \n
  15. \n \n \n \n \"\"/\n
  16. \n
  17. \n \n \n \n \"\"/\n
  18. \n
  19. \n \n \n \n \"\"/\n
  20. \n
  21. \n \n \n \n \"\"/\n
  22. \n
  23. \n \n \n \n \"\"/\n
  24. \n
  25. \n \n \n \n \"\"/\n
  26. \n
  27. \n \n \n \n \"\"/\n
  28. \n
  29. \n \n \n \n \"\"/\n
  30. \n
  31. \n \n \n \n \"\"/\n
  32. \n
  33. \n \n \n \n \"\"/\n
  34. \n
  35. \n \n \n \n \"\"/\n
  36. \n
  37. \n \n \n \n \"\"/\n
  38. \n
  39. \n \n \n \n \"\"/\n
  40. \n
  41. \n \n \n \n \"\"/\n
  42. \n
  43. \n \n \n \n \"\"/\n
  44. \n
  45. \n \n \n \n \"\"/\n
  46. \n
  47. \n \n \n \n \"\"/\n
  48. \n
  49. \n \n \n \n \"\"/\n
  50. \n
  51. \n \n \n \n \"\"/\n
  52. \n
  53. \n \n \n \n \"\"/\n
  54. \n
  55. \n \n \n \n \"\"/\n
  56. \n
  57. \n \n \n \n \"\"/\n
  58. \n
  59. \n \n \n \n \"\"/\n
  60. \n
  61. \n \n \n \n \"\"/\n
  62. \n
  63. \n \n \n \n \"\"/\n
  64. \n
  65. \n \n \n \n \"\"/\n
  66. \n
  67. \n \n \n \n \"\"/\n
  68. \n
  69. \n \n \n \n \"\"/\n
  70. \n
  71. \n \n \n \n \"\"/\n
  72. \n
  73. \n \n \n \n \"\"/\n
  74. \n
  75. \n \n \n \n \"\"/\n
  76. \n
  77. \n \n \n \n \"\"/\n
  78. \n
  79. \n \n \n \n \"\"/\n
  80. \n
  81. \n \n \n \n \"\"/\n
  82. \n\n
\n
\n
\n
\n
\n

Data collections

\n
\n
\n
    \n
  1. \n \n \n 220\n \"\"/\n
  2. \n\n
  3. \n \n \n 218\n \"\"/\n
  4. \n
  5. \n \n \n 225\n \"\"/\n
  6. \n
  7. \n \n \n 1\n \"\"/\n
  8. \n
  9. \n \n \n 59\n \"\"/\n
  10. \n\n
\n
\n
\n
\n
\n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n
\n Filtered by:\n \n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
    \n
  1. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  2. \n\n
  3. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  4. \n\n
  5. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  6. \n\n
  7. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg (T = 100.0(2) K) Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Single crystal; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  8. \n\n
  9. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  10. \n\n
  11. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  12. \n\n
  13. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  14. \n\n
  15. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  16. \n\n
  17. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  18. \n\n
  19. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  20. \n\n
  21. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  22. \n\n
  23. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  24. \n\n
  25. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  26. \n\n
  27. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  28. \n\n
  29. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  30. \n\n
  31. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  32. \n\n
  33. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  34. \n\n
  35. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  36. \n\n
  37. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  38. \n\n
  39. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  40. \n\n
\n
\n
\n \n \n Page\n \n \n \n \n \n \n \n is not a valid page number. Please enter a number between\n \n 1\n \n and\n \n 11\n \n \n \n of\n \n 11\n \n \n \n \n \n \n \n \n
\n\n
\n
\n
\n\n \n
\n
\n \n\n \n \n \n \n \n
\n

\n While using an institutional account for this website we don\u2019t track any personal, performance, functional or 1st or 3rd party related information. We only use essential cookies necessary for it to function correctly. Please read our\n privacy policy\n and\n California Privacy Statement\n for more information.\n

\n Okay\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" + }, + "http://materials.springer.com/search?searchTerm=es:Mg&pageNumber=4&datasourceFacet=sm_isp&substanceId=": { + "status_code": 200, + "json": null, + "text": "\n\n\n\n \n\n \n \n \n \n \n \n Search Results - SpringerMaterials\n \n \n \n \n \n \n \n \n \n\n\n \n
\n
\n
\n \n \"SpringerMaterials\"\n \n
\n \n
\n \n
\n
\n
\n\n
\n
\n
\n \n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n Filtered by:\n \n
\n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
\n
\n

Properties

\n
\n
\n
\n
\n \n
\n
\n
    \n \n
  1. \n \n \n \n \"\"/\n
  2. \n
  3. \n \n \n \n \"\"/\n
  4. \n
  5. \n \n \n \n \"\"/\n
  6. \n
  7. \n \n \n \n \"\"/\n
  8. \n
  9. \n \n \n \n \"\"/\n
  10. \n
  11. \n \n \n \n \"\"/\n
  12. \n
  13. \n \n \n \n \"\"/\n
  14. \n
  15. \n \n \n \n \"\"/\n
  16. \n
  17. \n \n \n \n \"\"/\n
  18. \n
  19. \n \n \n \n \"\"/\n
  20. \n
  21. \n \n \n \n \"\"/\n
  22. \n
  23. \n \n \n \n \"\"/\n
  24. \n
  25. \n \n \n \n \"\"/\n
  26. \n
  27. \n \n \n \n \"\"/\n
  28. \n
  29. \n \n \n \n \"\"/\n
  30. \n
  31. \n \n \n \n \"\"/\n
  32. \n
  33. \n \n \n \n \"\"/\n
  34. \n
  35. \n \n \n \n \"\"/\n
  36. \n
  37. \n \n \n \n \"\"/\n
  38. \n
  39. \n \n \n \n \"\"/\n
  40. \n
  41. \n \n \n \n \"\"/\n
  42. \n
  43. \n \n \n \n \"\"/\n
  44. \n
  45. \n \n \n \n \"\"/\n
  46. \n
  47. \n \n \n \n \"\"/\n
  48. \n
  49. \n \n \n \n \"\"/\n
  50. \n
  51. \n \n \n \n \"\"/\n
  52. \n
  53. \n \n \n \n \"\"/\n
  54. \n
  55. \n \n \n \n \"\"/\n
  56. \n
  57. \n \n \n \n \"\"/\n
  58. \n
  59. \n \n \n \n \"\"/\n
  60. \n
  61. \n \n \n \n \"\"/\n
  62. \n
  63. \n \n \n \n \"\"/\n
  64. \n
  65. \n \n \n \n \"\"/\n
  66. \n
  67. \n \n \n \n \"\"/\n
  68. \n
  69. \n \n \n \n \"\"/\n
  70. \n
  71. \n \n \n \n \"\"/\n
  72. \n
  73. \n \n \n \n \"\"/\n
  74. \n
  75. \n \n \n \n \"\"/\n
  76. \n
  77. \n \n \n \n \"\"/\n
  78. \n
  79. \n \n \n \n \"\"/\n
  80. \n
  81. \n \n \n \n \"\"/\n
  82. \n\n
\n
\n
\n
\n
\n

Data collections

\n
\n
\n
    \n
  1. \n \n \n 220\n \"\"/\n
  2. \n\n
  3. \n \n \n 218\n \"\"/\n
  4. \n
  5. \n \n \n 225\n \"\"/\n
  6. \n
  7. \n \n \n 1\n \"\"/\n
  8. \n
  9. \n \n \n 59\n \"\"/\n
  10. \n\n
\n
\n
\n
\n
\n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n
\n Filtered by:\n \n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
    \n
  1. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  2. \n\n
  3. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates\n
    • \n
    \n
    \n
    \n
  4. \n\n
  5. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg (p = 58 GPa) Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype W, Space group cI2, 229, Powder; Data on Cell parameters, Published and standardized atom coordinates, Powder pattern\n
    • \n
    \n
    \n
    \n
  6. \n\n
  7. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates, Isotropic displacement parameters\n
    • \n
    \n
    \n
    \n
  8. \n\n
  9. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194, Powder; Data on Cell parameters, Published and standardized atom coordinates, Isotropic displacement parameters\n
    • \n
    \n
    \n
    \n
  10. \n\n
  11. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype Mg, Space group hP2, 194; Data on Cell parameters, Published and standardized atom coordinates, Powder pattern\n
    • \n
    \n
    \n
    \n
  12. \n\n
  13. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n HP-Mg (Mg hp) Crystal Structure\n \n

    \n
    \n
      \n
    • \n Element system Mg, Phase prototype W, Space group cI2, 229, Powder; Data on Cell parameters, Published and standardized atom coordinates, Isotropic displacement parameters\n
    • \n
    \n
    \n
    \n
  14. \n\n
  15. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 84-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026550 \u00b0C (273\u2026823 K); Partial composition: 84-100 at.% Mg; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  16. \n\n
  17. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn Binary Phase Diagram 0-1.4 at.% Mn\n \n

    \n
    \n
      \n
    • \n Temperature: 600\u2026850 \u00b0C (873\u20261123 K); Partial composition: 0-1.4 at.% Mn; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  18. \n\n
  19. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Pb Binary Phase Diagram 0-33.3 at.% Pb\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026700 \u00b0C (273\u2026973 K); Partial composition: 0-33.3 at.% Pb; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  20. \n\n
  21. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Zn Binary Phase Diagram 0-4.8 at.% Zn\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026700 \u00b0C (273\u2026973 K); Partial composition: 0-4.8 at.% Zn; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  22. \n\n
  23. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ce-Mg Binary Phase Diagram 99.4-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026800 \u00b0C (373\u20261073 K); Partial composition: 99.4-100 at.% Mg; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  24. \n\n
  25. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026700 \u00b0C (273\u2026973 K); Full composition; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  26. \n\n
  27. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn Binary Phase Diagram 0-5 at.% Mn\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u2026800 \u00b0C (473\u20261073 K); Partial composition: 0-10 wt.% Mn; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  28. \n\n
  29. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 80-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026700 \u00b0C (373\u2026973 K); Partial composition: 80-100 at.% Mg; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  30. \n\n
  31. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 50-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 150\u2026700 \u00b0C (423\u2026973 K); Partial composition: 0-50 at.% Li; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  32. \n\n
  33. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 150\u2026700 \u00b0C (423\u2026973 K); Full composition; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  34. \n\n
  35. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 50-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 150\u2026500 \u00b0C (423\u2026773 K); Partial composition: 0-50 at.% Al; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  36. \n\n
  37. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Pb Binary Phase Diagram 0-10 at.% Pb\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026700 \u00b0C (273\u2026973 K); Partial composition: 0-10 at.% Pb; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  38. \n\n
  39. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn Binary Phase Diagram 0-3.25 at.% Mn\n \n

    \n
    \n
      \n
    • \n Temperature: 300\u2026900 \u00b0C (573\u20261173 K); Partial composition: 0-7 wt.% Mn; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  40. \n\n
\n
\n
\n \n \n Page\n \n \n \n \n \n \n \n is not a valid page number. Please enter a number between\n \n 1\n \n and\n \n 11\n \n \n \n of\n \n 11\n \n \n \n \n \n \n \n \n
\n\n
\n
\n
\n\n \n
\n
\n \n\n \n \n \n \n \n
\n

\n While using an institutional account for this website we don\u2019t track any personal, performance, functional or 1st or 3rd party related information. We only use essential cookies necessary for it to function correctly. Please read our\n privacy policy\n and\n California Privacy Statement\n for more information.\n

\n Okay\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" + }, + "http://materials.springer.com/search?searchTerm=es:Mg&pageNumber=5&datasourceFacet=sm_isp&substanceId=": { + "status_code": 200, + "json": null, + "text": "\n\n\n\n \n\n \n \n \n \n \n \n Search Results - SpringerMaterials\n \n \n \n \n \n \n \n \n \n\n\n \n
\n
\n
\n \n \"SpringerMaterials\"\n \n
\n \n
\n \n
\n
\n
\n\n
\n
\n
\n \n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n Filtered by:\n \n
\n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
\n
\n

Properties

\n
\n
\n
\n
\n \n
\n
\n
    \n \n
  1. \n \n \n \n \"\"/\n
  2. \n
  3. \n \n \n \n \"\"/\n
  4. \n
  5. \n \n \n \n \"\"/\n
  6. \n
  7. \n \n \n \n \"\"/\n
  8. \n
  9. \n \n \n \n \"\"/\n
  10. \n
  11. \n \n \n \n \"\"/\n
  12. \n
  13. \n \n \n \n \"\"/\n
  14. \n
  15. \n \n \n \n \"\"/\n
  16. \n
  17. \n \n \n \n \"\"/\n
  18. \n
  19. \n \n \n \n \"\"/\n
  20. \n
  21. \n \n \n \n \"\"/\n
  22. \n
  23. \n \n \n \n \"\"/\n
  24. \n
  25. \n \n \n \n \"\"/\n
  26. \n
  27. \n \n \n \n \"\"/\n
  28. \n
  29. \n \n \n \n \"\"/\n
  30. \n
  31. \n \n \n \n \"\"/\n
  32. \n
  33. \n \n \n \n \"\"/\n
  34. \n
  35. \n \n \n \n \"\"/\n
  36. \n
  37. \n \n \n \n \"\"/\n
  38. \n
  39. \n \n \n \n \"\"/\n
  40. \n
  41. \n \n \n \n \"\"/\n
  42. \n
  43. \n \n \n \n \"\"/\n
  44. \n
  45. \n \n \n \n \"\"/\n
  46. \n
  47. \n \n \n \n \"\"/\n
  48. \n
  49. \n \n \n \n \"\"/\n
  50. \n
  51. \n \n \n \n \"\"/\n
  52. \n
  53. \n \n \n \n \"\"/\n
  54. \n
  55. \n \n \n \n \"\"/\n
  56. \n
  57. \n \n \n \n \"\"/\n
  58. \n
  59. \n \n \n \n \"\"/\n
  60. \n
  61. \n \n \n \n \"\"/\n
  62. \n
  63. \n \n \n \n \"\"/\n
  64. \n
  65. \n \n \n \n \"\"/\n
  66. \n
  67. \n \n \n \n \"\"/\n
  68. \n
  69. \n \n \n \n \"\"/\n
  70. \n
  71. \n \n \n \n \"\"/\n
  72. \n
  73. \n \n \n \n \"\"/\n
  74. \n
  75. \n \n \n \n \"\"/\n
  76. \n
  77. \n \n \n \n \"\"/\n
  78. \n
  79. \n \n \n \n \"\"/\n
  80. \n
  81. \n \n \n \n \"\"/\n
  82. \n\n
\n
\n
\n
\n
\n

Data collections

\n
\n
\n
    \n
  1. \n \n \n 220\n \"\"/\n
  2. \n\n
  3. \n \n \n 218\n \"\"/\n
  4. \n
  5. \n \n \n 225\n \"\"/\n
  6. \n
  7. \n \n \n 1\n \"\"/\n
  8. \n
  9. \n \n \n 59\n \"\"/\n
  10. \n\n
\n
\n
\n
\n
\n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n
\n Filtered by:\n \n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
    \n
  1. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 53-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 537\u2026675 \u00b0C (810\u2026948 K); Partial composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  2. \n\n
  3. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026700 \u00b0C (373\u2026973 K); Full composition: 0-20 wt.% Mg; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  4. \n\n
  5. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 67-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 250\u2026720 \u00b0C (523\u2026993 K); Partial composition: 0-33 at.% Li; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  6. \n\n
  7. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n La-Mg Binary Phase Diagram 99.53-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 550\u2026675 \u00b0C (823\u2026948 K); Partial composition: 0-2.625 wt.% La; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  8. \n\n
  9. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-4.3 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 400\u2026650 \u00b0C (673\u2026923 K); Partial composition: 0-18 wt.% Sn; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  10. \n\n
  11. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 55-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u2026700 \u00b0C (473\u2026973 K); Partial composition: 0-45.4 wt.% Al; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  12. \n\n
  13. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Pb Binary Phase Diagram 0-22 at.% Pb\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026700 \u00b0C (373\u2026973 K); Partial composition: 0-70 wt.% Pb; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  14. \n\n
  15. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 85-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026550 \u00b0C (273\u2026823 K); Partial composition: 84-100 wt.% Mg; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  16. \n\n
  17. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 82-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u2026700 \u00b0C (473\u2026973 K); Partial composition: 0-20.05 wt.% Al; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  18. \n\n
  19. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ag-Mg Binary Phase Diagram 94-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 300\u2026700 \u00b0C (573\u2026973 K); Partial composition: 0-6 at.% Ag; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  20. \n\n
  21. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 65-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u2026700 \u00b0C (473\u2026973 K); Partial composition: 0-35 at.% Al; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  22. \n\n
  23. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n In-Mg Binary Phase Diagram 70-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 180\u2026680 \u00b0C (453\u2026953 K); Partial composition: 0-30 at.% In; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  24. \n\n
  25. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Pb Binary Phase Diagram 0-24 at.% Pb\n \n

    \n
    \n
      \n
    • \n Temperature: 180\u2026680 \u00b0C (453\u2026953 K); Partial composition: 0-24 at.% Pb; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  26. \n\n
  27. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-12 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 180\u2026680 \u00b0C (453\u2026953 K); Partial composition: 0-12 at.% Sn; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  28. \n\n
  29. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn Binary Phase Diagram 0-3.3 at.% Mn\n \n

    \n
    \n
      \n
    • \n Temperature: 400\u2026900 \u00b0C (673\u20261173 K); Partial composition: 0-7.2 wt.% Mn; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  30. \n\n
  31. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 68-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u2026650 \u00b0C (473\u2026923 K); Partial composition: 0-32 at.% Li; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  32. \n\n
  33. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026700 \u00b0C (373\u2026973 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  34. \n\n
  35. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026700 \u00b0C (373\u2026973 K); Full composition; Investigation: calculated; detailed; subregular solution model\n
    • \n
    \n
    \n
    \n
  36. \n\n
  37. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026700 \u00b0C (373\u2026973 K); Full composition; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  38. \n\n
  39. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n La-Mg Binary Phase Diagram 97-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 450\u2026700 \u00b0C (723\u2026973 K); Partial composition: 0-15 wt.% La; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  40. \n\n
\n
\n
\n \n \n Page\n \n \n \n \n \n \n \n is not a valid page number. Please enter a number between\n \n 1\n \n and\n \n 11\n \n \n \n of\n \n 11\n \n \n \n \n \n \n \n \n
\n\n
\n
\n
\n\n \n
\n
\n \n\n \n \n \n \n \n
\n

\n While using an institutional account for this website we don\u2019t track any personal, performance, functional or 1st or 3rd party related information. We only use essential cookies necessary for it to function correctly. Please read our\n privacy policy\n and\n California Privacy Statement\n for more information.\n

\n Okay\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" + }, + "http://materials.springer.com/search?searchTerm=es:Mg&pageNumber=6&datasourceFacet=sm_isp&substanceId=": { + "status_code": 200, + "json": null, + "text": "\n\n\n\n \n\n \n \n \n \n \n \n Search Results - SpringerMaterials\n \n \n \n \n \n \n \n \n \n\n\n \n
\n
\n
\n \n \"SpringerMaterials\"\n \n
\n \n
\n \n
\n
\n
\n\n
\n
\n
\n \n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n Filtered by:\n \n
\n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
\n
\n

Properties

\n
\n
\n
\n
\n \n
\n
\n
    \n \n
  1. \n \n \n \n \"\"/\n
  2. \n
  3. \n \n \n \n \"\"/\n
  4. \n
  5. \n \n \n \n \"\"/\n
  6. \n
  7. \n \n \n \n \"\"/\n
  8. \n
  9. \n \n \n \n \"\"/\n
  10. \n
  11. \n \n \n \n \"\"/\n
  12. \n
  13. \n \n \n \n \"\"/\n
  14. \n
  15. \n \n \n \n \"\"/\n
  16. \n
  17. \n \n \n \n \"\"/\n
  18. \n
  19. \n \n \n \n \"\"/\n
  20. \n
  21. \n \n \n \n \"\"/\n
  22. \n
  23. \n \n \n \n \"\"/\n
  24. \n
  25. \n \n \n \n \"\"/\n
  26. \n
  27. \n \n \n \n \"\"/\n
  28. \n
  29. \n \n \n \n \"\"/\n
  30. \n
  31. \n \n \n \n \"\"/\n
  32. \n
  33. \n \n \n \n \"\"/\n
  34. \n
  35. \n \n \n \n \"\"/\n
  36. \n
  37. \n \n \n \n \"\"/\n
  38. \n
  39. \n \n \n \n \"\"/\n
  40. \n
  41. \n \n \n \n \"\"/\n
  42. \n
  43. \n \n \n \n \"\"/\n
  44. \n
  45. \n \n \n \n \"\"/\n
  46. \n
  47. \n \n \n \n \"\"/\n
  48. \n
  49. \n \n \n \n \"\"/\n
  50. \n
  51. \n \n \n \n \"\"/\n
  52. \n
  53. \n \n \n \n \"\"/\n
  54. \n
  55. \n \n \n \n \"\"/\n
  56. \n
  57. \n \n \n \n \"\"/\n
  58. \n
  59. \n \n \n \n \"\"/\n
  60. \n
  61. \n \n \n \n \"\"/\n
  62. \n
  63. \n \n \n \n \"\"/\n
  64. \n
  65. \n \n \n \n \"\"/\n
  66. \n
  67. \n \n \n \n \"\"/\n
  68. \n
  69. \n \n \n \n \"\"/\n
  70. \n
  71. \n \n \n \n \"\"/\n
  72. \n
  73. \n \n \n \n \"\"/\n
  74. \n
  75. \n \n \n \n \"\"/\n
  76. \n
  77. \n \n \n \n \"\"/\n
  78. \n
  79. \n \n \n \n \"\"/\n
  80. \n
  81. \n \n \n \n \"\"/\n
  82. \n\n
\n
\n
\n
\n
\n

Data collections

\n
\n
\n
    \n
  1. \n \n \n 220\n \"\"/\n
  2. \n\n
  3. \n \n \n 218\n \"\"/\n
  4. \n
  5. \n \n \n 225\n \"\"/\n
  6. \n
  7. \n \n \n 1\n \"\"/\n
  8. \n
  9. \n \n \n 59\n \"\"/\n
  10. \n\n
\n
\n
\n
\n
\n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n
\n Filtered by:\n \n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
    \n
  1. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 86-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026700 \u00b0C (273\u2026973 K); Partial composition: 0-15 wt.% Al; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  2. \n\n
  3. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ag-Mg Binary Phase Diagram 95-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u2026700 \u00b0C (473\u2026973 K); Partial composition: 95-100 at.% Mg; Investigation: detailed\n
    • \n
    \n
    \n
    \n
  4. \n\n
  5. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026700 \u00b0C (273\u2026973 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  6. \n\n
  7. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn-Nd Solvus Projection of Ternary Phase Diagram\n \n

    \n
    \n
      \n
    • \n Partial composition: Mg-Mg99.2Mn0.8-Mg98.8mn0.8Nd0.4-Mg99.6Nd0.4, Mg-rich corner; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  8. \n\n
  9. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn Binary Phase Diagram 0-3 at.% Mn\n \n

    \n
    \n
      \n
    • \n Temperature: 275\u2026925 \u00b0C (548\u20261198 K); Partial composition: 0-3 at.% Mn; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  10. \n\n
  11. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026900 \u00b0C (373\u20261173 K); Full composition; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  12. \n\n
  13. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn Binary Phase Diagram 0-5 at.% Mn\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026900 \u00b0C (273\u20261173 K); Partial composition: 0-5 at.% Mn; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  14. \n\n
  15. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026800 \u00b0C (373\u20261073 K); Full composition; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  16. \n\n
  17. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn Binary Phase Diagram 0-5 at.% Mn\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u20261000 \u00b0C (473\u20261273 K); Partial composition: 0-5 at.% Mn; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  18. \n\n
  19. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Y Binary Phase Diagram 0-20 at.% Y\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026800 \u00b0C (373\u20261073 K); Partial composition: 0-20 at.% Y; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  20. \n\n
  21. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Gd-Mg Vertical Section of Ternary Phase Diagram\n \n

    \n
    \n
      \n
    • \n Temperature: 400\u20261800 \u00b0C (673\u20262073 K); Partial composition: GdAl2-Mg; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  22. \n\n
  23. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn-Nd Solidus Projection of Ternary Phase Diagram\n \n

    \n
    \n
      \n
    • \n Partial composition: Mg-Mg99Mn1-Mg98.2Mn1Nd0.8-Mg99.2Nd0.8, Mg-rich corner; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  24. \n\n
  25. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ce-Mg-Mn Vertical Section of Ternary Phase Diagram\n \n

    \n
    \n
      \n
    • \n Temperature: 580\u2026660 \u00b0C (853\u2026933 K); Partial composition: Mg99.73Mn0.27-Ce5.49Mg94.18Mn0.34, 0.6 wt.% Mn; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  26. \n\n
  27. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Mn Binary Phase Diagram 0-3 at.% Mn\n \n

    \n
    \n
      \n
    • \n Temperature: 300\u2026900 \u00b0C (573\u20261173 K); Partial composition: 0-3 at.% Mn; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  28. \n\n
  29. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Pb Binary Phase Diagram 0-100 at.% Pb\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026750 \u00b0C (273\u20261023 K); Full composition; Investigation: calculated; thermodynamic model\n
    • \n
    \n
    \n
    \n
  30. \n\n
  31. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026900 \u00b0C (373\u20261173 K); Full composition; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  32. \n\n
  33. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ag-Mg Binary Phase Diagram 72-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 150\u2026550 \u00b0C (423\u2026823 K); Partial composition: 0-28 at.% Ag; Investigation: experimental\n
    • \n
    \n
    \n
    \n
  34. \n\n
  35. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: -150\u2026850 \u00b0C (123\u20261123 K); Full composition; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  36. \n\n
  37. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026900 \u00b0C (373\u20261173 K); Full composition; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  38. \n\n
  39. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Zn Binary Phase Diagram 0-6 at.% Zn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026700 \u00b0C (373\u2026973 K); Partial composition: 0-6 at.% Zn; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  40. \n\n
\n
\n
\n \n \n Page\n \n \n \n \n \n \n \n is not a valid page number. Please enter a number between\n \n 1\n \n and\n \n 11\n \n \n \n of\n \n 11\n \n \n \n \n \n \n \n \n
\n\n
\n
\n
\n\n \n
\n
\n \n\n \n \n \n \n \n
\n

\n While using an institutional account for this website we don\u2019t track any personal, performance, functional or 1st or 3rd party related information. We only use essential cookies necessary for it to function correctly. Please read our\n privacy policy\n and\n California Privacy Statement\n for more information.\n

\n Okay\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" + }, + "http://materials.springer.com/search?searchTerm=es:Mg&pageNumber=7&datasourceFacet=sm_isp&substanceId=": { + "status_code": 200, + "json": null, + "text": "\n\n\n\n \n\n \n \n \n \n \n \n Search Results - SpringerMaterials\n \n \n \n \n \n \n \n \n \n\n\n \n
\n
\n
\n \n \"SpringerMaterials\"\n \n
\n \n
\n \n
\n
\n
\n\n
\n
\n
\n \n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n Filtered by:\n \n
\n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
\n
\n

Properties

\n
\n
\n
\n
\n \n
\n
\n
    \n \n
  1. \n \n \n \n \"\"/\n
  2. \n
  3. \n \n \n \n \"\"/\n
  4. \n
  5. \n \n \n \n \"\"/\n
  6. \n
  7. \n \n \n \n \"\"/\n
  8. \n
  9. \n \n \n \n \"\"/\n
  10. \n
  11. \n \n \n \n \"\"/\n
  12. \n
  13. \n \n \n \n \"\"/\n
  14. \n
  15. \n \n \n \n \"\"/\n
  16. \n
  17. \n \n \n \n \"\"/\n
  18. \n
  19. \n \n \n \n \"\"/\n
  20. \n
  21. \n \n \n \n \"\"/\n
  22. \n
  23. \n \n \n \n \"\"/\n
  24. \n
  25. \n \n \n \n \"\"/\n
  26. \n
  27. \n \n \n \n \"\"/\n
  28. \n
  29. \n \n \n \n \"\"/\n
  30. \n
  31. \n \n \n \n \"\"/\n
  32. \n
  33. \n \n \n \n \"\"/\n
  34. \n
  35. \n \n \n \n \"\"/\n
  36. \n
  37. \n \n \n \n \"\"/\n
  38. \n
  39. \n \n \n \n \"\"/\n
  40. \n
  41. \n \n \n \n \"\"/\n
  42. \n
  43. \n \n \n \n \"\"/\n
  44. \n
  45. \n \n \n \n \"\"/\n
  46. \n
  47. \n \n \n \n \"\"/\n
  48. \n
  49. \n \n \n \n \"\"/\n
  50. \n
  51. \n \n \n \n \"\"/\n
  52. \n
  53. \n \n \n \n \"\"/\n
  54. \n
  55. \n \n \n \n \"\"/\n
  56. \n
  57. \n \n \n \n \"\"/\n
  58. \n
  59. \n \n \n \n \"\"/\n
  60. \n
  61. \n \n \n \n \"\"/\n
  62. \n
  63. \n \n \n \n \"\"/\n
  64. \n
  65. \n \n \n \n \"\"/\n
  66. \n
  67. \n \n \n \n \"\"/\n
  68. \n
  69. \n \n \n \n \"\"/\n
  70. \n
  71. \n \n \n \n \"\"/\n
  72. \n
  73. \n \n \n \n \"\"/\n
  74. \n
  75. \n \n \n \n \"\"/\n
  76. \n
  77. \n \n \n \n \"\"/\n
  78. \n
  79. \n \n \n \n \"\"/\n
  80. \n
  81. \n \n \n \n \"\"/\n
  82. \n\n
\n
\n
\n
\n
\n

Data collections

\n
\n
\n
    \n
  1. \n \n \n 220\n \"\"/\n
  2. \n\n
  3. \n \n \n 218\n \"\"/\n
  4. \n
  5. \n \n \n 225\n \"\"/\n
  6. \n
  7. \n \n \n 1\n \"\"/\n
  8. \n
  9. \n \n \n 59\n \"\"/\n
  10. \n\n
\n
\n
\n
\n
\n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n
\n Filtered by:\n \n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
    \n
  1. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Zn Binary Phase Diagram 0-100 at.% Zn\n \n

    \n
    \n
      \n
    • \n Temperature: 300\u2026700 \u00b0C (573\u2026973 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  2. \n\n
  3. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Zn Binary Phase Diagram 0-100 at.% Zn\n \n

    \n
    \n
      \n
    • \n Temperature: 300\u2026650 \u00b0C (573\u2026923 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  4. \n\n
  5. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 350\u2026700 \u00b0C (623\u2026973 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  6. \n\n
  7. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Pb Binary Phase Diagram 0-100 at.% Pb\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026700 \u00b0C (373\u2026973 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  8. \n\n
  9. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026800 \u00b0C (373\u20261073 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  10. \n\n
  11. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 50\u2026800 \u00b0C (323\u20261073 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  12. \n\n
  13. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026800 \u00b0C (373\u20261073 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  14. \n\n
  15. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ag-Mg Binary Phase Diagram 70-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u2026700 \u00b0C (473\u2026973 K); Partial composition: 0-67 wt.% Ag; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  16. \n\n
  17. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ag-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u20261000 \u00b0C (373\u20261273 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  18. \n\n
  19. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026900 \u00b0C (273\u20261173 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  20. \n\n
  21. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026800 \u00b0C (373\u20261073 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  22. \n\n
  23. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Li-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u2026700 \u00b0C (273\u2026973 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  24. \n\n
  25. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026800 \u00b0C (373\u20261073 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  26. \n\n
  27. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ag-Mg Binary Phase Diagram 72-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 200\u2026700 \u00b0C (473\u2026973 K); Partial composition: 0-63 wt.% Ag; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  28. \n\n
  29. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 100\u2026900 \u00b0C (373\u20261173 K); Full composition; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  30. \n\n
  31. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ag-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u20261000 \u00b0C (273\u20261273 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  32. \n\n
  33. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Sn Binary Phase Diagram 0-100 at.% Sn\n \n

    \n
    \n
      \n
    • \n Temperature: 0\u20261000 \u00b0C (273\u20261273 K); Full composition; Investigation: calculated; detailed\n
    • \n
    \n
    \n
    \n
  34. \n\n
  35. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Ag-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 400\u20261000 \u00b0C (673\u20261273 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  36. \n\n
  37. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Al-Mg Binary Phase Diagram 0-100 at.% Mg\n \n

    \n
    \n
      \n
    • \n Temperature: 150\u2026700 \u00b0C (423\u2026973 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  38. \n\n
  39. \n
    \n
    \n \n
    \n
    \n
    \n

    \n Inorganic Solid Phases\n

    \n

    \n \n Mg-Pb Binary Phase Diagram 0-100 at.% Pb\n \n

    \n
    \n
      \n
    • \n Temperature: 180\u2026670 \u00b0C (453\u2026943 K); Full composition; Investigation: experimental; detailed\n
    • \n
    \n
    \n
    \n
  40. \n\n
\n
\n
\n \n \n Page\n \n \n \n \n \n \n \n is not a valid page number. Please enter a number between\n \n 1\n \n and\n \n 11\n \n \n \n of\n \n 11\n \n \n \n \n \n \n \n \n
\n\n
\n
\n
\n\n \n
\n
\n \n\n \n \n \n \n \n
\n

\n While using an institutional account for this website we don\u2019t track any personal, performance, functional or 1st or 3rd party related information. We only use essential cookies necessary for it to function correctly. Please read our\n privacy policy\n and\n California Privacy Statement\n for more information.\n

\n Okay\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" + }, + "http://materials.springer.com/search?searchTerm=es:Mg&pageNumber=8&datasourceFacet=sm_isp&substanceId=": { + "status_code": 200, + "json": null, + "text": "\n\n\n\n \n\n \n \n \n \n \n \n Search Results - SpringerMaterials\n \n \n \n \n \n \n \n \n \n\n\n \n
\n
\n
\n \n \"SpringerMaterials\"\n \n
\n \n
\n \n
\n
\n
\n\n
\n
\n
\n \n
\n
\n 220\n results for\n
\n Substance: mg \n
\n
\n Filtered by:\n \n
\n
\n
\n Search instead using the phrase: "es:Mg"\n
\n
\n
\n
\n

Properties

\n
\n
\n
\n
\n \n
\n
\n
    \n \n
  1. \n \n \n \n \"\"/\n
  2. \n
  3. \n \n \n \n \"\"/\n
  4. \n
  5. \n \n \n \n \"\"/\n
  6. \n
  7. \n \n \n \n \"\"/\n
  8. \n
  9. \n \n \n \n \"\"/\n
  10. \n
  11. \n \n \n \n \"\"/\n
  12. \n
  13. \n \n \n \n \"\"/\n
  14. \n
  15. \n \n \n \n \"\"/\n
  16. \n
  17. \n \n \n \n \"\"/\n
  18. \n
  19. \n \n \n \n \"\"/\n
  20. \n
  21. \n \n \n \n \"\"/\n
  22. \n
  23. \n \n \n \n \"\"/\n
  24. \n
  25. \n \n \n \n \"\"/\n
  26. \n
  27. \n \n \n \n \"\"/\n
  28. \n
  29. \n \n \n \n