From 17c7aabdc2af142e724b7d19657ba1806122df2a Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Mon, 13 Dec 2021 13:17:41 -0800 Subject: [PATCH 001/306] #18: Initial migration of style sheets --- app/src/assets/css/abstract/_animation.scss | 49 ++ app/src/assets/css/abstract/_mixins.scss | 60 +++ app/src/assets/css/abstract/_variables.scss | 20 + app/src/assets/css/base/_grid.scss | 54 +++ app/src/assets/css/base/_reset.scss | 43 ++ app/src/assets/css/modules/_button.scss | 130 ++++++ app/src/assets/css/modules/_footer.scss | 86 ++++ app/src/assets/css/modules/_form.scss | 100 ++++ app/src/assets/css/modules/_header.scss | 61 +++ app/src/assets/css/modules/_misc.scss | 480 ++++++++++++++++++++ app/src/assets/css/modules/_navigation.scss | 200 ++++++++ app/src/assets/css/modules/_quicklinks.scss | 105 +++++ app/src/assets/css/modules/_section.scss | 151 ++++++ app/src/assets/css/modules/_utility.scss | 148 ++++++ app/src/assets/css/modules/_visualize.scss | 395 ++++++++++++++++ app/src/assets/css/style.scss | 15 + 16 files changed, 2097 insertions(+) create mode 100644 app/src/assets/css/abstract/_animation.scss create mode 100644 app/src/assets/css/abstract/_mixins.scss create mode 100644 app/src/assets/css/abstract/_variables.scss create mode 100644 app/src/assets/css/base/_grid.scss create mode 100644 app/src/assets/css/base/_reset.scss create mode 100644 app/src/assets/css/modules/_button.scss create mode 100644 app/src/assets/css/modules/_footer.scss create mode 100644 app/src/assets/css/modules/_form.scss create mode 100644 app/src/assets/css/modules/_header.scss create mode 100644 app/src/assets/css/modules/_misc.scss create mode 100644 app/src/assets/css/modules/_navigation.scss create mode 100644 app/src/assets/css/modules/_quicklinks.scss create mode 100644 app/src/assets/css/modules/_section.scss create mode 100644 app/src/assets/css/modules/_utility.scss create mode 100644 app/src/assets/css/modules/_visualize.scss create mode 100644 app/src/assets/css/style.scss diff --git a/app/src/assets/css/abstract/_animation.scss b/app/src/assets/css/abstract/_animation.scss new file mode 100644 index 00000000..4514ec65 --- /dev/null +++ b/app/src/assets/css/abstract/_animation.scss @@ -0,0 +1,49 @@ +@keyframes moveInLeft { + 0% { + opacity: 0; + transform: translateX(-10rem); + } + 80% { + transform: translateX(1rem); + } + 100% { + opacity: 1; + transform: translate(0); + } +} + +@keyframes moveInRight { + 0% { + opacity: 0; + transform: translateX(10rem); + } + 80% { + transform: translateX(-1rem); + } + 100% { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes moveInBottom { + 0% { + opacity: 0; + transform: translateY(3rem); + } + 100% { + opacity: 1; + transform: translate(0); + } +} + +@keyframes moveInTop { + 0% { + opacity: 0; + transform: translateY(-4rem); + } + 100% { + opacity: 1; + transform: translate(0); + } +} \ No newline at end of file diff --git a/app/src/assets/css/abstract/_mixins.scss b/app/src/assets/css/abstract/_mixins.scss new file mode 100644 index 00000000..9b76c5ae --- /dev/null +++ b/app/src/assets/css/abstract/_mixins.scss @@ -0,0 +1,60 @@ +@mixin clearfix { + &::after { + content: ""; + display: table; + clear: both; + } +} + +@mixin absCenter { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +@mixin chartDisplayAdjust($i, $num) { + @if $i > $num { + visibility: hidden; + display: none; + opacity: 0; + } +} + + + +@mixin respond($breakpoint) { + @if $breakpoint == phone { + @media only screen and (max-width: 40.5em) { @content }; //600px + } + @if $breakpoint == tab-port { + @media only screen and (max-width: 56.25em) { @content }; //900px + } + @if $breakpoint == tab-land { + @media only screen and (max-width: 75em) { @content }; //1200px + } + @if $breakpoint == laptop { + @media only screen and (max-width: 90em) { @content }; //1440px + } + @if $breakpoint == big-desktop-chart-adjust { + @media only screen and (min-width: 112.5em) and (min-resolution: 250dpi) { @content }; //1800 + } + @if $breakpoint == big-desktop { + @media only screen and (min-width: 112.5em) { @content }; //1800 + } +} + + +@supports (-webkit-hyphens:none){ + .safari_only { + bottom: 1.5rem !important; + } +} + +/* @media screen and (min-color-index:0) and(-webkit-min-device-pixel-ratio:0){ + @media screen { + _:-webkit-full-screen, .safari_only { + bottom: 1.5rem !important; + } + } +} */ \ No newline at end of file diff --git a/app/src/assets/css/abstract/_variables.scss b/app/src/assets/css/abstract/_variables.scss new file mode 100644 index 00000000..32833689 --- /dev/null +++ b/app/src/assets/css/abstract/_variables.scss @@ -0,0 +1,20 @@ +// $primary: #14274E; +// $primary-light: #394867; +// $secondary: #b3d4fc; +// $primary-white: #ffffff; +// $primary-black: #000000; + +$primary: #08233c; +$primary-light: #083d56; +$secondary: #0e5f76; +$tertiary: #d7df71; +$primary-white: #ffffff; +$primary-grey: #4b4b4b; +$primary-black: #000000; +$error: red; + +// FONT SIZE +$small-size: .6rem; +$medium-size: 1rem; +$medium-mid-size: 1.3rem; +$default-size: 1.5rem; \ No newline at end of file diff --git a/app/src/assets/css/base/_grid.scss b/app/src/assets/css/base/_grid.scss new file mode 100644 index 00000000..b3fab7d1 --- /dev/null +++ b/app/src/assets/css/base/_grid.scss @@ -0,0 +1,54 @@ +.grid { + display: grid; + + &_gap { + &-smaller { + grid-gap: .4rem; + } + &-small { + grid-gap: 1rem; + } + &-big { + grid-gap: 5rem; + } + } + + &_row { + &-1 { + grid-template-rows: repeat(1, 1fr); + } + &-2 { + grid-template-rows: repeat(2, 1fr); + } + } + + &_col { + &-2 { + grid-template-columns: repeat(2, 1fr); + } + &-3 { + grid-template-columns: repeat(3, 1fr); + @include respond(phone) { + grid-template-columns: repeat(1, 1fr); + grid-gap: 1.4rem; + } + } + &-4 { + grid-template-columns: repeat(4, 1fr); + @include respond(phone) { + grid-template-columns: repeat(1, 1fr); + grid-gap: 1.4rem; + } + } + &-space-right { + grid-template-columns: 1fr 2fr; + @include respond(phone) { + grid-template-columns: repeat(1, 1fr); + grid-gap: 1rem; + } + } + &-space-left { + grid-template-columns: 2fr 1fr; + } + } +} \ No newline at end of file diff --git a/app/src/assets/css/base/_reset.scss b/app/src/assets/css/base/_reset.scss new file mode 100644 index 00000000..397c0bc7 --- /dev/null +++ b/app/src/assets/css/base/_reset.scss @@ -0,0 +1,43 @@ +*, +*::before, +*::after { + margin: 0; + padding: 0; + box-sizing: inherit; +} + +html { + // This defines what 1rem is + font-size: 62.5%; //1 rem = 10px; 10px/16px = 62.5% + + @include respond(tab-land) { // width < 1200? + font-size: 56.25%; //1 rem = 9px, 9/16 = 50% + } + + @include respond(tab-port) { // width < 900? + font-size: 50%; //1 rem = 8px, 8/16 = 50% + } + + @include respond(big-desktop) { + font-size: 75%; //1rem = 12, 12/16 + } + scroll-behavior: smooth; +} + +body { + box-sizing: border-box; + font-family: "Roboto", sans-serif; + background-color: $primary; +} + +img { + max-width: 100%; + height: auto; + margin: 0; +} + +::selection { + background-color: $tertiary !important; + color: $primary !important; + text-shadow: none; +} \ No newline at end of file diff --git a/app/src/assets/css/modules/_button.scss b/app/src/assets/css/modules/_button.scss new file mode 100644 index 00000000..7561eb60 --- /dev/null +++ b/app/src/assets/css/modules/_button.scss @@ -0,0 +1,130 @@ +.btn { + &, + &:link, + &:visited { + text-transform: uppercase; + text-decoration: none; + padding: 1rem 1.8rem; + display: inline-block; + border-radius: 10rem; + transition: all .2s; + position: relative; + font-size: $medium-size; + font-weight: bold; + + //Change for the + + + + + + + + +
+
+

Nanomine Visualization Dashboard

+

Welcome! Explore a series of visualization revealing data information by clicking on the buttons in the navigation bar.

+
+ +
+
+
+

In this prototype data visualizer, data in NanoMine are visualized in various ways. At present, four functions are being developed and preliminary versions are available in the navigation bar:

+

• Filler Descriptors vs. Material Property:to see impact of the filler features on the final properties.

+

• Material Property Dashboard:to explore the correlations between two selected properties.

+

• Material Spectrum:to examine the relationshipsbetween the features and the properties of a specific composite or a certain matrix or filler of interest.

+

• Database Overview (under construction) will offera visual summary of the data in NanoMine.

+ +
+ + +

While many of these functions are under construction, an example illustrating the types of visualizations which will be readily available in the next months is below.

+

To re-createthe sample visualization shown below:

+

• select the first tab (“filler descriptor vs material propertyâ€)

+

• select“mass fractionâ€as the x-axis

+

• select “glass transition temperature†as the y-axis

+

• Refinement can be obtained by playing with other features on the page

+

• A table below the graph contains the information of the graph in tabular form and will eventually point to individual records for each sample.

+

• In a month, there will be control samples labeled as such in NanoMine allowing for difference in property plots. ????

+ +
+
+
+
+ + + \ No newline at end of file diff --git a/whyis/materialsmine/tests/README.md b/whyis/materialsmine/tests/README.md new file mode 100644 index 00000000..d959d628 --- /dev/null +++ b/whyis/materialsmine/tests/README.md @@ -0,0 +1,53 @@ +* The autoparser currently allows for automatic testing of the following categories: + * PNC Present + * Authors + * Keywords + * DOI Number + * Language + * Journal Volume + * Matrix Chemical Names + * Matrix Chemical Trade Names + * Filler Chemical Names + * Filler Chemical Trade Names + * Devices + * Temperatures + * Material Properties Combined (ensuring properties are properly associated) + +* This list will be expanded as new automated tests are developed + +* The autoparser and all actual testing code are in `ingest_tester.py` + +# An Intro to Unit Tests for Nanomine +* Tristan Protzman +* protzt@rpi.edu + +Hopefully this should outline the basics of expanding the unit tests for the xml ingest SELTr script use by the Nanomine project. + +### Identifying tests +* To start, I had been printing all the triples generated and seeing what was in there, and writing tests to verify that those work more broadly than in a specific file. +* Now that a lot of the backlog has been worked through, I have been addressing topics as Neha or I added them. +* Effective tests will target a specific property that has a definite value to be compared against. + * i.e. the mass of a sample or the chemical abbreviation. + +### Writing tests +* All reusable test code (queries, comparison, general processing) should go in `ingest_tester.py`. + * This file is then imported by files which test specific files. + * The general pattern for this file is query the graph, process the results, and compare to expected values. + * Determining the query has mostly been done by examining the ingest SETLr script to determine what the expected structure is, and verifying with those more knowledgeable in the subject than I when questions arise. + * Processing the data usually is just a list comprehension to pull desired parameter out of the returned results + * Finally, using `unittest.assertEqual()` (or `unittest.assertCountEqual()` for lists of data) to verify that the query matches the expected result. +* Then, in a python file per xml file we wish to test, we fill in the expected results and call the testing function. + * `auto_test_template.py` can be used as a template, though it should not be modified + * Extend `template.IngestTestSetup` to get all the functionality needed. + * Can instead extend `template.IngestTestTests` to get an automated test suite, + * In most cases `rdflib` will need to be imported as well to instantiate the expected data as a `rdflib.Literal()`. + * Each test should be its own function within the class for more granular pass/fail results. + +### Automated testing +* Things have kinda fallen off here, but the infrastructure is in place to run automatic testing on large numbers of files. + * At the top of `ingest_tester.py` is the `autoparse` function which can read through the xml file to pull information from it, in effect loading the expected data automatically. + * The tests can then look for this data to automatically run tests. + * Tests which we want to be ran automatically should be placed in the `IngestTestTests` class in `template.py` +* These tests can be then executed automatically with the `auto_tester.py` script, which can be supplied with a number of files to test and a `--scramble` parameter to randomize which files are tested. +* I believe this functionally works, though I admit it's been a while since I've worked on it. +* The tests can also be run through whyis using `python manage.py test --apponly` diff --git a/whyis/materialsmine/tests/__init__.py b/whyis/materialsmine/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/whyis/materialsmine/tests/auto_test_template.py b/whyis/materialsmine/tests/auto_test_template.py new file mode 100644 index 00000000..4d0611ab --- /dev/null +++ b/whyis/materialsmine/tests/auto_test_template.py @@ -0,0 +1,16 @@ +# Note: Do not edit this, it is copied and used as a template for batch testing +# Add any new tests to test_template.IngestTestTests instead, as this will then run +# them while doing batch testing. If you wish to test a specific file, this serves +# as a starting point which can be worked from + +from . import ingest_tester +from . import template + +file_under_test = "" + +class IngestTestRunner(test_template.IngestTestTests): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() diff --git a/whyis/materialsmine/tests/auto_tester.py b/whyis/materialsmine/tests/auto_tester.py new file mode 100644 index 00000000..90e7918e --- /dev/null +++ b/whyis/materialsmine/tests/auto_tester.py @@ -0,0 +1,69 @@ +import os +import subprocess +import sys +import time +import random +from SPARQLWrapper import SPARQLWrapper, JSON + +def main(argv): + run_all = True + to_run = 0 + if len(argv) >= 2: + run_all = False + to_run = int(argv[1]) + endpoint = SPARQLWrapper("https://materialsmine.org/wi/sparql") + endpoint.setQuery( + ''' + SELECT DISTINCT ?article WHERE { + ?doi a . + ?doi ?article . + } + ''' + ) + endpoint.setReturnFormat(JSON) + results = endpoint.query().convert() + files = [uri["article"]["value"].replace("http://nanomine.org/sample/", "").replace("-", "_").title() + for uri in results["results"]["bindings"]] + + + if os.path.exists("/apps/nanomine-graph/tests/output.txt"): + os.remove("/apps/nanomine-graph/tests/output.txt") + + tests_ran = 0 + tests_failed = 0 + if "--scramble" in argv: + random.shuffle(files) + for uri in files: + sys.stdout.write(uri + "...") + tests_ran += 1 + test_text = str() + with open("/apps/nanomine-graph/tests/auto_tester.py", "r") as f: + test_text = f.read() + test_text = test_text.replace("", uri) + with open("/apps/nanomine-graph/tests/test_auto_active.py", "w") as f: + f.write(test_text) + std_err = subprocess.run(["/apps/whyis/venv/bin/python", "manage.py", "test", "--test=test_auto_active"], stdout=subprocess.DEVNULL, stderr=subprocess.PIPE).stderr.decode("utf-8") + if "FAILED" in std_err or "ERROR" in std_err: # We want to catch any tests that fail or error to investigate them + print(" FAIL") + tests_failed += 1 + with open("/apps/nanomine-graph/tests/output.txt", "a") as outfile: + outfile.write("*" * 20 + uri + "*" * 20) + # outfile.write("\nSTDOUT\n") + # outfile.write(std_out) + outfile.write("\nSTDERR\n") + outfile.write(std_err) + outfile.write("\n" + "*" * 45) + outfile.write("\n\n\n") + else: + print(" PASS") + os.remove("/apps/nanomine-graph/tests/test_auto_active.py") + if not run_all and tests_ran >= to_run: + break + return tests_ran, tests_failed + + +if __name__ == "__main__": + start = time.time() + tests_ran, tests_failed = main(sys.argv) + end = time.time() + print("{}/{} tests passed in {:.1f} seconds".format(tests_ran - tests_failed, tests_ran, end - start)) \ No newline at end of file diff --git a/whyis/materialsmine/tests/ingest_tester.py b/whyis/materialsmine/tests/ingest_tester.py new file mode 100644 index 00000000..bfaaf521 --- /dev/null +++ b/whyis/materialsmine/tests/ingest_tester.py @@ -0,0 +1,756 @@ +import json +import requests +import tempfile +import xml.etree.ElementTree as ET +import pandas as pd +import rdflib +import slugify +import os + +from urllib3.util.retry import Retry +from requests.adapters import HTTPAdapter + +from base64 import b64encode + +import autonomic + +disabled = [] + +files = { + "template": ''' a , + , + ; + "data:text/xml;charset=UTF-8;base64,%s" .''' +} + + +def get_remote_xml(file_under_test): + """ Given an nanomine file returns the xml string """ + s = requests.Session() + retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504], raise_on_redirect=True, raise_on_status=True) + s.mount("http://", HTTPAdapter(max_retries=retries)) + response = s.get('https://materialsmine.org/nmr/xml/' + file_under_test + '.xml', timeout=5) + j = json.loads(response.text) + xml_str = j["data"][0]["xml_str"] + return xml_str + + +def get_local_xml(file_under_test): + """ Attempts to load a given file from the local /tests/xml/ folder """ + file_under_test += ".xml" + test_folder_path = os.path.abspath(os.path.dirname(__file__)) + file_path = os.path.join(test_folder_path, "xml", file_under_test) + print (file_path) + with open(file_path) as f: + return f.read() + +def get_xml(file_under_test): + #try: + return get_local_xml(file_under_test) + #except FileNotFoundError: + # print("File not found locally, loading from server...") + # return get_remote_xml(file_under_test) + +def disable_test(func): + disabled.append(func.__name__) + print(func.__name__, "is disabled and will not run") + def disable(*args, **kwargs): + print(func.__name__, "has been disabled") + return disable + + +def setUp(runner, file_under_test): + # Skip setting up disabled tests + if os.getenv("CI") is not None: + if runner._testMethodName in disabled: + print("Skipping test", str(runner._testMethodName), "in CI since it is disabled") + return + # Initialization + runner.login(*runner.create_user("user@example.com", "password")) + + xml_str = get_xml(file_under_test) + encoded_file = b64encode(xml_str.encode('utf8')) + + print ("XML length:", len(encoded_file)) + files[file_under_test] = files["template"] % (file_under_test, encoded_file) + upload = files[file_under_test] + + response = runner.client.post("/pub", data=upload, content_type="text/turtle", follow_redirects=True) + runner.assertEquals(response.status, '201 CREATED') + + response = runner.client.post("/pub", data=open('/apps/nanomine-graph/setl/xml_ingest.setl.ttl', 'rb').read(), + content_type="text/turtle", follow_redirects=True) + runner.assertEquals(response.status, '201 CREATED') + + fileid = runner.app.db.value(rdflib.URIRef('https://materialsmine.org/nmr/xml/'+file_under_test), + rdflib.URIRef('http://vocab.rpi.edu/whyis/hasFileID')) + runner.assertNotEquals(fileid,None) + setlmaker = autonomic.SETLMaker() + results = runner.run_agent(setlmaker) + + # confirm this is creating a SETL script for the XML file. + runner.assertTrue(len(results) > 0) + + setlr = autonomic.SETLr() + + print(len(runner.app.db)) + for setlr_np in results: + print (setlr_np.serialize(format="trig").decode('utf8')) + setlr_results = runner.run_agent(setlr, nanopublication=setlr_np) + + +def test_non_spherical_shape(runner, expected_widthDescription=None, expected_width=None, expected_lengthDescription=None, expected_length=None, expected_depthDescription=None, expected_depth=None): + print("\n\nNon Spherical Shape") + dimensions = runner.app.db.query( + """ + SELECT ?widthValue ?lengthValue ?depthValue ?lengthDesc ?widthDesc ?depthDesc WHERE{ + ?bnode . + ?bnode . + ?bnode ?widthValue . + ?bnode ?widthDesc . + ?bnode1 . + ?bnode1 . + ?bnode1 ?lengthValue . + ?bnode1 ?lengthDesc . + ?bnode2 . + ?bnode2 . + ?bnode2 ?depthValue . + ?bnode2 ?depthDesc . + } + """ + ) + width_value = [dim["widthValue"] for dim in dimensions] + runner.assertEqual(expected_width, width_value[0]) + length_value = [dim["lengthValue"] for dim in dimensions] + runner.assertEqual(expected_length, length_value[0]) + depth_value = [dim["depthValue"] for dim in dimensions] + runner.assertEqual(expected_depth, depth_value[0]) + width_desc = [dim["widthDesc"] for dim in dimensions] + runner.assertEqual(expected_widthDescription, width_desc[0]) + length_desc = [dim["lengthDesc"] for dim in dimensions] + runner.assertEqual(expected_lengthDescription, length_desc[0]) + depth_desc = [dim["depthDesc"] for dim in dimensions] + runner.assertEqual(expected_depthDescription, depth_desc[0]) + print("Expected Non Spherical Dimensions and descriptions found") + +def query_table(runner, dependentVar, independentVar, + measurement_description=None, x_description=None, y_description=None): + + if measurement_description is not None: + measurement_description = '?sample "{}" .'.format(measurement_description) + else: + measurement_description = "" + + if x_description is not None: + x_description = '?independentVarNode "{}" .'.format(x_description) + else: + x_description = "" + + if y_description is not None: + y_description = '?dependentVarNode "{}" .'.format(y_description) + else: + y_description = "" + + + + query = """ + SELECT ?dependentVar ?independentVar + WHERE {{ + ?sample ?dependentVarNode . + ?dependentVarNode a {} . + ?dependentVarNode ?dependentVar . + ?dependentVarNode ?independentVarNode . + ?independentVarNode a {} . + ?independentVarNode ?independentVar . + {} + {} + {} + }} + """.format(dependentVar, independentVar, measurement_description, x_description, y_description) + # print(query) + values = runner.app.db.query(query) + return values + + + + +def autoparse(file_under_test): + # Parses out information from the specified file for verification the the correct data + # ends up in the graph + with tempfile.TemporaryFile() as temp: + xml_str = get_remote_xml(file_under_test) + temp.write(xml_str.encode('utf-8')) + temp.seek(0) + tree = ET.parse(temp) + + root = tree.getroot() + expected_data = dict() + # CommonFields Data + # common_fields = next(root.iter("CommonFields")) + expected_data["authors"] = [ + elem.text for elem in root.findall(".//CommonFields//Author")] + expected_data["keywords"] = [elem.text.title() + for elem in root.findall(".//CommonFields//Keyword")] + expected_data["DOI"] = [elem.text.title() + for elem in root.findall(".//CommonFields//DOI")] + expected_data["language"] = ["http://nanomine.org/language/" + elem.text.lower() + for elem in root.findall(".//CommonFields//Language")] + expected_data["journ_vol"] = [ + rdflib.Literal(int(val.text)) for val in root.findall(".//CommonFields//Volume")] + + # Matrix Data + # matrix_data = next(root.iter("Matrix")) + expected_data["m_name"] = [rdflib.Literal(elem.text) + for elem in root.findall(".//Matrix//ChemicalName")] + expected_data["m_trd_name"] = [ + rdflib.Literal(elem.text) for elem in root.findall(".//Matrix//TradeName")] + expected_data["abbrev"] = [rdflib.Literal(elem.text) + for elem in root.findall(".//Matrix//Abbreviation")] + expected_data["manufac"] = [ + rdflib.Literal(elem.text) for elem in root.findall(".//Matrix//ManufacturerOrSourceName")] + expected_data["specific_surface_area"] = [ + rdflib.Literal(elem.text, datatype=rdflib.XSD.double) for elem in root.findall(".//Matrix//SurfaceArea/specific/value")] + expected_data["specific_surface_area_units"] = [ + rdflib.Literal(elem.text) for elem in root.findall(".//Matrix//SurfaceArea/specific/unit")] + + # Filler data + # filler_data = next(root.iter("Filler")) + expected_data["f_name"] = [rdflib.Literal(elem.text) + for elem in root.findall(".//Filler//ChemicalName")] + expected_data["f_trd_name"] = [ + rdflib.Literal(elem.text) for elem in root.findall(".//Filler//TradeName")] + expected_data["abbrev"] += [rdflib.Literal(elem.text) + for elem in root.findall(".//Filler//Abbreviation")] + expected_data["manufac"] += [rdflib.Literal(elem.text) + for elem in root.findall(".//Filler//ManufacturerOrSourceName")] + expected_data["specific_surface_area"] += [ + rdflib.Literal(elem.text, datatype=rdflib.XSD.double) for elem in root.findall(".//Filler//SurfaceArea/specific/value")] + expected_data["specific_surface_area_units"] += [ + rdflib.Literal(elem.text) for elem in root.findall(".//Filler//SurfaceArea/specific/unit")] + + #Viscoleastic Properties,hardness, hardnessteststandard - Neha + expected_data["viscoelastic_measurement_mode"] = [rdflib.Literal(elem.text) + for elem in root.iter(".//Viscoelastic//MeasurementMode")] + + expected_data["hardness"] = [rdflib.Literal(elem.text) + for elem in root.iter("Hardness")] + + expected_data["hardnessteststandard"] = [rdflib.Literal(elem.text) + for elem in root.iter(".//HardnessTestStandard")] + + expected_data["melt_viscosity_values"] = [rdflib.Literal(elem.text) + for elem in root.iter("Author")] + + + # Check that matrix and filler components are properly constructed + def build_component_dict(component): + material = dict() + material["name"] = component.find(".//ChemicalName") + material["abbrev"] = component.find(".//Abbreviation") + material["manufac"] = component.find(".//ManufacturerOrSourceName") + material["trade"] = component.find(".//TradeName") + for key, value in material.items(): + if value is not None: + material[key] = rdflib.Literal(material[key].text) + return material + + expected_data["compiled_material"] = [build_component_dict( + component) for component in root.findall(".//MatrixComponent")] + expected_data["compiled_material"] += [build_component_dict( + component) for component in root.findall(".//FillerComponent")] + + def extract_choose_parameter(section): + if section is None: + return None + order = list() + for param in section.findall(".//ChooseParameter"): + for component in param: + order.append(component.tag) + return order + + expected_data["filler_processing"] = extract_choose_parameter(root.find(".//FillerProcessing")) + expected_data["solution_processing"] = extract_choose_parameter(root.find(".//SolutionProcessing")) + + # Table data + + def extract_table_data(data_tag): + if data_tag is None: + return None + if data_tag.find("data") is None: + return None + table = dict() # Holds the description, headers, and dataframe + table["description"] = data_tag.find(".//description").text + table["headers"] = [elem.text for elem in data_tag.find( + ".//headers").iter("column")] + data = dict() + for i, category in enumerate(table["headers"]): + data[category] = data_tag.find( + ".//rows").findall("row/column[@id='" + str(i) + "']") + data[category] = [float(elem.text) for elem in data[category]] + + table["data"] = pd.DataFrame(data) + return table + + expected_data["Dielectric_Real_Permittivity"] = [extract_table_data( + data) for data in root.iter("Dielectric_Real_Permittivity")] + expected_data["Dielectric_Loss_Permittivity"] = [extract_table_data( + data) for data in root.iter("Dielectric_Loss_Permittivity")] + expected_data["Dielectric_Loss_Tangent"] = [extract_table_data( + data) for data in root.iter("Dielectric_Loss_Tangent")] + expected_data["ElectricConductivity"] = [extract_table_data( + data) for data in root.iter("ElectricConductivity")] + + + # Other Data + expected_data["equipment"] = [elem.text.lower() + for elem in root.iter("EquipmentUsed")] + expected_data["equipment"] += [elem.text.lower() + for elem in root.iter("Equipment")] + expected_data["equipment"] = ["http://nanomine.org/ns/" + slugify.slugify(elem) + for elem in expected_data["equipment"]] + expected_data["values"] = [ + rdflib.Literal(val.text, datatype=rdflib.XSD.double) for val in root.iter("value")] + + expected_data["temps"] = [] + for node in root.iter("Temperature"): + expected_data["temps"] += [rdflib.Literal(val.text, datatype=rdflib.XSD.double) + for val in node.iter("value")] + return expected_data + + +def test_nanocomposites(runner): + # Ensure there is a nanocomposite in the graph + nanocomposites = list(runner.app.db.subjects( + rdflib.RDF.type, rdflib.URIRef("http://nanomine.org/ns/PolymerNanocomposite"))) + print(nanocomposites, len(runner.app.db)) + runner.assertEquals(len(nanocomposites), 1) + print("Correct Number of Nanocomposites") + + +def test_authors(runner, expected_authors=None): + # Ensure that the proper number of authors are in the graph + print("\n\nauthors") + authors = runner.app.db.query( + """SELECT ?name + WHERE { + ?paper ?author . + ?author ?name . + } + """ + ) + # for author in authors: + # print(author) + authors = [str(author[0]) for author in authors] + if expected_authors is None: + expected_authors = runner.expected_data["authors"] + runner.assertCountEqual(expected_authors, authors) + print("Expected Authors Found") + + +def test_language(runner, expected_language=None): + # Ensure the paper is marked as being in English + languages = list(runner.app.db.objects( + None, rdflib.URIRef("http://purl.org/dc/terms/language"))) + print("\n\nLanguage") + processed_langs = [str(language) for language in languages] + # print(processed_langs) + if expected_language is None: + expected_language = runner.expected_data["language"] + runner.assertCountEqual(expected_language, processed_langs) + print("Correct Language") + + +def test_keywords(runner, expected_keywords=None): + # Check how many keywords exist + print("\n\nKeywords") + keywords_lst = list(runner.app.db.objects( + None, rdflib.URIRef("http://www.w3.org/ns/dcat#keyword"))) + keywords = [str(keyword) for keyword in keywords_lst] + # print(keywords) + if expected_keywords is None: + expected_keywords = runner.expected_data["keywords"] + runner.assertCountEqual(expected_keywords, keywords) + print("Expected Keywords Found") + + +def test_devices(runner, expected_devices=None): + # Check if all used devices are showing up + print("\n\nDevices") + devices_lst = list(runner.app.db.subjects(rdflib.URIRef( + "http://www.w3.org/2000/01/rdf-schema#subClassOf"), rdflib.URIRef("http://semanticscience.org/resource/Device"))) + devices_lst = [str(device) for device in devices_lst] + if expected_devices is None: + expected_devices = runner.expected_data["equipment"] + runner.assertCountEqual(expected_devices, devices_lst) + print("Expected Devices Found") + + +def test_volume(runner, expected_volume=None): + # Checks the volume of the journal + print("Journal Volume") + volume = runner.app.db.query( + """ + SELECT ?volume + WHERE { + ?publication a . + ?publication ?volume . + } + """ + ) + volume = [vol[0] for vol in volume] + if expected_volume is None: + expected_volume = runner.expected_data["journ_vol"] + runner.assertCountEqual(expected_volume, volume) + print("Expected Journal Volume Found") + + +def test_matrix_chemical_names(runner, expected_names=None): + # Check if the names of the chemicals are present + print("\n\nMatrix Chemical Names") + names = runner.app.db.query( + """ + SELECT ?chemName WHERE { + ?matrix ?bnode . + ?matrix a ?chemURI . + ?bnode a . + ?chemURI ?chemName . + } + """ + ) + names = [name[0] for name in names] + if expected_names is None: + expected_names = runner.expected_data["m_name"] + runner.assertCountEqual(expected_names, names) + print("Expected Matrix Chemical Names found") + + + +# TODO Reimplement +@disable_test +def test_matrix_trade_names(runner, expected_names=None): + # Check if the names of the chemicals are present + print("\n\nMatrix Trade Names") + names = runner.app.db.query( + """ + SELECT ?trade + WHERE { + ?mat ?bnode_mat . + ?bnode_mat a . + ?mat ?prop . + ?prop a . + ?prop ?trade . + } + """ + ) + names = [name[0] for name in names] + if expected_names is None: + expected_names = runner.expected_data["m_trd_name"] + runner.assertCountEqual(expected_names, names) + print("Expected Matrix Chemical Trade Names found") + + +def test_filler_chemical_names(runner, expected_names=None): + # Check if the names of the chemicals are present + print("\n\nFiller Chemical Names") + names = runner.app.db.query( + """ + SELECT ?chemName WHERE { + ?Filler ?bnode . + ?Filler a ?chemURI . + ?bnode a . + ?chemURI ?chemName . + } + """ + ) + names = [name[0] for name in names] + if expected_names is None: + expected_names = runner.expected_data["f_name"] + runner.assertCountEqual(expected_names, names) + print("Expected Filler Chemical Names found") + + +# TODO Reimplement +@disable_test +def test_filler_trade_names(runner, expected_names=None): + # Check if the names of the chemicals are present + print("\n\nFiller Trade Names") + names = list(runner.app.db.query( + """ + SELECT ?trade + WHERE { + ?mat ?bnode_mat . + ?bnode_mat a . + ?mat ?prop . + ?prop a . + ?prop ?trade . + } + """ + )) + names = [name[0] for name in names] + if expected_names is None: + expected_names = runner.expected_data["f_trd_name"] + runner.assertCountEqual(expected_names, names) + print("Expected Filler Chemical Trade Names found") + + +# TODO Fix or remove +@disable_test +def test_temperatures(runner, expected_temperatures=None): + print("Checking if the expected temperatures are present") + temperatures = list(runner.app.db.objects( + None, rdflib.URIRef("http://purl.obolibrary.org/obo/PATO_0000146"))) + if expected_temperatures is None: + expected_temperatures = runner.expected_data["temps"] + runner.assertCountEqual(expected_temperatures, temperatures) + print("Expected Temperatures Found") + + +# TODO Reimplement +@disable_test +def test_abbreviations(runner, expected_abbreviations=None): + print("Checking if the expected abbreviations are present") + abbreviations = list(runner.app.db.query( + """ + SELECT ?abbrev + WHERE { + ?prop a . + ?prop ?abbrev . + } + """ + )) + abbreviations = [a[0] for a in abbreviations] + if expected_abbreviations is None: + expected_abbreviations = runner.expected_data["abbrev"] + runner.assertCountEqual(expected_abbreviations, abbreviations) + print("Expected Abbreviations Found") + + +# TODO Reimplement +@disable_test +def test_manufacturers(runner, expected_manufacturers=None): + print("Checking if the expected manufactures are present") + manufacturers = list(runner.app.db.query( + """ + SELECT ?manufac + WHERE { + ?prop a . + ?prop ?manufac . + } + """ + )) + manufacturers = [m[0] for m in manufacturers] + if expected_manufacturers is None: + expected_manufacturers = runner.expected_data["manufac"] + runner.assertCountEqual(expected_manufacturers, manufacturers) + print("Expected Manufactures Found") + + +# TODO Reimplement +@disable_test +def test_complete_material(runner, expected_materials=None): + materials = runner.app.db.query( + """ + SELECT ?abbrev ?manufac ?name ?trade + WHERE { + ?mat ?bnode_mat . + ?mat a ?compound . + { ?bnode_mat a } UNION { ?bnode_mat a } . + OPTIONAL {?mat ?bnode_abbrev . + ?bnode_abbrev a . + ?bnode_abbrev ?abbrev} . + + OPTIONAL {?mat ?bnode_manufac . + ?bnode_manufac a . + ?bnode_manufac ?manufac} . + + OPTIONAL {?compound ?name} . + + + OPTIONAL {?mat ?bnode_trade . + ?bnode_trade a . + ?bnode_trade ?trade} . + } + """ + ) + material_properties = list() + for material in materials: + material_dict = dict() + for key in material.labels.keys(): + material_dict[key] = material[key] + material_properties.append(material_dict) + + if expected_materials is None: + expected_materials = runner.expected_data["compiled_material"] + + runner.assertCountEqual(expected_materials, material_properties) + + +def test_dielectric_real_permittivity(runner, expected_frequency, expected_real_permittivity, descriptions): + print("Checking if the Dielectric Real Permittivity Table is as expected") + values = query_table(runner, "", "", **descriptions) + frequency = [v["independentVar"] for v in values] + real_permittivity = [v["dependentVar"] for v in values] + runner.assertCountEqual(expected_frequency, frequency) + runner.assertCountEqual(expected_real_permittivity, real_permittivity) + + +def test_dielectric_loss_tangent(runner, expected_frequency, expected_tan_delta, descriptions): + print("Checking if Dielectric Loss Tangent Table is as expected") + values = query_table(runner, "", "", **descriptions) + frequency = [v["independentVar"] for v in values] + tan_delta = [v["dependentVar"] for v in values] + runner.assertCountEqual(expected_frequency, frequency) + runner.assertCountEqual(expected_tan_delta, tan_delta) + +# TODO Fix or remove +@disable_test +def test_filler_processing(runner, expected_process=None): + print("Testing Filler Processing") + process = runner.app.db.query( + """ + SELECT ?method + WHERE { + ?sequence a . + ?sequence ?method . + } + """ + ) + if expected_process is None: + expected_process = runner.expected_data["filler_processing"] + runner.assertTrue(expected_process is not None) + runner.assertTrue(process is not None) + runner.assertCountEqual(expected_process, process) # TODO figure out how to query ordering in process order + + +# TODO Reimplement +@disable_test +def test_viscoelastic_measurement_mode(runner, expected_mode=None): + print("Testing viscoelastic measurement mode") + mode = list(runner.app.db.objects( + None, rdflib.URIRef("http://nanomine.org/ns/tensile"))) + if expected_mode is None: + expected_mode = runner.expected_data["viscoelastic_measurement_mode"] + runner.assertCountEqual(expected_mode, mode) + print("Expected mode Found") + +# TODO Add autoparsing +def test_tensile_loading_profile(runner, expected_strain=None, expected_stress=None): + print("Stress value") + values = query_table(runner, "", "") + + if expected_strain is None: + raise NotImplementedError + if expected_stress is None: + raise NotImplementedError + + stress = [value["dependentVar"] for value in values] + strain = [value["independentVar"] for value in values] + runner.assertCountEqual(expected_strain, strain) + runner.assertCountEqual(expected_stress, stress) + print("Expected Stress value Found") + +# TODO Add autoparsing +# TODO Verify node type, currently doesn't +def test_flexural_loading_profile(runner, expected_strain=None, expected_stress=None): + print("Testing Flexural Loading Profile") + values = query_table(runner, "", "") + print("Finished Query", flush=True) + if expected_strain is None: + raise NotImplementedError + if expected_stress is None: + raise NotImplementedError + + stress = [value["dependentVar"] for value in values] + strain = [value["independentVar"] for value in values] + + runner.assertCountEqual(expected_strain, strain) + runner.assertCountEqual(expected_stress, stress) + print("Expected Flexural Loading Profile Found") + + +# TODO Refactor to remove usage of specific bnodes +# TODO Reimplement +@disable_test +def test_melt_viscosity(runner, expected_value=None): + print("\n\nMelt Viscosity") + values = runner.app.db.query( + """ + SELECT ?value + WHERE { + ?value . + . + . + } + """ + ) + values = [value[0] for value in values] + if expected_value is None: + expected_authors = runner.expected_data["melt_viscosity_data"] + runner.assertCountEqual(expected_value, values) + print("Expected Melt Viscosity values found") + + +# TODO Add autoparsing +def test_rheometer_mode(runner, expected_modes=None): + print("\n\nTesting for Rheometer Mode") + modes = runner.app.db.objects(None, rdflib.URIRef("http://nanomine.org/ns/RheometerMode")) + modes = list(modes) + if expected_modes is None: + raise NotImplementedError + runner.assertCountEqual(expected_modes, modes) + print("Expected Rheometer Modes Found") + + +def test_specific_surface_area(runner, expected_area=None, expected_units=None): + print("\n\nTesting for specific surface area") + query_results = runner.app.db.query( + ''' + SELECT ?area ?unit_label + WHERE + { + ?aNode a . + ?aNode ?area . + ?aNode ?unit . + ?unit ?unit_label . + } + ''' + ) + surface_area =[result["area"] for result in query_results] + units = [result["unit_label"] for result in query_results] + if expected_area is None: + expected_area = runner.expected_data["specific_surface_area"] + if expected_units is None: + expected_units = runner.expected_data["specific_surface_area_units"] + runner.assertCountEqual(expected_area, surface_area) + runner.assertCountEqual(expected_units, units) + + +def test_shear_loading_profile(runner, expected_aspect_ratio, expected_number, descriptions, types): + print("Testing shear loading profile") + values = query_table(runner, types["y_type"], types["x_type"], **descriptions) + + number = [value["dependentVar"] for value in values] + aspect_ratio = [value["independentVar"] for value in values] + + runner.assertCountEqual(expected_aspect_ratio, aspect_ratio) + runner.assertCountEqual(expected_number, number) + + +def test_weibull_plot(runner, expected_breakdown, expected_failure, descriptions): + print("Testing Weibull Plot") + values = query_table(runner, "", "", **descriptions) + + breakdown = [value["independentVar"] for value in values] + failure = [value["dependentVar"] for value in values] + + runner.assertCountEqual(expected_breakdown, breakdown) + runner.assertCountEqual(expected_failure, failure) + + + +disabled.append("test_triples") # Prevent triples from being printed in CI +def print_triples(runner): + if os.getenv("CI") is None: + print("Printing SPO Triples") + for s, p, o in runner.app.db.triples((None, None, None)): + print(str(s.n3()) + " " + str(p.n3()) + " " + str(o.n3()) + " .") diff --git a/whyis/materialsmine/tests/interesting_files.txt b/whyis/materialsmine/tests/interesting_files.txt new file mode 100644 index 00000000..60d39f77 --- /dev/null +++ b/whyis/materialsmine/tests/interesting_files.txt @@ -0,0 +1 @@ +L138_S2_Zikry_2007 \ No newline at end of file diff --git a/whyis/materialsmine/tests/template.py b/whyis/materialsmine/tests/template.py new file mode 100644 index 00000000..15022bb7 --- /dev/null +++ b/whyis/materialsmine/tests/template.py @@ -0,0 +1,134 @@ +from . import ingest_tester +from whyis.test.agent_unit_test_case import AgentUnitTestCase +from base64 import b64encode +import autonomic + +class IngestTest(AgentUnitTestCase): + + upload_template = ''' a , + , + ; + "data:text/xml;charset=UTF-8;base64,%s" .''' + + def setUp(self): + # Initialization + self.login(*self.create_user("user@example.com", "password")) + + encoded_file = b64encode(self.data.encode('utf8')).decode('ascii') + + print ("XML length:", len(encoded_file)) + upload = self.upload_template % (encoded_file) + response = self.client.post("/pub", data=upload, content_type="text/turtle", follow_redirects=True) + self.assertEquals(response.status, '201 CREATED') + + response = self.client.post("/pub", data=open('/apps/nanomine-graph/setl/xml_ingest.setl.ttl', 'rb').read(), + content_type="text/turtle", follow_redirects=True) + self.assertEquals(response.status, '201 CREATED') + + setlmaker = autonomic.SETLMaker() + setlmaker.dry_run = False + results = self.run_agent(setlmaker) + + # confirm this is creating a SETL script for the XML file. + self.assertTrue(len(results) > 0) + + setlr = autonomic.SETLr() + setlr.dry_run = False + + print(len(self.app.db)) + for setlr_np in results: + setlr_results = self.run_agent(setlr, nanopublication=setlr_np) + +class IngestTestSetup(AgentUnitTestCase): + @classmethod + def setUpClass(cls): + print("Setting Up Class") + cls.maxDiff = None + cls.expected_data = ingest_tester.autoparse(cls.file_under_test) + + def setUp(self): + ingest_tester.setUp(self, self.file_under_test) + + def run_agent(self, agent, nanopublication=None): + app = self.app + agent.dry_run = True + agent.app = app + results = [] + if nanopublication is not None: + results.extend(agent.process_graph(nanopublication)) + elif agent.query_predicate == app.NS.whyis.globalChangeQuery: + results.extend(agent.process_graph(app.db)) + else: + print("Running as update agent") + for resource in agent.getInstances(app.db): + print(resource.identifier) + for np_uri, in app.db.query('''select ?np where { + graph ?assertion { ?e ?p ?o.} + ?np a np:Nanopublication; + np:hasAssertion ?assertion. +}''', initBindings={'e': resource.identifier}, initNs=app.NS.prefixes): + print(np_uri) + np = app.nanopub_manager.get(np_uri) + results.extend(agent.process_graph(np)) + return results + +class IngestTestTests(IngestTestSetup): + pass + +class OldIngestTestTests(IngestTestSetup): + def test_nanocomposites(self): + ingest_tester.test_nanocomposites(self) + + def test_authors(self): + ingest_tester.test_authors(self, self.expected_data["authors"]) + + def test_language(self): + ingest_tester.test_language(self, self.expected_data["language"]) + + def test_keywords(self): + ingest_tester.test_keywords(self, self.expected_data["keywords"]) + + def test_devices(self): + ingest_tester.test_devices(self, self.expected_data["equipment"]) + + def test_volume(self): + ingest_tester.test_volume(self, self.expected_data["journ_vol"]) + + def test_matrix_chemical_names(self): + ingest_tester.test_matrix_chemical_names(self) + + def test_matrix_trade_names(self): + ingest_tester.test_matrix_trade_names(self) + + def test_filler_chemical_names(self): + ingest_tester.test_filler_chemical_names(self) + + def test_filler_trade_names(self): + ingest_tester.test_filler_trade_names(self) + + # TODO Fix or remove + def test_temperatures(self): + ingest_tester.test_temperatures(self) + + def test_abbreviations(self): + ingest_tester.test_abbreviations(self) + + def test_manufacturers(self): + ingest_tester.test_manufacturers(self) + + def test_complete_material(self): + ingest_tester.test_complete_material(self) + + # TODO Fix or remove + def test_filler_processing(self): + ingest_tester.test_filler_processing(self) + + def test_viscoelastic_measurement_mode(self): + ingest_tester.test_viscoelastic_measurement_mode(self) + + # TODO add the following tests once completed + # test_stress + # test_melt_viscosity + # test_rheometer_mode + # test_specific_surface_area + # test_dielectric_real_permittivity diff --git a/whyis/materialsmine/tests/test_L101_S11_Dang_2007.py b/whyis/materialsmine/tests/test_L101_S11_Dang_2007.py new file mode 100644 index 00000000..f60bbe81 --- /dev/null +++ b/whyis/materialsmine/tests/test_L101_S11_Dang_2007.py @@ -0,0 +1,14 @@ +from . import ingest_tester +from . import template + +file_under_test = "L101_S11_Dang_2007" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_L101_S3_Dang_2007.py b/whyis/materialsmine/tests/test_L101_S3_Dang_2007.py new file mode 100644 index 00000000..a184a642 --- /dev/null +++ b/whyis/materialsmine/tests/test_L101_S3_Dang_2007.py @@ -0,0 +1,35 @@ +import rdflib + +from . import ingest_tester +from . import template + +class L101_S3_Dang_2007(template.IngestTestSetup): + @classmethod + def setUpClass(cls): + cls.file_under_test = "L101_S3_Dang_2007" + super().setUpClass() + + def no_test_chemprops_id(self): + print (len(self.app.db)) + component_types = [x.asdict() for x in self.app.db.query(''' + SELECT ?sample ?part ?parttype ?role WHERE { + ?sample a . + ?sample /? ?part. + ?part a ?parttype. +# [ +# a ?role; +# ?sample +# ]. + }''')] + print (component_types) + + + + def no_test_specific_surface_area(self): + expected_surface_area = [rdflib.Literal(9.0)] + expected_units = [rdflib.Literal("m^2/g")] + ingest_tester.test_specific_surface_area(self, expected_surface_area, expected_units) + ingest_tester.test_specific_surface_area(self) + + def no_test_print_triples(self): + ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_L102_S3_Hu_2007.py b/whyis/materialsmine/tests/test_L102_S3_Hu_2007.py new file mode 100644 index 00000000..26ca4a29 --- /dev/null +++ b/whyis/materialsmine/tests/test_L102_S3_Hu_2007.py @@ -0,0 +1,84 @@ +from . import ingest_tester +from . import template +import rdflib + + +class L102Test(template.IngestTestSetup): + @classmethod + def setUpClass(cls): + cls.file_under_test = "L102_S3_Hu_2007" + super().setUpClass() + + def no_test_authors(self): + expected_authors = ["Hu, Tao", + "Juuti, Jari", + "Vilkman, Taisto", + "Jantunen, Heli"] + ingest_tester.test_authors(self, expected_authors) + ingest_tester.test_authors(self) + + def no_test_language(self): + ingest_tester.test_language(self, ["http://nanomine.org/language/english"]) + ingest_tester.test_language(self) + + def no_test_keywords(self): + expected_keywords = ["Composites", + "Dielectric Properties", + "Microstructure-Final", + "Bst-Coc"] + ingest_tester.test_keywords(self, expected_keywords) + ingest_tester.test_keywords(self) + + def no_test_devices(self): + expected_devices = ["http://nanomine.org/ns/jeol-jsm-6400", + "http://nanomine.org/ns/agilent-e4991a", + "http://nanomine.org/ns/siemens-d5000"] + ingest_tester.test_devices(self, expected_devices) + ingest_tester.test_devices(self) + + def no_test_volume(self): + excepted_volume = [rdflib.Literal(27)] + ingest_tester.test_volume(self, excepted_volume) + ingest_tester.test_volume(self) + + def no_test_matrix_chemical_names(self): + expected_names = [rdflib.Literal("cyclo olefin copolymer")] + ingest_tester.test_matrix_chemical_names(self, expected_names) + ingest_tester.test_matrix_chemical_names(self) + + def no_test_matrix_trade_names(self): + expected_names = [rdflib.Literal("Topas 8007S-04")] + ingest_tester.test_matrix_trade_names(self, expected_names) + ingest_tester.test_matrix_trade_names(self) + + def no_test_filler_chemical_names(self): + expected_names = [rdflib.Literal("barium strontium titanate")] + ingest_tester.test_filler_chemical_names(self, expected_names) + ingest_tester.test_filler_chemical_names(self) + + def no_test_filler_trade_names(self): + expected_names = [] + ingest_tester.test_filler_trade_names(self, expected_names) + ingest_tester.test_filler_trade_names(self) + + def no_test_complete_material(self): + expected_material = list() + expected_material.append({"abbrev": rdflib.Literal("COC"), + "manufac": rdflib.Literal("Ticona GmbH, Germany"), + "name": rdflib.Literal("cyclo olefin copolymer"), + "trade": rdflib.Literal("Topas 8007S-04")}) + + expected_material.append({"abbrev": rdflib.Literal("BST"), + "manufac": rdflib.Literal("Sigma–Aldrich Chemie GmbH, Germany"), + "name": rdflib.Literal("barium strontium titanate"), + "trade": None}) + + ingest_tester.test_complete_material(self, expected_material) + + + def no_test_manufacturer(self): + ingest_tester.test_manufacturers(self) + + + # def test_print_triples(self): + # ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_L104_S4_He_2009.py b/whyis/materialsmine/tests/test_L104_S4_He_2009.py new file mode 100644 index 00000000..3e35e001 --- /dev/null +++ b/whyis/materialsmine/tests/test_L104_S4_He_2009.py @@ -0,0 +1,14 @@ +from . import ingest_tester +from . import template + +file_under_test = "L104_S4_He_2009" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_L141_S19_Gao_2013.py b/whyis/materialsmine/tests/test_L141_S19_Gao_2013.py new file mode 100644 index 00000000..9da0482c --- /dev/null +++ b/whyis/materialsmine/tests/test_L141_S19_Gao_2013.py @@ -0,0 +1,14 @@ +from . import ingest_tester +from . import template + +file_under_test = "L141_S19_Gao_2013" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_L150_S7_Akcora_2009.py b/whyis/materialsmine/tests/test_L150_S7_Akcora_2009.py new file mode 100644 index 00000000..3a848a13 --- /dev/null +++ b/whyis/materialsmine/tests/test_L150_S7_Akcora_2009.py @@ -0,0 +1,15 @@ +import rdflib + +from . import ingest_tester, template + +file_under_test = "L150_S7_Akcora_2009" + +# TODO Add test for shear loading profile +class Test_L150_S7_Akcora_2009(template.IngestTestSetup): + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_L155_S2_Roy_2005.py b/whyis/materialsmine/tests/test_L155_S2_Roy_2005.py new file mode 100644 index 00000000..e31b9a41 --- /dev/null +++ b/whyis/materialsmine/tests/test_L155_S2_Roy_2005.py @@ -0,0 +1,182 @@ +from . import ingest_tester +from . import template +import rdflib + +file_under_test = "L155_S2_Roy_2005" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) + + def no_test_dielectric_real_permittivity(self): + frequency = [ + 0.002078949, + 0.005239995, + 0.013207416, + 0.033289313, + 0.082305244, + 0.203493333, + 0.512905286, + 1.292778627, + 3.258450684, + 7.902591204, + 20.30583336, + 50.20459806, + 126.540773, + 318.9462293, + 773.5276395, + 1949.677704, + 4914.165902, + 12386.16334, + 30623.82819, + 78688.41195, + 190839.8845, + 481012.2468, + ] + + real_permittivity = [ + 3.21, + 2.88, + 2.595, + 2.385, + 2.2425, + 2.175, + 2.1, + 2.055, + 2.025, + 2.01, + 1.995, + 1.965, + 1.95, + 1.95, + 1.95, + 1.935, + 1.9275, + 1.935, + 1.9275, + 1.92, + 1.92, + 1.905, + ] + frequency = [rdflib.Literal(f) for f in frequency] + real_permittivity = [rdflib.Literal(p) for p in real_permittivity] + + descriptions = {} + descriptions["measurement_description"] = rdflib.Literal("Measured at 25 Celsius") + descriptions["x_description"] = rdflib.Literal("Frequency (Hz)") + descriptions["y_description"] = rdflib.Literal("Real Part of Dielectric Permittivity") + + ingest_tester.test_dielectric_real_permittivity(self, frequency, real_permittivity, descriptions) + + def no_test_dielectric_loss_tangent(self): + return + frequency = [ + 0.002132876, + 0.005323618, + 0.013287653, + 0.033643142, + 0.08278107, + 0.209594224, + 0.523143327, + 1.305756117, + 3.25914324, + 8.134761557, + 20.30421516, + 50.67894742, + 126.4937202, + 315.7259981, + 788.0462816, + 1966.949018, + 4909.468555, + 12430.33287, + 30585.61668, + 77440.03084, + 190546.0718, + 489390.0918, + ] + + tan_delta = [ + 0.189265537, + 0.152777778, + 0.12405838, + 0.093691149, + 0.066148776, + 0.045433145, + 0.032015066, + 0.02306968, + 0.016949153, + 0.013182674, + 0.010122411, + 0.007768362, + 0.006355932, + 0.005178908, + 0.004237288, + 0.003766478, + 0.003295669, + 0.003060264, + 0.002589454, + 0.002589454, + 0.002354049, + 0.002354049, + ] + + frequency = [rdflib.Literal(f) for f in frequency] + tan_delta = [rdflib.Literal(t) for t in tan_delta] + + descriptions = {} + descriptions["measurement_description"] = rdflib.Literal("Measured at 25 Celsius") + descriptions["x_description"] = rdflib.Literal("Frequency (Hz)") + descriptions["y_description"] = rdflib.Literal("tan delta") + + ingest_tester.test_dielectric_loss_tangent(self, frequency, tan_delta, descriptions) + + def no_test_weibull_plot(self): + breakdown_strength = [ + 134.3096058, + 135.4974638, + 136.6958274, + 137.9047896, + 145.3864394, + 150.5983687, + 168.8625957, + 208.5987317, + 271.6654549, + 281.4043353, + 460.765468, + 554.3522963, + 559.2550864, + 940.2240538, + ] + + failure_probability = [ + 12.5086297, + 18.69779897, + 24.93299398, + 31.18775889, + 37.44027712, + 43.73113085, + 49.92556641, + 56.22166161, + 62.45004225, + 68.73755053, + 74.97001936, + 81.0239571, + 87.5667591, + 93.3498204, + ] + + breakdown_strength = [rdflib.Literal(b) for b in breakdown_strength] + failure_probability = [rdflib.Literal(f) for f in failure_probability] + + descriptions = {} + descriptions["measurement_description"] = rdflib.Literal("Measured at 25 Celsius") + descriptions["x_description"] = rdflib.Literal("Frequency (Hz)") + descriptions["y_description"] = rdflib.Literal("tan delta") + + ingest_tester.test_weibull_plot(self, breakdown_strength, failure_probability, {}) diff --git a/whyis/materialsmine/tests/test_L157_S5_Zhao_2008.py b/whyis/materialsmine/tests/test_L157_S5_Zhao_2008.py new file mode 100644 index 00000000..92cd135f --- /dev/null +++ b/whyis/materialsmine/tests/test_L157_S5_Zhao_2008.py @@ -0,0 +1,20 @@ +from . import template +from . import ingest_tester + +class L157_S5_Zhao_2008(template.IngestTestSetup): + @classmethod + def setUpClass(cls): + cls.file_under_test = "L157_S5_Zhao_2008" + super().setUpClass() + + # def test_triples(self): + # ingest_tester.print_triples(self) + + def no_test_filler_trade_names(self): + ingest_tester.test_filler_trade_names(self) + + def no_test_matrix_trade_names(self): + ingest_tester.test_matrix_trade_names(self) + + def no_test_complete_material(self): + ingest_tester.test_complete_material(self) diff --git a/whyis/materialsmine/tests/test_L168_S4_Luo_2013.py b/whyis/materialsmine/tests/test_L168_S4_Luo_2013.py new file mode 100644 index 00000000..4a13a8e1 --- /dev/null +++ b/whyis/materialsmine/tests/test_L168_S4_Luo_2013.py @@ -0,0 +1,63 @@ +from . import ingest_tester +from . import template +import rdflib + +file_under_test = "L168_S4_Luo_2013" + +class L168Test(template.IngestTestTests): + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_authors(self): + expected_authors = ["Luo, Suibin", + "Yu, Shuhui", + "Sun, Rong", + "Wong, Ching-Ping"] + ingest_tester.test_authors(self, expected_authors) + ingest_tester.test_authors(self) + + def no_test_language(self): + ingest_tester.test_language(self, ["http://nanomine.org/language/english"]) + ingest_tester.test_language(self) + + def no_test_keywords(self): + expected_keywords = ["Ag-Deposited Batio3", + "Hetero-Epitaxial Interface", + "Polymer Matrix", + "Dielectric Composites"] + ingest_tester.test_keywords(self, expected_keywords) + ingest_tester.test_keywords(self) + + def no_test_devices(self): + expected_devices = ["http://nanomine.org/ns/cs9912bx", + "http://nanomine.org/ns/agilent-4294a-impedance-analyzer", + "http://nanomine.org/ns/xrd-d-max-2500-pc-rigaku-co", + "http://nanomine.org/ns/fei-nova-nanosem450", + "http://nanomine.org/ns/fei-tecnai-spirit"] + ingest_tester.test_devices(self, expected_devices) + ingest_tester.test_devices(self) + + def no_test_abbreviations(self): + expected_abbreviations = ["PVDF", + "AgNO3", + "BaTiO3"] + expected_abbreviations = [rdflib.Literal(v) for v in expected_abbreviations] + ingest_tester.test_abbreviations(self, expected_abbreviations) + ingest_tester.test_abbreviations(self) + + # def test_filler_processing(self): + # ingest_tester.test_filler_processing(self) + + def no_test_manufacturers(self): + expected_manufacturers = ["Shanghai 3F Co.", + "Guoyao Chemical Co. China", + "Shanghai Lingfeng Chemical Co. China", + "Shangdong Guoci Functional Materials Co., China"] + expected_manufacturers = [rdflib.Literal(v) for v in expected_manufacturers] + # ingest_tester.test_manufacturers(self, expected_manufacturers) + ingest_tester.test_manufacturers(self) + + def no_test_complete_material(self): + ingest_tester.test_complete_material(self) diff --git a/whyis/materialsmine/tests/test_L172_S18_Huo_2015.py b/whyis/materialsmine/tests/test_L172_S18_Huo_2015.py new file mode 100644 index 00000000..ec003514 --- /dev/null +++ b/whyis/materialsmine/tests/test_L172_S18_Huo_2015.py @@ -0,0 +1,8 @@ +from . import ingest_tester +from . import template + +class L172Test(template.IngestTestTests): + @classmethod + def setUpClass(cls): + cls.file_under_test = "L172_S18_Huo_2015" + super().setUpClass() diff --git a/whyis/materialsmine/tests/test_L199_S1_Duncan_2010.py b/whyis/materialsmine/tests/test_L199_S1_Duncan_2010.py new file mode 100644 index 00000000..6cffdc43 --- /dev/null +++ b/whyis/materialsmine/tests/test_L199_S1_Duncan_2010.py @@ -0,0 +1,129 @@ +import rdflib + +from . import ingest_tester, template + +file_under_test = "L199_S1_Duncan_2010" + +# TODO Add test for shear loading profile +class Test_L199_S1_Duncan_2010(template.IngestTestSetup): + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) + + def no_test_shear_loading_profile_1(self): + descriptions = {} + descriptions["measurement_description"] = rdflib.Literal("Number of MWNT within grip region dissolved in THF") + descriptions["x_description"] = rdflib.Literal("Aspect ratio (L/d)") + descriptions["y_description"] = rdflib.Literal("Number of MWNT within grip region dissolved in THF") + + types = {} + types["y_type"] = "" + types["x_type"] = "" + + aspect_ratio = [ + "0-199", + "200-399", + "400-599", + "600-799", + "800-999", + "1000-1199", + "1200-1399", + "1400-1599", + "1600-1799", + "1800-1999", + ">2000", + ] + + number = [ + 0.0, + 0.0, + 0.0, + 0.0, + 18.4393465415, + 17.0142509559, + 10.4362182829, + 16.7014250956, + 11.9742787626, + 22.540841154, + 21.8456725756, + ] + + aspect_ratio = [rdflib.Literal(a, datatype=rdflib.XSD.double) for a in aspect_ratio] + number = [rdflib.Literal(n) for n in number] + ingest_tester.test_shear_loading_profile(self, aspect_ratio, number, descriptions, types) + + def no_test_shear_loading_profile_2(self): + descriptions = {} + descriptions["measurement_description"] = rdflib.Literal("Number of MWNT along the fracture edge dissolved in THF") + descriptions["x_description"] = rdflib.Literal("Aspect ratio (L/d)") + descriptions["y_description"] = rdflib.Literal("Number of MWNT along the fracture edge dissolved in THF") + + types = {} + types["y_type"] = "" + types["x_type"] = "" + + aspect_ratio = [ + "0-49.99", + "50-99.99", + "100-149.99", + "150-199.99", + "200-249.99", + "250-299.99", + "300-349.99", + "350-399.99", + ">400", + ] + + number = [ + 0.0, + 0.0, + 3.09094256259, + 0.0, + 7.79270986745, + 13.9304123711, + 34.486377025, + 43.1148748159, + 11.1800441826, + ] + + aspect_ratio = [rdflib.Literal(a, datatype=rdflib.XSD.double) for a in aspect_ratio] + number = [rdflib.Literal(n) for n in number] + ingest_tester.test_shear_loading_profile(self, aspect_ratio, number, descriptions, types) + + def no_test_shear_loading_profile_3(self): + descriptions = {} + descriptions["measurement_description"] = rdflib.Literal("Number of MWNT along the fracture for ARNT/PC") + descriptions["x_description"] = rdflib.Literal("Aspect ratio (L/d)") + descriptions["y_description"] = rdflib.Literal("Number of MWNT along the fracture for ARNT/PC") + + types = {} + types["y_type"] = "" + types["x_type"] = "" + + aspect_ratio = [ + "0-16", + "16-31", + "32-48", + "49-64", + "65-80", + "81-96", + ">97", + ] + + number = [ + 0.0, + 8.95470779757, + 16.0864952961, + 29.1779569873, + 27.8728191726, + 14.8469887788, + 23.6376183327, + ] + + aspect_ratio = [rdflib.Literal(a, datatype=rdflib.XSD.double) for a in aspect_ratio] + number = [rdflib.Literal(n) for n in number] + ingest_tester.test_shear_loading_profile(self, aspect_ratio, number, descriptions, types) diff --git a/whyis/materialsmine/tests/test_L203_S9_Ma_2009.py b/whyis/materialsmine/tests/test_L203_S9_Ma_2009.py new file mode 100644 index 00000000..af0f6266 --- /dev/null +++ b/whyis/materialsmine/tests/test_L203_S9_Ma_2009.py @@ -0,0 +1,365 @@ +from . import ingest_tester +from . import template +import rdflib + +file_under_test = "L203_S9_Ma_2009" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) + + def no_test_flexural_loading_profile(self): + strain = [ + 0.0455199451544, + 0.0984788280365, + 0.179423054029, + 0.1570619867, + 0.224083753163, + 0.341314431514, + 0.433387994902, + 0.491957257436, + 0.550558700481, + 0.620298988801, + 0.684450107351, + 0.753087481772, + 0.832297373221, + 0.843503017436, + 0.922369928714, + 0.893651956553, + 0.996215269668, + 1.0476737362, + 1.11125833147, + 1.16150351957, + 1.24238777279, + 1.21165977244, + 1.31216477615, + 1.29535250667, + 1.39583469147, + 1.37066368038, + 1.46276723015, + 1.44597485409, + 1.54090004963, + 1.53384593521, + 1.61337348731, + 1.64019535865, + 1.71380081897, + 1.68028115923, + 1.75063185335, + 1.79742407255, + 1.91449092284, + 1.8893155235, + 1.96461353245, + 2.02317913811, + 2.10410142284, + 2.09848153531, + 2.16548136052, + 2.17795715977, + 2.25468573874, + 2.24070915744, + 2.32156561841, + 2.39127226346, + 2.46655754649, + 2.550199377, + 2.61990675343, + 2.70075151239, + 2.77184667339, + 2.85367831878, + 2.92028915683, + 2.99943221451, + 3.08172391236, + 3.17145293044, + 3.25267459145, + 3.33630073571, + 3.41434558119, + 3.50352948091, + 3.58991513886, + 3.65403597848, + 3.73761637347, + 3.80451790184, + 3.8936816156, + 3.97449126855, + 4.05530238424, + 4.13889916204, + 4.22248306764, + 4.30607399443, + 4.39174451366, + 4.47324882683, + 4.56160965772, + 4.64039908501, + 4.7184110813, + 4.8075528538, + 4.89672549034, + 4.94549030177, + 4.97468731428, + 5.05826653907, + 5.14556836645, + 5.22261533745, + 5.29704844291, + 5.34794526547, + 5.40686130437, + 5.49836185265, + 5.5691956863, + 5.65990138987, + 5.74106323135, + 5.82701039849, + 5.91532007491, + 5.99410555974, + 6.07765679724, + 6.16675790528, + 6.25031314097, + 6.32829793009, + 6.41184380417, + 6.4953765135, + 6.57892268013, + 6.66246094791, + 6.74599453489, + 6.82953982387, + 6.91307809165, + 6.99662513593, + 7.08016340371, + 7.16369640559, + 7.24720834386, + 7.25047759129, + 7.26382226436, + 7.26373449933, + 7.2636467343, + 7.26355896926, + 7.26347120423, + 7.2633834392, + 7.26329567417, + 7.26320790914, + 7.26312014411, + 7.26303237907, + 7.26294461404, + 7.26285684901, + 7.26276908398, + 7.26268131895, + 7.26259355392, + 7.26250578888, + 7.26241802385, + 7.26233025882, + 7.26224249379, + 7.26215472876, + 7.26206696373, + 7.26197919869, + 7.26189143366, + 7.26180366863, + 7.2617159036, + 7.26162813857, + 7.26154037354, + 7.2614526085, + 7.26136484347, + 7.26127707844, + 7.26118931341, + 7.26110154838, + 7.26101378334, + 7.26092601831, + 7.26083825328, + 7.26075048825, + 7.26066272322, + 7.26057495819, + 7.26048719315, + 7.26039942812, + 7.26031166309, + 7.26022389806, + 7.26013613303, + 7.260048368, + 7.25996060296, + 7.25987283793, + 7.2597850729, + 7.25969730787, + 7.25960954284, + 7.25952177781, + 7.25943401277, + 7.25934624774, + 7.25925848271, + 7.25917071768, + 7.25908295265, + 7.25899518762, + 7.25890742258, + 0.255895025071, + 0.298562831401 + ] + + + stress = [ + 0.97757885763, + 1.81445012788, + 5.30622335891, + 3.71905370844, + 7.26854219949, + 12.347485081, + 15.622826087, + 17.2532821824, + 19.5186061381, + 21.7550724638, + 23.6163895993, + 26.072173913, + 28.3153736857, + 29.6043478261, + 31.360540738, + 29.9506393862, + 34.1277813299, + 35.5836487639, + 37.2573913043, + 39.502514919, + 41.8111253197, + 39.9930946292, + 44.7719181586, + 42.76342711, + 47.0920716113, + 45.0143222506, + 48.8812446718, + 47.2652173913, + 51.8535805627, + 50.0499786871, + 53.065601023, + 54.7451150895, + 56.312084399, + 54.3641943734, + 57.6539641944, + 57.7116794544, + 59.5585677749, + 57.3942455243, + 59.3854219949, + 60.9437340153, + 64.0026427962, + 63.021483376, + 66.1381074169, + 65.0126598465, + 67.7541346974, + 66.7441176471, + 68.5044330776, + 70.077173913, + 71.8172890026, + 73.5833759591, + 75.1705456095, + 76.7, + 78.1933823529, + 79.5692729266, + 80.8987851662, + 82.2159298502, + 83.510400682, + 85.0109974425, + 86.1268258028, + 87.5834490318, + 88.8202046036, + 90.0322250639, + 90.9845268542, + 92.2484910486, + 92.8025575448, + 93.9799488491, + 94.7937340153, + 95.6306052856, + 96.4963341858, + 97.3736061381, + 97.9969309463, + 98.7587723785, + 99.3388107417, + 100.143938619, + 100.81673365, + 101.044296675, + 101.632992327, + 102.013913043, + 103.003729753, + 103.515952685, + 102.602608696, + 103.133589088, + 103.845410628, + 103.710741688, + 104.337364511, + 103.739599318, + 104.362099622, + 104.182082978, + 104.444549994, + 104.282122762, + 104.217811472, + 104.368695652, + 104.032298137, + 104.182082978, + 104.160920716, + 103.739599318, + 103.797314578, + 103.849258312, + 103.72228474, + 103.335592498, + 103.214390452, + 102.937357204, + 102.56797954, + 102.429462916, + 102.152429668, + 102.048542199, + 101.771508951, + 101.390588235, + 100.594117647, + 0.256138107417, + 98.6895140665, + 96.958056266, + 95.2265984655, + 93.495140665, + 91.7636828645, + 90.0322250639, + 88.3007672634, + 86.5693094629, + 84.8378516624, + 83.1063938619, + 81.3749360614, + 79.6434782609, + 77.9120204604, + 76.1805626598, + 74.4491048593, + 72.7176470588, + 70.9861892583, + 69.2547314578, + 67.5232736573, + 65.7918158568, + 64.0603580563, + 62.3289002558, + 60.5974424552, + 58.8659846547, + 57.1345268542, + 55.4030690537, + 53.6716112532, + 51.9401534527, + 50.2086956522, + 48.4772378517, + 46.7457800512, + 45.0143222506, + 43.2828644501, + 41.5514066496, + 39.8199488491, + 38.0884910486, + 36.3570332481, + 34.6255754476, + 32.8941176471, + 31.1626598465, + 29.431202046, + 27.6997442455, + 25.968286445, + 24.2368286445, + 22.505370844, + 20.7739130435, + 19.042455243, + 17.3109974425, + 15.5795396419, + 13.8480818414, + 12.1166240409, + 10.3851662404, + 8.6537084399, + 6.92225063939, + 5.19079283887, + 3.45933503836, + 1.72787723785, + 8.38235294118, + 10.1470588235, + ] + + strain = [rdflib.Literal(s) for s in strain] + stress = [rdflib.Literal(s) for s in stress] + ingest_tester.test_flexural_loading_profile(self, strain, stress) diff --git a/whyis/materialsmine/tests/test_L217_S2_Ash_2002.py b/whyis/materialsmine/tests/test_L217_S2_Ash_2002.py new file mode 100644 index 00000000..c265e4ce --- /dev/null +++ b/whyis/materialsmine/tests/test_L217_S2_Ash_2002.py @@ -0,0 +1,14 @@ +from . import ingest_tester +from . import template + +file_under_test = "L217_S2_Ash_2002" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_L254_S35_Castillo_2011.py b/whyis/materialsmine/tests/test_L254_S35_Castillo_2011.py new file mode 100644 index 00000000..7d3c9fa1 --- /dev/null +++ b/whyis/materialsmine/tests/test_L254_S35_Castillo_2011.py @@ -0,0 +1,24 @@ +import rdflib +from . import ingest_tester +from . import template + +file_under_test = "L254_S35_Castillo_2011" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) + + def no_test_non_spherical_shape(self): + width_description = rdflib.Literal("50th percentile value measured by TEM, diameter") + length_description = rdflib.Literal("50th percentile value measured by TEM") + depth_description = rdflib.Literal("50th percentile value measured by TEM, diameter") + expected_width_value = rdflib.Literal(10.5) + expected_length_value = rdflib.Literal(727.0) + expected_depth_value = rdflib.Literal(10.5) + ingest_tester.test_non_spherical_shape(self, width_description, expected_width_value, length_description, expected_length_value, depth_description, expected_depth_value) diff --git a/whyis/materialsmine/tests/test_L256_S3_Potschke_2004.py b/whyis/materialsmine/tests/test_L256_S3_Potschke_2004.py new file mode 100644 index 00000000..2bd069a4 --- /dev/null +++ b/whyis/materialsmine/tests/test_L256_S3_Potschke_2004.py @@ -0,0 +1,18 @@ +import rdflib + +from . import ingest_tester, template + +file_under_test = "L256_S3_Potschke_2004" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) + + def no_test_melt_viscosity(self): + ingest_tester.test_melt_viscosity(self, [rdflib.Literal(1793550.45609)]) diff --git a/whyis/materialsmine/tests/test_L260_S5_Haggenmueller_2006.py b/whyis/materialsmine/tests/test_L260_S5_Haggenmueller_2006.py new file mode 100644 index 00000000..0d9ebc8c --- /dev/null +++ b/whyis/materialsmine/tests/test_L260_S5_Haggenmueller_2006.py @@ -0,0 +1,14 @@ +from . import ingest_tester +from . import template + +file_under_test = "L260_S5_Haggenmueller_2006" + +class IngestTestRunner(template.IngestTestSetup): + first_run = bool() + @classmethod + def setUpClass(cls): + cls.file_under_test = file_under_test + super().setUpClass() + + def no_test_triples(self): + ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_L300_S5_Nakane_1999.py b/whyis/materialsmine/tests/test_L300_S5_Nakane_1999.py new file mode 100644 index 00000000..15f12f84 --- /dev/null +++ b/whyis/materialsmine/tests/test_L300_S5_Nakane_1999.py @@ -0,0 +1,66 @@ +from . import ingest_tester +from . import template +import rdflib + +class L300_S5_Nakane_1999(template.IngestTestSetup): + @classmethod + def setUpClass(cls): + cls.file_under_test = "L300_S5_Nakane_1999" + super().setUpClass() + + # def test_viscoelastic_measurement_mode(self): + # expected_properties = ["tensile"] + # ingest_tester.test_viscoelastic_measurement_mode(self, expected_properties) + # ingest_tester.test_viscoelastic_measurement_mode(self) + + def no_test_tensile_loading_profile(self): + strain = [ + 0.488947522403, + 0.206702455438, + 0.0792094406024, + 0.458310507435, + 0.160242593969, + 0.90212884315, + 0.940644788598, + 1.3802561525, + 1.22448532952, + 0.93220689301, + 1.80212313252, + 1.9786885736, + 1.79906431079, + 2.00943420192, + 2.30809720581, + 2.1881058389, + 2.54316050748, + 2.71920844731, + 2.81124282387, + 2.90484571504 + ] + stress = [ + 24.9897478167, + 10.2678907707, + 4.02476970038, + 19.158611338, + 15.5440079659, + 41.2782263019, + 32.5323892337, + 60.5980280682, + 51.9931198677, + 47.4921877784, + 79.3363291472, + 73.9835174962, + 67.1880712416, + 88.0281205131, + 99.0291856973, + 94.3884072907, + 106.063545902, + 111.225327822, + 115.638172539, + 120.767514725 + ] + strain = [rdflib.Literal(val) for val in strain] + stress = [rdflib.Literal(val) for val in stress] + ingest_tester.test_tensile_loading_profile(self, strain, stress) + + def no_test_triples(self): + ingest_tester.print_triples(self) diff --git a/whyis/materialsmine/tests/test_article_metadata.py b/whyis/materialsmine/tests/test_article_metadata.py new file mode 100644 index 00000000..dab6aa33 --- /dev/null +++ b/whyis/materialsmine/tests/test_article_metadata.py @@ -0,0 +1,62 @@ +import rdflib + +from . import template + +SKOS = rdflib.Namespace("http://www.w3.org/2004/02/skos/core#") + +class TestArticleMetadata(template.IngestTest): + + data = ''' + + L101_S3_Dang_2007 + L101_S1_Dang_2007 + PNC_schema_010720 + 5e496fa88aba2cf1302d73e3 + 5e4c1081c941bb7a1270dd9d + + + + research article + Composites Science and Technology + Study on microstructure and dielectric property of the BaTiO3/epoxy resin composites + Dang, Zhi-Min + Yu, Yan-Fei + Xu, Hai-Ping + Bai, Jinbo + Dielectric properties + Microstructure + Silane coupling agent + BaTiO3 + Elsevier + 2008 + 10.1016/j.compscitech.2007.05.021 + 68 + https://www.sciencedirect.com/science/article/pii/S0266353807002199?via%3Dihub + English + Key Laboratory of Beijing City on Preparation and Processing of Novel Polymer Materials and Key Laboratory of the Ministry of Education on Nanomaterials, Beijing University of Chemical Technology, Beijing 100029, PR China + 2015-07-24 + + + + 0266-3538 + 1 + + + + + +''' + + def test_author_list(self): + first_author = set(self.app.db.query('''select distinct ?firstAuthor where { + ?pub bibo:authorList/rdf:first ?firstAuthor. + }''', initNs={"bibo": rdflib.URIRef('http://purl.org/ontology/bibo/'), 'rdf': rdflib.RDF})) + print ("First Author:") + print ('\n'.join(['\t'.join(x) for x in first_author])) + self.assertIn((rdflib.URIRef('http://nanomine.org/author/bai-jinbo'),), first_author) + last_author = set(self.app.db.query('''select distinct ?lastAuthor where { + ?pub bibo:authorList/rdf:rest* [rdf:first ?lastAuthor; rdf:rest rdf:nil]. + }''', initNs={"bibo": rdflib.URIRef('http://purl.org/ontology/bibo/'), 'rdf': rdflib.RDF})) + print ("Last Author:") + print ('\n'.join(['\t'.join(x) for x in last_author])) + self.assertIn((rdflib.URIRef('http://nanomine.org/author/dang-zhi-min'),), last_author) diff --git a/whyis/materialsmine/tests/test_chem_props_ingest.py b/whyis/materialsmine/tests/test_chem_props_ingest.py new file mode 100644 index 00000000..e9d98062 --- /dev/null +++ b/whyis/materialsmine/tests/test_chem_props_ingest.py @@ -0,0 +1,149 @@ +from whyis.test.agent_unit_test_case import AgentUnitTestCase + +import autonomic +import rdflib + +class ChemPropsTest(AgentUnitTestCase): + def setUp(self): + self.maxDiff = 10000 + self.login(*self.create_user("user@example.com", "password")) + + upload = '''<{}> a , + , + ; + "data:application/json;charset=UTF-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPFBvbHltZXJOYW5vY29tcG9zaXRlPjxJRD5MMTAyX1MzX0h1XzIwMDc8L0lEPjxDb250cm9sX0lEPkwxMDJfUzFfSHVfMjAwNzwvQ29udHJvbF9JRD48REFUQV9TT1VSQ0U+PENpdGF0aW9uPjxDb21tb25GaWVsZHM+PENpdGF0aW9uVHlwZT5yZXNlYXJjaCBhcnRpY2xlPC9DaXRhdGlvblR5cGU+PFB1YmxpY2F0aW9uPkpvdXJuYWwgb2YgdGhlIEV1cm9wZWFuIENlcmFtaWMgU29jaWV0eTwvUHVibGljYXRpb24+PFRpdGxlPkRpZWxlY3RyaWMgcHJvcGVydGllcyBvZiBCU1QvcG9seW1lciBjb21wb3NpdGU8L1RpdGxlPjxBdXRob3I+SHUsIFRhbzwvQXV0aG9yPjxBdXRob3I+SnV1dGksIEphcmk8L0F1dGhvcj48QXV0aG9yPkphbnR1bmVuLCBIZWxpPC9BdXRob3I+PEF1dGhvcj5WaWxrbWFuLCBUYWlzdG88L0F1dGhvcj48S2V5d29yZD5Db21wb3NpdGVzPC9LZXl3b3JkPjxLZXl3b3JkPkRpZWxlY3RyaWMgcHJvcGVydGllczwvS2V5d29yZD48S2V5d29yZD5NaWNyb3N0cnVjdHVyZS1maW5hbDwvS2V5d29yZD48S2V5d29yZD5CU1QtQ09DPC9LZXl3b3JkPjxQdWJsaXNoZXI+RWxzZXZpZXI8L1B1Ymxpc2hlcj48UHVibGljYXRpb25ZZWFyPjIwMDc8L1B1YmxpY2F0aW9uWWVhcj48RE9JPjEwLjEwMTYvai5qZXVyY2VyYW1zb2MuMjAwNy4wMi4wODI8L0RPST48Vm9sdW1lPjI3PC9Wb2x1bWU+PFVSTD5odHRwczovL3d3dy5zY2llbmNlZGlyZWN0LmNvbS9zY2llbmNlL2FydGljbGUvcGlpL1MwOTU1MjIxOTA3MDAxMjUyP3ZpYSUzRGlodWI8L1VSTD48TGFuZ3VhZ2U+RW5nbGlzaDwvTGFuZ3VhZ2U+PExvY2F0aW9uPk1pY3JvZWxlY3Ryb25pY3MgYW5kIE1hdGVyaWFscyBQaHlzaWNzIExhYm9yYXRvcmllcywgRU1QQVJUIFJlc2VhcmNoIEdyb3VwIG9mIEluZm90ZWNoIE91bHUsIFAuTy4gQm94IDQ1MDAsIEZJTi05MDAxNCBVbml2ZXJzaXR5IG9mIE91bHUsIEZpbmxhbmQ8L0xvY2F0aW9uPjxEYXRlT2ZDaXRhdGlvbj4yMDE1LTA3LTI0PC9EYXRlT2ZDaXRhdGlvbj48L0NvbW1vbkZpZWxkcz48Q2l0YXRpb25UeXBlPjxKb3VybmFsPjxJU1NOPjA5NTUtMjIxOTwvSVNTTj48SXNzdWU+MTMtMTU8L0lzc3VlPjwvSm91cm5hbD48L0NpdGF0aW9uVHlwZT48L0NpdGF0aW9uPjwvREFUQV9TT1VSQ0U+PE1BVEVSSUFMUz48TWF0cml4PjxNYXRyaXhDb21wb25lbnQ+PENoZW1pY2FsTmFtZT5jeWNsbyBvbGVmaW4gY29wb2x5bWVyPC9DaGVtaWNhbE5hbWU+PEFiYnJldmlhdGlvbj5DT0M8L0FiYnJldmlhdGlvbj48UG9seW1lclR5cGU+Y29wb2x5bWVyPC9Qb2x5bWVyVHlwZT48TWFudWZhY3R1cmVyT3JTb3VyY2VOYW1lPlRpY29uYSBHbWJILCBHZXJtYW55PC9NYW51ZmFjdHVyZXJPclNvdXJjZU5hbWU+PFRyYWRlTmFtZT5Ub3BhcyA4MDA3Uy0wNDwvVHJhZGVOYW1lPjxEZW5zaXR5Pjx2YWx1ZT4xLjAyPC92YWx1ZT48dW5pdD5nL2NtXjM8L3VuaXQ+PC9EZW5zaXR5PjwvTWF0cml4Q29tcG9uZW50PjwvTWF0cml4PjxGaWxsZXI+PEZpbGxlckNvbXBvbmVudD48Q2hlbWljYWxOYW1lPmJhcml1bSBzdHJvbnRpdW0gdGl0YW5hdGU8L0NoZW1pY2FsTmFtZT48QWJicmV2aWF0aW9uPkJTVDwvQWJicmV2aWF0aW9uPjxNYW51ZmFjdHVyZXJPclNvdXJjZU5hbWU+U2lnbWHigJNBbGRyaWNoIENoZW1pZSBHbWJILCBHZXJtYW55PC9NYW51ZmFjdHVyZXJPclNvdXJjZU5hbWU+PERlbnNpdHk+PHZhbHVlPjQuOTwvdmFsdWU+PHVuaXQ+Zy9jbV4zPC91bml0PjwvRGVuc2l0eT48U3BoZXJpY2FsUGFydGljbGVEaWFtZXRlcj48ZGVzY3JpcHRpb24+bGVzcyB0aGFuIDIwMCBubTwvZGVzY3JpcHRpb24+PHZhbHVlPjIwMDwvdmFsdWU+PHVuaXQ+bm08L3VuaXQ+PC9TcGhlcmljYWxQYXJ0aWNsZURpYW1ldGVyPjwvRmlsbGVyQ29tcG9uZW50PjxGaWxsZXJDb21wb3NpdGlvbj48RnJhY3Rpb24+PHZvbHVtZT4wLjA1PC92b2x1bWU+PC9GcmFjdGlvbj48L0ZpbGxlckNvbXBvc2l0aW9uPjxEZXNjcmlwdGlvbj5CYTAuNVNyMC41VGlPMzwvRGVzY3JpcHRpb24+PC9GaWxsZXI+PC9NQVRFUklBTFM+PFBST0NFU1NJTkc+PE1lbHRNaXhpbmc+PENob29zZVBhcmFtZXRlcj48TWl4aW5nPjxNaXhlcj5Ub3JxdWUgUmhlb21ldGVyPC9NaXhlcj48UlBNPjxkZXNjcmlwdGlvbj4zMi02NCBycG08L2Rlc2NyaXB0aW9uPjx2YWx1ZT40ODwvdmFsdWU+PHVuaXQ+cnBtPC91bml0PjwvUlBNPjxUaW1lPjx2YWx1ZT4xNTwvdmFsdWU+PHVuaXQ+bWludXRlczwvdW5pdD48dW5jZXJ0YWludHk+PHR5cGU+YWJzb2x1dGU8L3R5cGU+PHZhbHVlPjU8L3ZhbHVlPjwvdW5jZXJ0YWludHk+PC9UaW1lPjxUZW1wZXJhdHVyZT48dmFsdWU+MjMwPC92YWx1ZT48dW5pdD5DZWxzaXVzPC91bml0PjwvVGVtcGVyYXR1cmU+PC9NaXhpbmc+PC9DaG9vc2VQYXJhbWV0ZXI+PENob29zZVBhcmFtZXRlcj48TW9sZGluZz48TW9sZGluZ01vZGU+aG90LXByZXNzaW5nPC9Nb2xkaW5nTW9kZT48TW9sZGluZ0luZm8+PFRlbXBlcmF0dXJlPjx2YWx1ZT4yMDA8L3ZhbHVlPjx1bml0PkNlbHNpdXM8L3VuaXQ+PC9UZW1wZXJhdHVyZT48L01vbGRpbmdJbmZvPjwvTW9sZGluZz48L0Nob29zZVBhcmFtZXRlcj48L01lbHRNaXhpbmc+PC9QUk9DRVNTSU5HPjxDSEFSQUNURVJJWkFUSU9OPjxTY2FubmluZ19FbGVjdHJvbl9NaWNyb3Njb3B5PjxFcXVpcG1lbnRVc2VkPkpFT0wgSlNNLTY0MDA8L0VxdWlwbWVudFVzZWQ+PC9TY2FubmluZ19FbGVjdHJvbl9NaWNyb3Njb3B5PjxEaWVsZWN0cmljX2FuZF9JbXBlZGFuY2VfU3BlY3Ryb3Njb3B5X0FuYWx5c2lzPjxFcXVpcG1lbnQ+QWdpbGVudCBFNDk5MUE8L0VxdWlwbWVudD48L0RpZWxlY3RyaWNfYW5kX0ltcGVkYW5jZV9TcGVjdHJvc2NvcHlfQW5hbHlzaXM+PFhSYXlfRGlmZnJhY3Rpb25fYW5kX1NjYXR0ZXJpbmc+PEVxdWlwbWVudD5TaWVtZW5zIEQ1MDAwPC9FcXVpcG1lbnQ+PC9YUmF5X0RpZmZyYWN0aW9uX2FuZF9TY2F0dGVyaW5nPjwvQ0hBUkFDVEVSSVpBVElPTj48UFJPUEVSVElFUz48RWxlY3RyaWNhbD48QUNfRGllbGVjdHJpY0Rpc3BlcnNpb24+PERpZWxlY3RyaWNfUmVhbF9QZXJtaXR0aXZpdHk+PGRlc2NyaXB0aW9uPlJlbGF0aXZlIHBlcm1pdHRpdml0eSBhdCAxR0h6PC9kZXNjcmlwdGlvbj48dmFsdWU+Mi45PC92YWx1ZT48L0RpZWxlY3RyaWNfUmVhbF9QZXJtaXR0aXZpdHk+PERpZWxlY3RyaWNfTG9zc19UYW5nZW50PjxkZXNjcmlwdGlvbj5Mb3NzIFRhbmdlbnQgYXQgMSBHSHo8L2Rlc2NyaXB0aW9uPjx2YWx1ZT41ZS0wNTwvdmFsdWU+PC9EaWVsZWN0cmljX0xvc3NfVGFuZ2VudD48L0FDX0RpZWxlY3RyaWNEaXNwZXJzaW9uPjwvRWxlY3RyaWNhbD48L1BST1BFUlRJRVM+PC9Qb2x5bWVyTmFub2NvbXBvc2l0ZT4=" . + '''.format("/apps/nanomine-graph/ChemDatabase/chemprops_example.json") + + response = self.client.post( + "/pub", data=upload, content_type="text/turtle", follow_redirects=True) + self.assertEquals(response.status, "201 CREATED") + + response = self.client.post( + "/pub", data=open("/apps/nanomine-graph/setl/chem_props.setl.ttl", "rb").read(), + content_type="text/turtle", follow_redirects=True) + self.assertEquals(response.status, "201 CREATED") + + setlmaker = autonomic.SETLMaker() + results = self.run_agent(setlmaker) + + self.assertTrue(len(results) > 0) + + setlr = autonomic.SETLr() + + print(len(self.app.db)) + for setlr_np in results: + setlr_results = self.run_agent(setlr, nanopublication=setlr_np) + + # def test_print_triples(self): + # print("\n\n\nPrinting SPO Triples") + # for s, p, o in self.app.db.triples((None, None, None)): + # print(str(s.n3()) + " " + str(p.n3()) + " " + str(o.n3()) + " .") + + def no_test_material(self): + expected_materials = list() + + # Initialize Expected Materials + # Poly(ether ether ketone) + expected_materials.append(dict()) + mat_num = 0 + expected_materials[mat_num]["id"] = rdflib.Literal("O(C1=CC=C(C=C1)C(=O)C2=CC=C(OC3=CC=C(C=C3)[*])C=C2)[*]") + expected_materials[mat_num]["stdname"] = rdflib.Literal("Poly(ether ether ketone)") + expected_materials[mat_num]["density"] = rdflib.Literal(1.29) + expected_materials[mat_num]["abbrev"] = [rdflib.Literal("PEEK")] + expected_materials[mat_num]["altname"] = [rdflib.Literal("Zeniva"), rdflib.Literal("KetaSpire")] + + # Polystyrene + expected_materials.append(dict()) + mat_num += 1 + expected_materials[mat_num]["id"] = rdflib.Literal("C(C(C1=CC=CC=C1)[*])[*]") + expected_materials[mat_num]["stdname"] = rdflib.Literal("Polystyrene") + expected_materials[mat_num]["density"] = rdflib.Literal(1.04) + expected_materials[mat_num]["abbrev"] = [rdflib.Literal("PS")] + expected_materials[mat_num]["altname"] = [ + rdflib.Literal("Pelaspan"), + rdflib.Literal("Afcolene"), + rdflib.Literal("Aim"), + rdflib.Literal("Amoco"), + rdflib.Literal("Bextrene"), + rdflib.Literal("Carinex"), + rdflib.Literal("Distrene"), + rdflib.Literal("Dylene"), + rdflib.Literal("Edistir"), + rdflib.Literal("Erinoid"), + rdflib.Literal("Fina"), + rdflib.Literal("Fostarene"), + rdflib.Literal("Gedex"), + rdflib.Literal("Hostyren"), + rdflib.Literal("Huntsman PS"), + rdflib.Literal("Lacqrene"), + rdflib.Literal("Ladene"), + rdflib.Literal("Lorkalene"), + rdflib.Literal("Luron"), + rdflib.Literal("Lustran"), + rdflib.Literal("Lustrex"), + rdflib.Literal("Neste PS"), + rdflib.Literal("Polystyrol"), + rdflib.Literal("Restirolo"), + rdflib.Literal("Sicostyrol"), + rdflib.Literal("Sternite"), + rdflib.Literal("Stiroplasto"), + rdflib.Literal("Stymer"), + rdflib.Literal("Styrodur"), + rdflib.Literal("Styron"), + rdflib.Literal("Styvarene"), + rdflib.Literal("Vestyron"), + rdflib.Literal("Polystyrol"), + rdflib.Literal("Polyzote"), + rdflib.Literal("Pyrochek 68") + ] + expected_materials[mat_num]["altname"] += [ + rdflib.Literal("polyphenylethene"), + rdflib.Literal("poly-1-phenylethylene"), + rdflib.Literal("polyvinylbenzene") + ] + + # Nylon + expected_materials.append(dict()) + mat_num += 1 + expected_materials[mat_num]["id"] = rdflib.Literal("N(CCCCCC(=O)[*])[*]") + expected_materials[mat_num]["stdname"] = rdflib.Literal("Nylon 6") + expected_materials[mat_num]["density"] = rdflib.Literal(1.08) + expected_materials[mat_num]["abbrev"] = [rdflib.Literal("PA 6"), rdflib.Literal("Nylon 6")] + expected_materials[mat_num]["altname"] = [rdflib.Literal("Perlon"), rdflib.Literal("Plaskon")] + expected_materials[mat_num]["altname"] += [ + rdflib.Literal("Poly(caprolactam)"), + rdflib.Literal("polyamide 6"), + rdflib.Literal("poly(ω-aminocaproamide)"), + rdflib.Literal("poly(6-aminocaproic acid)"), + rdflib.Literal("poly(ε-aminocaproic acid)"), + rdflib.Literal("poly(ω-caproamide)"), + rdflib.Literal("polycaprolactam"), + rdflib.Literal("poly-[imino-(1-oxohexamethylene)]") + ] + + for mat in expected_materials: + mat["abbrev"] = mat["abbrev"].sort() + mat["altname"] = mat["altname"].sort() + + # Query the graph for the materials + # Get everything but the alt names and abbreviations + + props = self.app.db.query( + ''' + SELECT ?chem ?id ?stdname ?abbrev ?density + WHERE + { + ?chem a . + ?chem ?id . + ?chem ?den . + ?den ?density . + ?chem ?stdname . + } + ''' + ) + materials = [{"chem": chem, "id": chem_id, "stdname": stdname, "density": density} for chem, chem_id, stdname, abbrev, density in props] + for chem in materials: + chem["altname"] = [name for name in self.app.db.objects(chem["chem"], rdflib.URIRef("http://www.w3.org/2004/02/skos/core#altLabel"))].sort() + chem["abbrev"] = [abbrev for abbrev in self.app.db.objects(chem["chem"], rdflib.URIRef("http://www.w3.org/2004/02/skos/core#notation"))].sort() + chem.pop("chem", None) + self.assertCountEqual(expected_materials, materials) diff --git a/whyis/materialsmine/tests/test_chemical_names.py b/whyis/materialsmine/tests/test_chemical_names.py new file mode 100644 index 00000000..d2dfc24d --- /dev/null +++ b/whyis/materialsmine/tests/test_chemical_names.py @@ -0,0 +1,105 @@ +import rdflib + +from whyis.test.agent_unit_test_case import AgentUnitTestCase +from base64 import b64encode +import autonomic +from . import template + +SKOS = rdflib.Namespace("http://www.w3.org/2004/02/skos/core#") + +class TestChemicalNames(template.IngestTest): + + data = ''' + + L101_S3_Dang_2007 + + + + bisphenol A + 6623 + CC(C)(C1=CC=C(OCC2CO2)C=C1)C3=CC=C(OCC4CO4)C=C3 + BPA + Dow chemical + DER661 + + + + + barium titanate + Barium titanate + BaTiO3 + Guoteng electronic ceramic company + + silane coupling agent + KH550 + + + phosphated ester + BYK-9010 + + + + + ''' + + def test_chemprops_id(self): + print (len(self.app.db)) + component_types = set(self.app.db.query(''' + SELECT ?parttype ?role WHERE { + ?sample a . + ?sample /? ?part. + ?part a ?parttype; + [ + a ?role; + ?sample + ]. + }''')) + print ('\n'.join(['\t'.join(x) for x in component_types])) + self.assertIn((rdflib.URIRef('http://nanomine.org/compound/BariumTitanate'), + rdflib.URIRef('http://nanomine.org/ns/Filler')), component_types) + filler_type = self.app.db.resource(rdflib.URIRef('http://nanomine.org/compound/BariumTitanate')) + print ('\n'.join(["%s\t%s" %(p,o) for p,o in filler_type.predicate_objects()])) + + self.assertEquals(filler_type.value(rdflib.RDFS.label), rdflib.Literal("Barium titanate")) + self.assertEquals(filler_type.value(SKOS.altLabel), rdflib.Literal("barium titanate")) + self.assertEquals(filler_type.value(SKOS.notation), rdflib.Literal("BaTiO3")) + + def test_pubchem_id(self): + print (len(self.app.db)) + component_types = set(self.app.db.query(''' + SELECT ?parttype ?role WHERE { + ?sample a . + ?sample /? ?part. + ?part a ?parttype; + [ + a ?role; + ?sample + ]. + }''')) + print ('\n'.join(['\t'.join(x) for x in component_types])) + self.assertIn((rdflib.URIRef('http://rdf.ncbi.nlm.nih.gov/pubchem/compound/CID6623'), + rdflib.URIRef('http://nanomine.org/ns/Matrix')), component_types) + matrix_type = self.app.db.resource(rdflib.URIRef('http://rdf.ncbi.nlm.nih.gov/pubchem/compound/CID6623')) + print ('\n'.join(["%s\t%s" %(p,o) for p,o in matrix_type.predicate_objects()])) + + self.assertEquals(matrix_type.value(rdflib.RDFS.label), rdflib.Literal("bisphenol A")) + self.assertEquals(matrix_type.value(SKOS.notation), rdflib.Literal("BPA")) + + + def test_nonchemprops_id(self): + print (len(self.app.db)) + component_types = set(self.app.db.query(''' + SELECT ?parttype ?role WHERE { + ?sample a . + ?sample /? ?part. + ?part a ?parttype; + [ + a ?role; + ?sample + ]. + }''')) + print ('\n'.join(['\t'.join(x) for x in component_types])) + self.assertIn((rdflib.URIRef('http://nanomine.org/compound/PhosphatedEster'), + rdflib.URIRef('http://nanomine.org/ns/SurfaceTreatment')), component_types) + self.assertIn((rdflib.URIRef('http://nanomine.org/compound/SilaneCouplingAgent'), + rdflib.URIRef('http://nanomine.org/ns/SurfaceTreatment')), component_types) diff --git a/whyis/materialsmine/tests/test_component_properties.py b/whyis/materialsmine/tests/test_component_properties.py new file mode 100644 index 00000000..c8347aee --- /dev/null +++ b/whyis/materialsmine/tests/test_component_properties.py @@ -0,0 +1,112 @@ +import rdflib + +from . import template + +SKOS = rdflib.Namespace("http://www.w3.org/2004/02/skos/core#") + +class TestComponentProperties(template.IngestTest): + + data = ''' + + L101_S3_Dang_2007 + L101_S1_Dang_2007 + PNC_schema_010720 + 5e496fa88aba2cf1302d73e3 + 5e4c1081c941bb7a1270dd9d + + + + DGEBA Epoxy Resin + + inserted from ChemProps, NanoMine + 1.13 + g/cm3 + + + + + + Barium titanate + + inserted from ChemProps, NanoMine + 6.02 + g/cm3 + + + 0.1 + micrometers + + + + value ranges from 9 - 1.3 + 9 + m^2/g + + + + + + + 0.7802981205443941 + computed by NanoMine + + + 0.4 + reported + + + + + + +''' + + def test_fractions(self): + print (len(self.app.db)) + component_types = set(self.app.db.query(''' + SELECT ?role ?fractiontype ?value WHERE { + ?sample a . + ?sample ?part. + ?part [ + a ?role; + ?sample + ]. + ?part [ + ?value; + a ?fractiontype + ] + }''')) + print(component_types) + print ('\n'.join(['\t'.join(x) for x in component_types])) + self.assertIn((rdflib.URIRef('http://nanomine.org/ns/Filler'), + rdflib.URIRef('http://nanomine.org/ns/VolumeFraction'), + rdflib.Literal(0.4)), component_types) + self.assertIn((rdflib.URIRef('http://nanomine.org/ns/Filler'), + rdflib.URIRef('http://nanomine.org/ns/MassFraction'), + rdflib.Literal(0.7802981205443941)), component_types) + + def test_density(self): + print (len(self.app.db)) + component_types = set(self.app.db.query(''' + SELECT ?role ?fractiontype ?value ?unit WHERE { + ?sample a . + ?sample ?part. + ?part [ + a ?role; + ?sample + ]. + ?part [ + ?value; + a ?fractiontype; + ?unit; + ] + }''')) + print ('\n'.join(['\t'.join(x) for x in component_types])) + self.assertIn((rdflib.URIRef('http://nanomine.org/ns/Filler'), + rdflib.URIRef('http://nanomine.org/ns/Density'), + rdflib.Literal(6.02), + rdflib.URIRef('http://www.ontology-of-units-of-measure.org/resource/om-2/gramPerCubicCentimetre')), component_types) + self.assertIn((rdflib.URIRef('http://nanomine.org/ns/Matrix'), + rdflib.URIRef('http://nanomine.org/ns/Density'), + rdflib.Literal(1.13), + rdflib.URIRef('http://www.ontology-of-units-of-measure.org/resource/om-2/gramPerCubicCentimetre')), component_types) diff --git a/whyis/materialsmine/tests/test_pnc_properties.py b/whyis/materialsmine/tests/test_pnc_properties.py new file mode 100644 index 00000000..310f6f84 --- /dev/null +++ b/whyis/materialsmine/tests/test_pnc_properties.py @@ -0,0 +1,188 @@ +import rdflib + +from . import template + +SKOS = rdflib.Namespace("http://www.w3.org/2004/02/skos/core#") + +class TestStaticProperties(template.IngestTest): + + data = ''' + + L141_S19_Gao_2013 + L141_S1_Gao_2013 + PNC_schema_010720 + 5e496fa88aba2cf1302d73e3 + 5e4c12fec941bb7a1270ddbb + + + + + Modulus + 3.2 + GPa + + absolute + 0.1 + + + + Yield Stress + 76 + MPa + + absolute + 0.5 + + + + strain at break + 0.079 + + absolute + 0.02 + + + + + Tensile test strain rate + 0.1 + mm/min + + + + + + +''' + + def test_property(self): + print (len(self.app.db)) + properties = set(self.app.db.query(''' + SELECT ?sample ?property ?unit ?value ?uncertainty WHERE { + ?sample a . + ?sample ?attr. + ?attr ?value; + a ?property. + optional { + ?attr ?unit. + } + optional { + ?attr [ + a ; + ?uncertainty + ]. + } + }''')) + print ('\n'.join(['\t'.join([(val if val is not None else '-') for val in x]) for x in properties])) + self.assertIn((rdflib.URIRef('http://nanomine.org/sample/l141-s19-gao-2013'), + rdflib.URIRef('http://nanomine.org/ns/TensileModulus'), + rdflib.URIRef('http://www.ontology-of-units-of-measure.org/resource/om-2/gigapascal'), + rdflib.Literal(3.2), + rdflib.Literal(0.1)), properties) + self.assertIn((rdflib.URIRef('http://nanomine.org/sample/l141-s19-gao-2013'), + rdflib.URIRef('http://nanomine.org/ns/ElongationAtBreak'), + None, # no unit + rdflib.Literal(0.079), + rdflib.Literal(0.02)), properties) + +import rdflib + +from . import template + +SKOS = rdflib.Namespace("http://www.w3.org/2004/02/skos/core#") + +class TestDynamicProperties(template.IngestTest): + + data = ''' + + L104_S4_He_2009 + L104_S1_He_2009 + PNC_schema_010720 + 5e496fa88aba2cf1302d73e3 + 5e4c10bbc941bb7a1270dd9f + + + + + measured at 1000 Hz and room temperature + 25.4423 + + + + + + + + 25 + Celsius + + + + + + + dependence of dielectric constants on the frequency for PVDF/xGnP nano composites at room temperature + + Frequency + Hz + Dielectric permittivity + dimensionless + + + + frequency (Hz) + Dielectric Permittivity + + + + 53 + 33.8412508779 + + + 54 + 24.9339073612 + + + + + + + + + ''' + + def test_curve(self): + print (len(self.app.db)) + properties = set(self.app.db.query(''' + SELECT ?sample ?property ?unit ?value ?independentVar ?indepValue ?indepUnit WHERE { + ?sample a . + ?sample ?attr. + ?attr ?value. + ?attr a ?property. + optional { + ?attr ?unit. + } + optional { + ?attr ?irt. + ?irt a ?independentVar; + ?indepValue. + optional { + ?irt ?indepUnit. + } + } + }''')) + print ('\n'.join(['\t'.join([(val if val is not None else '-') for val in x]) for x in properties])) + self.assertIn((rdflib.URIRef('http://nanomine.org/sample/l104-s4-he-2009'), + rdflib.URIRef('http://nanomine.org/ns/DielectricPermittivity'), + None, + rdflib.Literal(33.8412508779), + rdflib.URIRef('http://nanomine.org/ns/Frequency'), + rdflib.Literal(53.0), + rdflib.URIRef('http://www.ontology-of-units-of-measure.org/resource/om-2/hertz')), properties) + self.assertIn((rdflib.URIRef('http://nanomine.org/sample/l104-s4-he-2009'), + rdflib.URIRef('http://nanomine.org/ns/DielectricPermittivity'), + None, + rdflib.Literal(24.9339073612), + rdflib.URIRef('http://nanomine.org/ns/Frequency'), + rdflib.Literal(54.0), + rdflib.URIRef('http://www.ontology-of-units-of-measure.org/resource/om-2/hertz')), properties) diff --git a/whyis/materialsmine/tests/xml/L101_S11_Dang_2007.xml b/whyis/materialsmine/tests/xml/L101_S11_Dang_2007.xml new file mode 100644 index 00000000..895d66fb --- /dev/null +++ b/whyis/materialsmine/tests/xml/L101_S11_Dang_2007.xml @@ -0,0 +1,489 @@ + + + L101_S11_Dang_2007 + L101_S1_Dang_2007 + + + + research article + Composites Science and Technology + Study on microstructure and dielectric property of the BaTiO3/epoxy resin composites + Dang, Zhi-Min + Yu, Yan-Fei + Xu, Hai-Ping + Bai, Jinbo + Dielectric properties + Microstructure + Silane coupling agent + BaTiO3 + Elsevier + 2008 + 10.1016/j.compscitech.2007.05.021 + 68 + https://www.sciencedirect.com/science/article/pii/S0266353807002199?via%3Dihub + English + Key Laboratory of Beijing City on Preparation and Processing of Novel Polymer Materials and Key Laboratory of the Ministry of Education on Nanomaterials, Beijing University of Chemical Technology, Beijing 100029, PR China + 2015-07-24 + + + + 0266-3538 + 1 + + + + + + + + bisphenol A epoxy resin + EPR + Dow chemical + DER661 + + + + + dissolving + + acetone + + + + + + MeTHPA was chosen as a hardener in 10/4 (EPR/MeTHPA) weight ratio + MeTHPA + + + + + + + barium titanate + BaTiO3 + Guoteng electronic ceramic company + + 0.7 + micrometers + + + + value ranges from 9 - 1.3 + 9 + m^2/g + + + + phosphated ester + BYK-9010 + + The amount of KH550 and BYK-9010 was 1.0 wt% in comparison with the BaTiO3 powders + + + + + + 0.6 + + + + + + + + Suspensions containing BaTiO3 powde and solvent were prepared in a polytetrafluoroethylene (PTFE) bottle + + + + Ultrasonic was applied to the suspensions. + ultra-sonication + + + + + EPR and curing agent were added into the suspensions. + EPR + + + + + Catalyst 2,4-EMI was added into suspensions + 2-ethyl-4- methyl-imidazole + + + + + ball milling + + + + + + + 75 + Celsius + + + + + + + To remove solvent residue + + 75 + Celsius + + + + + + + hot-pressing + + Samples were cured at temperature range between 150 and 160 degrees celsius + + 150 + Celsius + + + + + + + + + Hitachi S-4700 + + + Dupont TA 2010 + + + Nexus 670 + + + + + + + Dielectric Permittivity of 60 vol% BaTiO3/EPR composite without KH550. Taken at room temperature + + + Frequency + Hz + Dielectric Permittivity + + + + Frequency (Hz) + Dielectric Permittivity + + + + 1037.79237 + 36.81818 + + + 1272.6532 + 36.73295 + + + 1530.63225 + 36.64773 + + + 1951.22856 + 36.13636 + + + 2416.25708 + 36.22159 + + + 2963.07568 + 36.13636 + + + 3633.51004 + 35.88068 + + + 4543.23067 + 35.79545 + + + 5680.71772 + 35.71023 + + + 7171.68299 + 35.19886 + + + 9143.53871 + 35.28409 + + + 10680.9252 + 35.11364 + + + 13750.59549 + 35.19886 + + + 16376.87057 + 34.77273 + + + 20677.81907 + 34.85795 + + + 25603.52549 + 34.51705 + + + 31704.34482 + 34.43182 + + + 40029.90925 + 34.43182 + + + 49088.09946 + 34.26136 + + + 60783.71494 + 34.09091 + + + 76742.70088 + 33.92045 + + + 94110.19717 + 33.83523 + + + 115408.09887 + 33.75 + + + 140160.12385 + 33.75 + + + 178674.1632 + 33.23864 + + + 217003.09354 + 33.40909 + + + 268705.74179 + 33.23864 + + + 335987.68558 + 33.23864 + + + 420124.26433 + 33.32386 + + + 535588.2391 + 32.98295 + + + 650457.93715 + 32.98295 + + + 797676.52709 + 32.98295 + + + 978233.20119 + 33.06818 + + + + + + + Loss Tangent of 60 vol% BaTiO3/EPR composite without KH550. Taken at room temperature + + + Frequency + Hz + Loss Tangent + + + + Frequency (Hz) + Loss Tangent + + + + 1059.93907 + 0.03011 + + + 1262.18669 + 0.02879 + + + 1547.41478 + 0.0286 + + + 1972.1676 + 0.02784 + + + 2348.47811 + 0.02727 + + + 3022.29657 + 0.02633 + + + 3705.27311 + 0.02652 + + + 4498.72957 + 0.02727 + + + 5678.23658 + 0.02443 + + + 6961.40065 + 0.02576 + + + 8786.58723 + 0.02273 + + + 10877.19349 + 0.025 + + + 13206.46294 + 0.02386 + + + 16508.08245 + 0.02405 + + + 20043.16456 + 0.02292 + + + 25298.21549 + 0.02386 + + + 31622.7766 + 0.02348 + + + 39146.83264 + 0.02424 + + + 48461.09895 + 0.0233 + + + 61763.27794 + 0.02292 + + + 72838.25798 + 0.02292 + + + 94650.64885 + 0.02254 + + + 116039.73854 + 0.02348 + + + 138181.35219 + 0.02311 + + + 174410.66328 + 0.02311 + + + 222284.97711 + 0.02348 + + + 277856.28495 + 0.02348 + + + 334099.94527 + 0.0233 + + + 421696.50343 + 0.0233 + + + 507056.29618 + 0.02424 + + + 646239.14082 + 0.02424 + + + 799999.81699 + 0.025 + + + 961935.75439 + 0.02727 + + + + + + + + null + + + micrometers + + https://nanomine.org/nmr/blob?id=5b201f0ae74a1d61fc4405a0 + Microstructure of fractured surface of 0.7 micrometers loading nanocomposite without KH550 + SEM + + + diff --git a/whyis/materialsmine/tests/xml/L101_S3_Dang_2007.xml b/whyis/materialsmine/tests/xml/L101_S3_Dang_2007.xml new file mode 100644 index 00000000..be5d2a61 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L101_S3_Dang_2007.xml @@ -0,0 +1,228 @@ + + + L101_S3_Dang_2007 + L101_S1_Dang_2007 + PNC_schema_010720 + 5e496fa88aba2cf1302d73e3 + 5e4c1081c941bb7a1270dd9d + + + + research article + Composites Science and Technology + Study on microstructure and dielectric property of the BaTiO3/epoxy resin composites + Dang, Zhi-Min + Yu, Yan-Fei + Xu, Hai-Ping + Bai, Jinbo + Dielectric properties + Microstructure + Silane coupling agent + BaTiO3 + Elsevier + 2008 + 10.1016/j.compscitech.2007.05.021 + 68 + https://www.sciencedirect.com/science/article/pii/S0266353807002199?via%3Dihub + English + Key Laboratory of Beijing City on Preparation and Processing of Novel Polymer Materials and Key Laboratory of the Ministry of Education on Nanomaterials, Beijing University of Chemical Technology, Beijing 100029, PR China + 2015-07-24 + + + + 0266-3538 + 1 + + + + + + + + bisphenol A epoxy resin + DGEBA Epoxy Resin + CC(C)(C1=CC=C(OCC2CO2)C=C1)C3=CC=C(OCC4CO4)C=C3 + EPR + Dow chemical + DER661 + + inserted from ChemProps, NanoMine + 1.13 + g/cm3 + + + + + + dissolving + + acetone + + + + + + MeTHPA was chosen as a hardener in 10/4 (EPR/MeTHPA) weight ratio + MeTHPA + + + + + + + barium titanate + Barium titanate + BaTiO3 + Guoteng electronic ceramic company + + inserted from ChemProps, NanoMine + 6.02 + g/cm3 + + + 0.1 + micrometers + + + + value ranges from 9 - 1.3 + 9 + m^2/g + + + + silane coupling agent + KH550 + + The amount of KH550 and BYK-9010 was 1.0 wt% in comparison with the BaTiO3 powders + + + + phosphated ester + BYK-9010 + + The amount of KH550 and BYK-9010 was 1.0 wt% in comparison with the BaTiO3 powders + + + + + + + 0.7802981205443941 + computed by NanoMine + + + 0.4 + reported + + + + + + + + + Suspensions containing BaTiO3 powder, KH550 and solvent were prepared in a polytetrafluoroethylene (PTFE) bottle + + + + Ultrasonic was applied to the suspensions. + ultra-sonication + + + + + EPR and curing agent were added into the suspensions. + EPR + + + + + Catalyst 2,4-EMI was added into suspensions + 2-ethyl-4- methyl-imidazole + + + + + ball milling + + + + + + + 75 + Celsius + + + + + + + To remove solvent residue + + 75 + Celsius + + + + + + + hot-pressing + + Samples were cured at temperature range between 150 and 160 degrees celsius + + 150 + Celsius + + + + + + + + + Hitachi S-4700 + + + Dupont TA 2010 + + + Nexus 670 + + + + + + + Dielectric Permittivity at 10^3 Hz, taken at room temperature + 16.27129074 + + + Loss Tangent at 10^3 Hz, taken at room temperature + 0.023529412 + + + + + Dielectric Permittivity at 10^6 Hz, taken at room temperature + 15.2407932 + + + Loss Tangent at 10^6 Hz, taken at room temperature + 0.024242424 + + + + + diff --git a/whyis/materialsmine/tests/xml/L102_S3_Hu_2007.xml b/whyis/materialsmine/tests/xml/L102_S3_Hu_2007.xml new file mode 100644 index 00000000..f1af4ea5 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L102_S3_Hu_2007.xml @@ -0,0 +1,135 @@ + + + L102_S3_Hu_2007 + L102_S1_Hu_2007 + + + + research article + Journal of the European Ceramic Society + Dielectric properties of BST/polymer composite + Hu, Tao + Juuti, Jari + Jantunen, Heli + Vilkman, Taisto + Composites + Dielectric properties + Microstructure-final + BST-COC + Elsevier + 2007 + 10.1016/j.jeurceramsoc.2007.02.082 + 27 + https://www.sciencedirect.com/science/article/pii/S0955221907001252?via%3Dihub + English + Microelectronics and Materials Physics Laboratories, EMPART Research Group of Infotech Oulu, P.O. Box 4500, FIN-90014 University of Oulu, Finland + 2015-07-24 + + + + 0955-2219 + 13-15 + + + + + + + + cyclo olefin copolymer + COC + copolymer + Ticona GmbH, Germany + Topas 8007S-04 + + 1.02 + g/cm^3 + + + + + + barium strontium titanate + BST + Sigma–Aldrich Chemie GmbH, Germany + + 4.9 + g/cm^3 + + + less than 200 nm + 200 + nm + + + + + 0.05 + + + Ba0.5Sr0.5TiO3 + + + + + + + Torque Rheometer + + 32-64 rpm + 48 + rpm + + + + 230 + Celsius + + + + + + hot-pressing + + + 200 + Celsius + + + + + + + + + JEOL JSM-6400 + + + Agilent E4991A + + + Siemens D5000 + + + + + + + Relative permittivity at 1GHz + 2.9 + + + Loss Tangent at 1 GHz + 0.00005 + + + + + diff --git a/whyis/materialsmine/tests/xml/L104_S4_He_2009.xml b/whyis/materialsmine/tests/xml/L104_S4_He_2009.xml new file mode 100644 index 00000000..76e34fbf --- /dev/null +++ b/whyis/materialsmine/tests/xml/L104_S4_He_2009.xml @@ -0,0 +1,1579 @@ + + + L104_S4_He_2009 + L104_S1_He_2009 + PNC_schema_010720 + 5e496fa88aba2cf1302d73e3 + 5e4c10bbc941bb7a1270dd9f + + + + research article + Advanced Materials + High Dielectric Permittivity and Low Percolation Threshold in Nanocomposites Based on Poly(vinylidene fluoride) and Exfoliated Graphite Nanoplates + He, Fuan + Lau, Sienting + Chan, Helen Laiwa + Fan, Jintu + poly(vinylidene fluoride) + exfoliated graphite nanoplates + nanocomposites + dielectrics + WILEYâ€VCH Verlag + 2009 + 10.1002/adma.200801758 + 21 + http://onlinelibrary.wiley.com/doi/10.1002/adma.200801758/abstract + English + Institute of Textiles and Clothing The Hong Kong Polytechnic University Hung Hom, Kowloon, Hong Kong (China) + 2017-06-26 + + + + 1521-4095 + 6 + + + + + + + + poly(vinylidene flouride) + Poly(vinylidene fluoride) + C(C(F)(F)[*])[*] + PVDF + + inserted from ChemProps, NanoMine + 1.68 + g/cm3 + + + + + + graphite nanoplates + Graphite + xGnPs + + inserted from ChemProps, NanoMine + 2.266 + g/cm3 + + + + exfoliated graphite nanoplates with diameters of 0.5-25 micrometer + 12.75 + micrometer + + absolute + 12.25 + + + + exfoliated graphite nanoplates with diameters of 0.5-25 micrometer + 12.75 + micrometer + + absolute + 12.25 + + + + exfoliated graphite nanoplates with thicknesses of 20-60 nm + 40 + nm + + absolute + 20 + + + + + + + acidic intercalation + + + + rapid thermal treatment + + + + ultrasonic powdering + + + + + + 0.010492168094092574 + computed by NanoMine + + + 0.0078 + reported + + + + + + + + + + Desired amount of xGnPs was first ultrasonically dispersed in 200 mL of N,N-dimethylformamide (DMF) for 1 hr. + ultra-sonication + + N,N-dimethylformamide + + + + + + + PVDF was added into the xGnP suspension, stirring for 30 min at 80 deg C. + stirring + + + 80 + Celsius + + + + + + Then ultrasonicating for 2 hours. + ultra-sonication + + N,N-dimethylformamide + + + + + + + Poured onto a glass plate to form a thin film and dried at 70 deg C for 3 days. + + 70 + Celsius + + + + + + + hot-pressing + + + 200 + Celsius + + + + + + + + + JEOL JSM-2010 + + + JEOL JSM-6490 + + + Agilen 4294 A + The dielectric porperties of the samples were measured in the frequency range of 50-10^7 Hz at room temperature + + + + + + + measured at 1000 Hz and room temperature + 25.4423 + + + + + + + + 25 + Celsius + + + + + + + dependence of dielectric constants on the frequency for PVDF/xGnP nano composites at room temperature + + Frequency + Hz + Dielectric permittivity + dimensionless + + + + frequency (Hz) + Dielectric Permittivity + + + + 53.4586372606 + 33.8412508779 + + + 53.4586372606 + 24.9339073612 + + + 51.6552840554 + 20.3792069301 + + + 59.2553097555 + 33.4761096982 + + + 59.2553097555 + 25.2486363287 + + + 65.6805319803 + 34.5366595745 + + + 65.9628714676 + 25.2443568671 + + + 72.8024593747 + 34.6774468093 + + + 72.8024593747 + 25.3137735357 + + + 80.6966376674 + 34.7716236622 + + + 80.3129466931 + 25.3515613288 + + + 89.4468042254 + 34.5600843575 + + + 89.4468042254 + 25.4687169669 + + + 99.1457762975 + 34.7009670824 + + + 99.1457762975 + 25.3988754048 + + + 109.896435572 + 34.5600843575 + + + 109.896435572 + 25.3446866278 + + + 121.81281949 + 34.5600843575 + + + 121.81281949 + 25.3601573275 + + + 135.021330901 + 34.5366595745 + + + 135.021330901 + 25.2828981485 + + + 149.662078873 + 34.5835250286 + + + 150.09067161 + 25.3744904695 + + + 165.890364901 + 34.466480446 + + + 165.890364901 + 25.3962923617 + + + 185.008560727 + 33.6321138545 + + + 183.00403788 + 25.203026115 + + + 204.254383641 + 34.3731300551 + + + 203.380117911 + 25.6193970584 + + + 225.91721694 + 33.4590907062 + + + 225.91721694 + 24.8916784067 + + + 249.877569335 + 33.9734440788 + + + 250.951712657 + 25.5024128482 + + + 278.893239195 + 32.9208875367 + + + 277.567176279 + 24.807434938 + + + 307.005425593 + 33.7152865483 + + + 308.545647023 + 25.0893607214 + + + 341.61115342 + 32.6821752203 + + + 341.025524265 + 24.4733025684 + + + 378.003894419 + 34.5132506687 + + + 375.694641726 + 26.2867870129 + + + 384.54559341 + 23.9805233694 + + + 418.991934706 + 33.5215360105 + + + 428.279322647 + 24.3739432178 + + + 464.424425093 + 33.1598444983 + + + 472.461709465 + 24.1764330483 + + + 514.783289981 + 33.3176018344 + + + 523.283810313 + 24.3469152919 + + + 570.602710205 + 33.1823354448 + + + 582.139840294 + 24.3189179878 + + + 632.474789353 + 33.2950192045 + + + 645.934262186 + 25.0502137454 + + + 713.188239247 + 33.4307449448 + + + 713.188239247 + 24.4733025684 + + + 790.521273943 + 32.935771769 + + + 790.521273943 + 24.3739432178 + + + 876.239750135 + 32.9804648552 + + + 876.239750135 + 24.2996885191 + + + 971.252925158 + 32.9581107363 + + + 966.634876725 + 24.3189179878 + + + 1076.56864971 + 33.1149083279 + + + 1076.56864971 + 24.4733025684 + + + 1193.30405863 + 33.0924630834 + + + 1193.30405863 + 24.354119807 + + + 1322.69742084 + 31.7732213663 + + + 1322.69742084 + 24.489901794 + + + 1466.12127434 + 29.8923102931 + + + 1466.12127434 + 23.657528706 + + + 1625.09698529 + 29.8720493216 + + + 1625.09698529 + 23.5508334901 + + + 1799.10462078 + 28.7981081001 + + + 1804.40420331 + 23.3705548016 + + + 2013.83481675 + 28.8714235442 + + + 1962.66644592 + 23.8184785408 + + + 2213.13268191 + 29.9938214697 + + + 2213.13268191 + 23.5508334901 + + + 2453.10897015 + 28.5841217338 + + + 2453.10897015 + 23.4181408952 + + + 2719.10657172 + 28.7006436994 + + + 2719.10657172 + 23.2598962827 + + + 3013.94705181 + 26.5028213057 + + + 3299.61539895 + 23.0349419486 + + + 3340.757926 + 31.9460348524 + + + 3640.01213585 + 23.4181408952 + + + 3703.0058353 + 31.0280873853 + + + 4059.50886109 + 23.9665907209 + + + 4083.46009574 + 30.9860400403 + + + 4472.20403939 + 23.4578699802 + + + 4549.59957177 + 30.1978791576 + + + 4957.13787749 + 23.1811754222 + + + 5042.92562817 + 30.1978791576 + + + 5494.65447462 + 23.1811754222 + + + 5589.74443577 + 29.9125850068 + + + 6090.4555293 + 22.830215545 + + + 6195.85636612 + 30.2183611259 + + + 6742.59246347 + 23.8415605884 + + + 6903.1323459 + 29.8963641362 + + + 7482.87610133 + 23.0635933927 + + + 7659.16441495 + 28.8819124047 + + + 8437.80546046 + 29.7911426713 + + + 8437.80546046 + 23.1027209847 + + + 9352.74077 + 28.9940309625 + + + 9352.74077 + 22.8689472094 + + + 10357.0079669 + 26.607851954 + + + 10546.29344 + 22.6759437509 + + + 11490.9960434 + 29.0727728204 + + + 11761.7112453 + 23.5523543143 + + + 12969.77986 + 26.7283967539 + + + 12920.4220849 + 22.5609244114 + + + 14348.7491135 + 26.607851954 + + + 14610.9879544 + 22.5609244114 + + + 15919.7926485 + 28.8959034798 + + + 16294.8454171 + 23.6346248277 + + + 17951.4015092 + 28.0275666874 + + + 17951.4015092 + 22.2570503852 + + + 19897.9231698 + 25.5933542785 + + + 20698.8562635 + 23.0245320687 + + + 22437.202287 + 27.7439589652 + + + 22965.7980435 + 23.0781187566 + + + 25421.4042221 + 25.8257769694 + + + 24941.3536205 + 22.1066516695 + + + 28043.9410933 + 25.2315228338 + + + 31046.7525708 + 27.489835137 + + + 31138.2063005 + 22.2872526916 + + + 34455.4418934 + 24.8495209727 + + + 38028.0732611 + 26.3460521841 + + + 38520.5957796 + 22.1066516695 + + + 42292.4287439 + 25.7791241842 + + + 43065.36842 + 22.1066516695 + + + 46967.7728374 + 25.7791241842 + + + 49684.9137773 + 22.9466077754 + + + 52684.6444687 + 25.5803428176 + + + 57403.9632582 + 26.3460521841 + + + 58147.4335981 + 22.1066516695 + + + 63901.9569007 + 27.4818482 + + + 63901.9569007 + 21.9820960365 + + + 70831.0283271 + 27.6688161197 + + + 70831.0283271 + 21.7105383595 + + + 78511.4387289 + 24.1682382811 + + + 87024.6579342 + 27.6125925756 + + + 87024.6579342 + 21.8088962618 + + + 96460.9897763 + 24.2092399129 + + + 106920.529991 + 27.6125925756 + + + 106920.529991 + 21.7350861699 + + + 118514.227981 + 23.8588868021 + + + 131365.063707 + 26.8373539349 + + + 131365.063707 + 21.58821455 + + + 145609.3522 + 23.6174614719 + + + 161398.189517 + 26.2969736679 + + + 161398.189517 + 21.4423353932 + + + 178899.055492 + 23.7217777153 + + + 198297.590274 + 26.1015721568 + + + 198297.590274 + 21.369765891 + + + 219799.563505 + 23.2598962827 + + + 243633.057014 + 25.6976845068 + + + 243633.057014 + 20.6574428847 + + + 270050.884195 + 22.799277449 + + + 299333.271716 + 25.3343780715 + + + 299333.271716 + 20.1047185472 + + + 329662.877206 + 23.8588868021 + + + 339274.653635 + 20.0502661252 + + + 367767.858164 + 25.6976845068 + + + 374132.413297 + 20.4831035116 + + + 407645.975848 + 25.1973306346 + + + 414700.657846 + 20.1958014079 + + + 451848.191559 + 24.7234765831 + + + 459667.832845 + 19.811526636 + + + 500843.379579 + 24.5231340285 + + + 512642.697593 + 20.0852542982 + + + 564758.649726 + 21.7978087897 + + + 625997.04073 + 23.5774620971 + + + 625997.04073 + 19.2379075231 + + + 689636.749172 + 23.2261260899 + + + 705883.830893 + 19.205325517 + + + 769114.604489 + 22.7144136917 + + + 787234.096884 + 18.7322351616 + + + 864082.576482 + 22.1452282824 + + + 871741.018123 + 18.3337322022 + + + 961305.442026 + 19.9350439147 + + + 1065542.53262 + 20.7697980243 + + + 1065542.53262 + 17.7346304713 + + + 1181082.34821 + 19.5535209292 + + + 1320429.9007 + 18.8825251003 + + + 1451105.39509 + 18.2716834656 + + + 1608452.89143 + 18.2716834656 + + + 1782862.02553 + 17.4602102876 + + + 1962666.44592 + 17.2133628816 + + + 2190465.98052 + 17.1434782164 + + + 2448903.56843 + 16.4684203424 + + + 2691257.73229 + 16.1833897503 + + + 2971468.57786 + 16.2033525998 + + + 3335030.81428 + 15.7432583049 + + + 3652524.55746 + 15.6439453363 + + + 3976293.10823 + 13.7763534178 + + + 4087465.6845 + 16.2462130943 + + + 4518481.91559 + 15.5045570705 + + + 4991276.4477 + 15.1122323389 + + + 5532494.78735 + 14.7428240747 + + + 6127618.16432 + 14.9925450119 + + + 6785699.68075 + 14.4039155145 + + + 7534408.79972 + 16.194366272 + + + 7534408.79972 + 13.2346304135 + + + 8351386.23297 + 14.6233580673 + + + 9200399.48763 + 14.7606849856 + + + 9629562.5246 + 12.7645958007 + + + 9914577.62975 + 17.1434782164 + + + 10173059.0369 + 12.7645958007 + + + + + + + + + measured at 1000 Hz and room temperature + 0.040229885 + + + + measured at 1000 Hz and room temperature + 3.93e-08 + S/m + + + + dependence of effective conductivities on the frequency for PVDF/xGnP nanocomposites at room temperature. + + Frequency + Hz + Conductivity + S/m + + + + frequency (Hz) + Conductivity (S/m) + + + + 50.5167164867 + 5.3187318445e-09 + + + 56.3360319205 + 4.97664502021e-09 + + + 62.8090779026 + 5.89003239432e-09 + + + 62.8213314277 + 4.95360235356e-09 + + + 70.0435597069 + 5.57176611684e-09 + + + 78.0963415248 + 6.24907163218e-09 + + + 78.1125393039 + 5.19843161236e-09 + + + 87.8760737692 + 6.53478416542e-09 + + + 84.7581014525 + 5.51016437285e-09 + + + 97.0947521873 + 7.24204236272e-09 + + + 109.044194649 + 8.29454841555e-09 + + + 104.409712971 + 7.25088549603e-09 + + + 120.721926393 + 7.96934453536e-09 + + + 134.609614129 + 8.45059997199e-09 + + + 150.088308277 + 9.31837981187e-09 + + + 167.352963506 + 9.94954493728e-09 + + + 186.619838078 + 9.83252172979e-09 + + + 208.92650523 + 1.14672355677e-08 + + + 198.863048334 + 9.95871193363e-09 + + + 231.987064838 + 1.28579927574e-08 + + + 260.07439259 + 1.42623837945e-08 + + + 251.74933335 + 1.24545073583e-08 + + + 288.419965119 + 1.50086460168e-08 + + + 323.920675677 + 1.69610345341e-08 + + + 310.166644577 + 1.42893357505e-08 + + + 358.570441291 + 1.79680951331e-08 + + + 399.814460274 + 1.92847160967e-08 + + + 445.812188542 + 2.03027754208e-08 + + + 497.069365313 + 2.26510321765e-08 + + + 554.239282741 + 2.44956256656e-08 + + + 617.991013775 + 2.62452238226e-08 + + + 689.059528913 + 2.8716436267e-08 + + + 768.303112027 + 3.13391060187e-08 + + + 856.657131068 + 3.42998149166e-08 + + + 955.1841465 + 3.71108158079e-08 + + + 1064.98441672 + 4.216422581e-08 + + + 1187.46492717 + 4.58565372725e-08 + + + 1336.01606038 + 5.30114122115e-08 + + + 1476.19613103 + 5.78822549001e-08 + + + 1645.91440634 + 6.48251470224e-08 + + + 1835.17789917 + 7.14613906506e-08 + + + 2046.1782555 + 7.96885389575e-08 + + + 2281.43477079 + 8.8990740653e-08 + + + 2543.74782136 + 9.90933855194e-08 + + + 2836.15105285 + 1.12781473004e-07 + + + 3162.1987587 + 1.27184357456e-07 + + + 3525.72820099 + 1.4346783651e-07 + + + 3959.57048238 + 1.66871233062e-07 + + + 4382.84871363 + 1.86966533834e-07 + + + 4906.85878318 + 2.13051850698e-07 + + + 5448.45563262 + 2.39072192859e-07 + + + 6049.82685576 + 2.68452877655e-07 + + + 6699.38781856 + 3.20659195099e-07 + + + 7446.27948416 + 3.56757320306e-07 + + + 8327.8747603 + 4.25277698346e-07 + + + 9218.40387529 + 4.63861474739e-07 + + + 10278.0106697 + 5.30066255296e-07 + + + 11563.22893 + 6.3941840336e-07 + + + 12723.7885578 + 7.02022838388e-07 + + + 14115.1916477 + 8.56703212565e-07 + + + 15660.792173 + 9.31239053922e-07 + + + 17460.639175 + 1.0793104795e-06 + + + 19387.4060726 + 1.23686928863e-06 + + + 21772.3094248 + 1.48177845536e-06 + + + 24273.9301946 + 1.75575510616e-06 + + + 26979.8251505 + 1.97420450439e-06 + + + 30173.7615862 + 2.37526310907e-06 + + + 33399.3096784 + 2.66329267369e-06 + + + 37391.0992112 + 3.13791650505e-06 + + + 41688.0738432 + 3.65784097375e-06 + + + 46098.1628639 + 4.15266763884e-06 + + + 51140.2324828 + 4.97788432425e-06 + + + 56737.0432949 + 5.6707668137e-06 + + + 63455.1574179 + 6.68608922734e-06 + + + 69948.84536 + 7.52818437063e-06 + + + 77458.857372 + 9.02234424094e-06 + + + 86092.5307265 + 1.02416436591e-05 + + + 95986.0792405 + 1.19585866352e-05 + + + 106576.945983 + 1.38323529489e-05 + + + 118823.744617 + 1.62444300708e-05 + + + 133681.172253 + 1.97181362221e-05 + + + 147703.395581 + 2.20711991991e-05 + + + 165361.293783 + 2.534131356e-05 + + + 183151.820754 + 2.94451022608e-05 + + + 200108.590115 + 3.47817728744e-05 + + + 221695.225654 + 3.9947332889e-05 + + + 247173.386524 + 4.6398037923e-05 + + + 273590.468097 + 5.29664962499e-05 + + + 307252.102484 + 6.22837562846e-05 + + + 340091.192173 + 7.09173053773e-05 + + + 379177.962099 + 8.19767178926e-05 + + + 422764.108315 + 9.33541104511e-05 + + + 473262.089094 + 0.000116262882068 + + + 525518.863685 + 0.000126075808339 + + + 585920.681771 + 0.00014490115202 + + + 655974.576147 + 0.000164746688648 + + + 723155.825365 + 0.000174016672449 + + + 872543.127478 + 0.000215863565332 + + + 978058.988407 + 0.000249343690735 + + + 1091473.21988 + 0.00028470939215 + + + 1205357.50636 + 0.0003202242385 + + + 1334781.81675 + 0.000380758340795 + + + 1483551.03129 + 0.000434144878018 + + + 1647396.70171 + 0.000462104499324 + + + 1836796.71694 + 0.000517831050679 + + + 2056256.02514 + 0.000628655468807 + + + 2304056.71548 + 0.000701264829763 + + + 2222280.43123 + 0.000597235507231 + + + 2545950.42156 + 0.000728461915318 + + + 2838674.90928 + 0.000811627061072 + + + 3187871.29025 + 0.000971682830986 + + + 3560963.1451 + 0.00105565323688 + + + 3963279.75644 + 0.00115196178432 + + + 4387309.05875 + 0.00120134465439 + + + 4912009.11057 + 0.00133073316054 + + + 5454198.36977 + 0.00148745129523 + + + 6081523.75965 + 0.00160473146126 + + + 6781000.02001 + 0.00173175675903 + + + 7560819.8688 + 0.0018926377944 + + + 8430540.83366 + 0.00202083250152 + + + + + + + + diff --git a/whyis/materialsmine/tests/xml/L141_S19_Gao_2013.xml b/whyis/materialsmine/tests/xml/L141_S19_Gao_2013.xml new file mode 100644 index 00000000..3f2c5796 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L141_S19_Gao_2013.xml @@ -0,0 +1,253 @@ + + + L141_S19_Gao_2013 + L141_S1_Gao_2013 + PNC_schema_010720 + 5e496fa88aba2cf1302d73e3 + 5e4c12fec941bb7a1270ddbb + + + + research article + Polymer + Effect of graft density and molecular weight on mechanical properties of rubbery block copolymer grafted SiO2 nanoparticle toughened epoxy + Gao, Jianing + Li, Junting + Zhao, Su + Benicewicz, Brian C. + Hillborg, Henrik + Schadler, Linda S. + Rubbery copolymer + Grafted particle + Toughening epoxy + Elsevier + 2013 + 10.1016/j.polymer.2013.05.033 + 54 + https://www.sciencedirect.com/science/article/pii/S0032386113004643?via%3Dihub + English + Department of Materials Science & Engineering, Rensselaer Polytechnic Institute, Troy, NY 12180, USA + 2016-07-12 + + + + 0032-3861 + 15 + + + + + + + + BISPHENOL A DIGLYCIDYL ETHER + DGEBA Epoxy Resin + CC(C)(C1=CC=C(OCC2CO2)C=C1)C3=CC=C(OCC4CO4)C=C3 + 2286 + DGEBA + C2H3OCH2OC6H3C3H6C6H5OCH2C2H3O + thermoset + homopolymer + Huntsman Corporation + Araldite F + + molecular weight between crosslinks + 312 + g/mol + + + inserted from ChemProps, NanoMine + 1.13 + g/cm3 + + + Aradur HY 90F + + + benzyldimethylamine + + + + + + Curing Agent + Aradur HY 90F + + + + + + + Catalyst + benzyldimethylamine + + + + + + + Silicon dioxide + Silicon dioxide + 24261 + SiO2 + Nissan + + inserted from ChemProps, NanoMine + 2.65 + g/cm3 + + Amorphous + + nanoparticle diameter + 15 + nm + + + polyglycidylmethacrylate + PGMA + C7H10O13 + + 0.7 + chains/nm2 + + + short brush + 20000 + g/mol + + + + Reversible addition-fragmentation chain-transfer polymerization + + + + + Polyhexylmethacrylate + PHMA + C10H18O2 + + Long brush + 40000 + g/mol + + + + + Nanoparticle volume fraction + + + 0.009330328850080982 + computed by NanoMine + + + 0.004 + reported + + + + Silica nanoparticle with grafted PHMA/PGMA + + + + Mixing and Epoxy Curing + + + + CHCl2 + + + + + Mixing of nanoparticles and epoxy + + + + + First curing step + + 80 + Celsius + + + + + + + + + Second curing step + + 135 + Celsius + + + + + + + + + JOEL High Resolution TEM + + + + + + + Modulus + 3.2 + GPa + + absolute + 0.1 + + + + Yield Stress + 76 + MPa + + absolute + 0.5 + + + + strain at break + 0.079 + + absolute + 0.02 + + + + + Tensile test strain rate + 0.1 + mm/min + + + + + + + + http://localhost/nmr/blob?id=5ac63561e74a1d06fd9ada29 + TEM micrograph showing particle disperison + TEM + grayscale + + + + TEM sample thickness + 100 + nm + + + + diff --git a/whyis/materialsmine/tests/xml/L150_S7_Akcora_2009.xml b/whyis/materialsmine/tests/xml/L150_S7_Akcora_2009.xml new file mode 100644 index 00000000..d0eb0d8f --- /dev/null +++ b/whyis/materialsmine/tests/xml/L150_S7_Akcora_2009.xml @@ -0,0 +1,538 @@ + + + L150_S7_Akcora_2009 + + + + research article + Nature Materials + Anisotropic self-assembly of spherical polymer-grafted nanoparticles + Akcora, Pinar + Liu, Hongjun + Kumar, Sanat K. + Moll, Joseph + Li, Yu + Benicewicz, Brian C. + Schadler, Linda S. + Acehan, Devrim + Panagiotopoulos, Athanassios Z. + Pryamitsyn, Victor + Ganesan, Venkat + Ilavsky, Jan + Thiyagarajan, Pappanan + Colby, Ralph H. + Douglas, Jack F. + Nature Publishing Group + 2009 + 10.1038/nmat2404 + 8 + http://www.nature.com/articles/nmat2404 + English + Department of Chemical Engineering, Columbia University, New York, New York 10027, USA + 2016-06-30 + + + + 1476-4660 + 4 + + + + + + + + polystyrene + PS + homopolymer + + 42 + kg/mol + + + + + + silica + SiO2 + Nissan Chemicals + + 14 + nm + + absolute + 4 + + + + + + 0.05 + + + + + + + + + ultra-sonication + + SiO2 + + + benzene or tetrahydrofuran + + + + + + + ultra-sonication + + polystyrene + + + SiO2 + + + benzene or tetrahydrofuran + + + + + + + annealing + + 150 + Celsius + + + + + + casting + + + + + + + used + + + ultrasmall-angle X-ray scattering (USAXS) + + + + + + + shear-stress response at 180 C with 37 chains grafted + + + Strain + Shear stress (Pa) + + + + 1.552618473 + 115.3782823 + + + 2.397249904 + 118.6468288 + + + 3.244094955 + 89.98576175 + + + 4.094070214 + 111.1087434 + + + 4.97019461 + 96.68628205 + + + 5.917928187 + 86.91468994 + + + 6.991933083 + 90.7802812 + + + 8.14582768 + 88.58562957 + + + 8.961824622 + 79.93498128 + + + 9.989841114 + 113.1311566 + + + 10.90780728 + 87.47647137 + + + 10.87964058 + 58.07657662 + + + 12.77601067 + 118.1871894 + + + 12.12765094 + 87.28921089 + + + 14.95313466 + 119.8214627 + + + 17.09570692 + 79.42427089 + + + 17.65709257 + 116.4697434 + + + 20.07907805 + 81.5688492 + + + 21.31724466 + 115.4157344 + + + 23.08770716 + 84.17132396 + + + 25.04218402 + 122.1945636 + + + 29.43214238 + 129.029571 + + + 30.39606706 + 71.29667984 + + + 33.83255545 + 109.2873889 + + + 35.47776926 + 141.220228 + + + 37.9296784 + 167.8997387 + + + 40.08494767 + 115.2378369 + + + 40.94918974 + 69.7897194 + + + 42.28061546 + 145.5416236 + + + 42.1351059 + 94.5299493 + + + 49.3759866 + 150.0044467 + + + 49.3759866 + 123.8084085 + + + 49.3759866 + 98.93340777 + + + 49.3759866 + 79.01570258 + + + 59.65247142 + 145.7847021 + + + 58.56359399 + 116.3520368 + + + 57.49459259 + 86.30609339 + + + 58.56359399 + 74.93001947 + + + 66.07392394 + 169.4341397 + + + 67.33870474 + 214.2518137 + + + 69.46077997 + 128.4865156 + + + 73.14721874 + 101.3961668 + + + 78.56301717 + 177.8764662 + + + 78.09888307 + 146.2138407 + + + 86.62995534 + 110.4426312 + + + 86.31056033 + 94.59236946 + + + 91.83616305 + 188.6141521 + + + 91.83616305 + 163.8957693 + + + 91.69380303 + 139.64724 + + + 102.3707466 + 103.8157991 + + + 109.6875957 + 180.2078591 + + + 108.9245226 + 145.7144794 + + + 110.3418359 + 123.9922642 + + + 116.2155979 + 86.36392383 + + + 127.2038192 + 187.8926724 + + + 129.1925884 + 162.4657802 + + + 129.1925884 + 137.7473974 + + + 129.1925884 + 113.0290145 + + + 138.3549381 + 87.5701016 + + + 153.2320226 + 161.0153627 + + + 153.2320226 + 136.3174083 + + + 153.2320226 + 111.5990254 + + + 164.85867 + 84.0790313 + + + 173.8528222 + 63.18269935 + + + 182.7340904 + 140.6584466 + + + 182.8758881 + 106.614492 + + + 192.9517716 + 167.7577126 + + + 199.6803474 + 85.49151032 + + + 208.9770076 + 194.9923574 + + + 217.8902468 + 118.5761151 + + + 228.6523704 + 165.6389941 + + + 224.6673346 + 140.7208667 + + + 233.9837148 + 89.00130667 + + + 261.5573504 + 123.8424558 + + + 270.4910591 + 170.6694018 + + + 275.2252144 + 137.287758 + + + 278.8276163 + 92.11392198 + + + 300.9044069 + 179.9831466 + + + 305.6088994 + 149.459689 + + + 303.2475302 + 127.2880486 + + + 308.9457397 + 94.70472574 + + + 307.9886563 + 80.54783375 + + + + + + steady-shear application at 180 C with 37 chains grafted + + + Strain + Shear stress (Pa) + + + + 922.6457063 + 39.65014577 + + + 724.6692949 + 37.31778426 + + + 560.0821712 + 41.98250729 + + + 380.5568822 + 37.31778426 + + + 275.7778875 + 37.31778426 + + + 203.0917621 + 39.65014577 + + + 140.2339435 + 39.65014577 + + + 95.28421909 + 39.65014577 + + + 59.73429965 + 39.65014577 + + + 29.88990093 + 39.65014577 + + + + + + + + + 0.5 um + + https://nanomine.org/nmr/blob?id=595d18bde74a1d5e0d187d64 + TEM + grayscale + + + diff --git a/whyis/materialsmine/tests/xml/L155_S2_Roy_2005.xml b/whyis/materialsmine/tests/xml/L155_S2_Roy_2005.xml new file mode 100644 index 00000000..77fecc1d --- /dev/null +++ b/whyis/materialsmine/tests/xml/L155_S2_Roy_2005.xml @@ -0,0 +1,2418 @@ + + + L155_S2_Roy_2005 + L155_S1_Roy_2005 + + + + research article + IEEE Transactions on Dielectrics and Electrical Insulation + Polymer nanocomposite dielectrics-the role of the interface + Roy, M. + Nelson, J.K. + MacCrone, R.K. + Schadler, L.S. + Reed, C.W. + Keefe, R. + Polymers + Dielectrics + Silicon compounds + Polyethylene + Breakdown voltage + Bonding + Infrared spectra + Spectroscopy + Paramagnetic resonance + Nanoparticles + X-ray photoelectron spectra + nanocomposites + filled polymers + nanoparticles + polyethylene insulation + electric breakdown + bonding processes + permittivity + paramagnetic resonance + Fourier transform spectroscopy + electrical insulation + polymer nanocomposite dielectrics + silica nanoparticles + polyethylene + breakdown strength + voltage endurance + micron scale fillers + dielectric spectroscopy + dielectric permittivity + space charge distribution + nanoscale fillers + interfacial region + Fourier transformed infrared spectroscopy + electron paramagnetic resonance + x-ray photoelectron spectroscopy + particle-polymer bonding + IEEE + 2005 + 10.1109/TDEI.2005.1511089 + 12 + http://ieeexplore.ieee.org:80/document/1511089/?reload=true + English + Rensselaer Polytech. Inst., Troy, NY, USA + + + + 1070-9878 + 4 + + + + + + + + Polyethylene + XLPE + thermoset + + non-ionic antioxidants + + + + + + nanosilica + SiO2 + + + + + + 195 + Celsius + + + vacuum + + + + + + 0.05 + + + + + + + + + melt mixed at unspecified temperature above the matrix polymer melting point (> 105 Celsius). + + + + + + + hot-pressing + + hot pressed at unspecified temperature and then isobarically cooled + + + + + + + + post-press curing of the matrix under vacuum (hardening/curing agent/additive was already in the matrix) + dicumyl peroxide + + + + + + + SEM micrograph of XLPE with 5% untreated nanosilica + + + Novocontrol Alpha Analyzer (type K) in combination with a Novocontrol active BDS-1200 sample cell + Measurements were performed on circularly laminar samples of 0.5 mm thickness with sputtered gold electrodes (15 nm thick) on both sides, at multiple temperatures + + + Rheometric Scientific DMTA (Model - V) + 2 cycles with the following ramps were performed and the second cycle was used for calculations/measurements with ~ 5 mg og materials and for four specimens. + + 10 + Celsius/minute + + + 10 + Celsius/minute + + Dwell time of 5 minutes at 150 Celsius is used after the sample is heated to 150 Celsius + + + Nicolet NEXUS 470-ESP + FTIR spectrum of only untreated nanosilica particles powder + + only filler FTIR spectrum + + + Wavenumber + 1/cm + Absorbance + a.u. + + + + Wavenumber (cm-1) + Absorbance (a.u.) + + + + 3991.24248983 + 0.847711836541 + + + 4002.35536316 + 0.705205339876 + + + 4003.09622138 + 0.606714555061 + + + 4002.35536316 + 0.484100719355 + + + 4002.35536316 + 0.400952283545 + + + 4002.35536316 + 0.301110018458 + + + 4002.35536316 + 0.209538710242 + + + 4002.35536316 + 0.121225146262 + + + 4003.09622138 + 0.0326426301893 + + + 3935.67812317 + 0.871587089002 + + + 3871.96431607 + 0.905874321112 + + + 3830.10582652 + 0.934168609387 + + + 3777.87532186 + 0.98700689618 + + + 3766.76244853 + 1.05400172683 + + + 3753.42700053 + 1.97087621485 + + + 3751.20442587 + 1.87706501248 + + + 3751.20442587 + 1.758900046 + + + 3735.39945046 + 1.54698211543 + + + 3742.3141272 + 1.45672660854 + + + 3753.42700053 + 1.37005027643 + + + 3753.42700053 + 1.24013717529 + + + 3753.42700053 + 1.17154731152 + + + 3736.75769054 + 1.65803161108 + + + 3700.08520854 + 1.77760965602 + + + 3680.08203655 + 1.89987142208 + + + 3666.74658855 + 1.95065856916 + + + 3630.07410655 + 2.0517746568 + + + 3602.29192323 + 2.11420792155 + + + 3568.95330323 + 2.2130545359 + + + 3537.8372579 + 2.3094232231 + + + 3508.94378724 + 2.37519272977 + + + 3455.60199525 + 2.41741212871 + + + 3393.92554826 + 2.38816376848 + + + 3349.87094326 + 2.37385508909 + + + 3297.79919394 + 2.30886700672 + + + 3238.23419288 + 2.21042776512 + + + 3206.67363262 + 2.13930890369 + + + 3164.44471396 + 2.04341168264 + + + 3131.10609397 + 1.94453178926 + + + 3111.10292197 + 1.87419841675 + + + 3091.84060819 + 1.77846251095 + + + 3075.54172731 + 1.6945467377 + + + 3059.98370464 + 1.60383808412 + + + 3042.20310731 + 1.52316937542 + + + 3010.64254705 + 1.44230260054 + + + 3001.75224839 + 1.33254537891 + + + 2991.82474821 + 1.20198316351 + + + 2987.75002799 + 1.05949992521 + + + 2986.63874066 + 0.926690309216 + + + 2991.08388999 + 0.821714955018 + + + 2986.63874066 + 0.0165896620742 + + + 2984.41616599 + 0.723044175494 + + + 2984.41616599 + 0.578775056357 + + + 2984.41616599 + 0.498664931233 + + + 2985.15702421 + 0.379170417167 + + + 2984.41616599 + 0.293072574722 + + + 2984.41616599 + 0.179642309061 + + + 2984.41616599 + 0.10343134932 + + + 2975.52586732 + 4.43661160001 + + + 2982.19359132 + 4.36119843015 + + + 2977.74844199 + 4.17787185913 + + + 2976.26672555 + 4.02515230839 + + + 2975.08135239 + 3.83647817456 + + + 2977.00758377 + 3.68356290958 + + + 2977.00758377 + 3.49321274502 + + + 2976.26672555 + 3.33354277193 + + + 2975.08135239 + 3.24330877907 + + + 2977.74844199 + 3.11897275932 + + + 2974.41457999 + 3.03665200585 + + + 2979.97101666 + 2.92624313137 + + + 2974.7850091 + 2.83814960092 + + + 2975.52586732 + 2.69636288881 + + + 2971.08071799 + 2.54944822078 + + + 2973.30329266 + 2.44202760513 + + + 2967.08008359 + 2.31345208067 + + + 2963.67213577 + 2.23258060192 + + + 2963.67213577 + 2.11438468969 + + + 2963.67213577 + 2.03880389809 + + + 2963.67213577 + 1.92234094824 + + + 2961.23788733 + 1.84298109439 + + + 2960.52348833 + 1.72630466416 + + + 2961.87290866 + 1.63985410541 + + + 2961.07913199 + 1.52653235656 + + + 2958.69780199 + 1.43577610439 + + + 2975.52586732 + 4.27818339042 + + + 2973.30329266 + 3.92636897218 + + + 2971.08071799 + 3.6073429901 + + + 2971.08071799 + 3.4194741126 + + + 2935.34855605 + 1.36489233574 + + + 2922.69697718 + 1.29214721874 + + + 2912.34124467 + 1.18845505451 + + + 2889.7344852 + 4.47297652038 + + + 2871.62050167 + 1.45808787852 + + + 2885.88202245 + 4.38586570504 + + + 2885.88202245 + 4.28740193277 + + + 2885.88202245 + 4.18192753991 + + + 2885.88202245 + 4.09283751875 + + + 2895.51317934 + 3.98296650847 + + + 2895.51317934 + 3.90852789662 + + + 2895.51317934 + 3.78233672608 + + + 2895.51317934 + 3.71002493172 + + + 2889.7344852 + 3.55383689894 + + + 2881.066444 + 3.41570472341 + + + 2885.88202245 + 3.30260666798 + + + 2888.84545534 + 3.18469093417 + + + 2881.066444 + 2.94718455579 + + + 2887.36373889 + 2.77007744194 + + + 2876.99172378 + 2.63343343199 + + + 2882.17773134 + 2.50693501714 + + + 2882.17773134 + 2.40555671721 + + + 2882.17773134 + 2.30807758265 + + + 2885.88202245 + 2.18697274259 + + + 2882.17773134 + 2.11170143523 + + + 2889.7344852 + 1.99556499312 + + + 2887.734168 + 1.8160822051 + + + 2882.17773134 + 1.72178489702 + + + 2880.84418654 + 1.61189731122 + + + 2881.43687312 + 1.51678220317 + + + 2869.58314156 + 3.1040790638 + + + 2842.41834009 + 1.89621947609 + + + 2845.50524934 + 1.30197206762 + + + 2842.17138734 + 4.46551589702 + + + 2839.94881268 + 1.4158475702 + + + 2839.94881268 + 4.36778921241 + + + 2840.93662364 + 4.23037128921 + + + 2838.67877001 + 3.80625346303 + + + 2837.72623801 + 3.68760599073 + + + 2841.43052912 + 3.59303854392 + + + 2841.06010001 + 3.48367286545 + + + 2839.94881268 + 3.3846458884 + + + 2839.94881268 + 3.28954001208 + + + 2839.20795446 + 3.18807619466 + + + 2838.04374868 + 3.01985571101 + + + 2839.05978281 + 2.90491554231 + + + 2840.6896709 + 2.80361116287 + + + 2839.94881268 + 2.70324732644 + + + 2839.20795446 + 2.5959544537 + + + 2839.94881268 + 2.49812759604 + + + 2839.94881268 + 2.40401423455 + + + 2839.94881268 + 2.30751748712 + + + 2839.94881268 + 2.20403600101 + + + 2839.94881268 + 2.10951077962 + + + 2839.94881268 + 2.01883408511 + + + 2838.04374868 + 1.7325282955 + + + 2841.21885534 + 1.61474309499 + + + 2838.17075294 + 4.05590055653 + + + 2837.72623801 + 3.95220065284 + + + 2842.17138734 + 3.09582574641 + + + 2842.17138734 + 1.8194398664 + + + 2835.50366335 + 1.51340438247 + + + 2835.50366335 + 1.21065360197 + + + 2835.50366335 + 1.12348784425 + + + 2835.50366335 + 1.0313257534 + + + 2836.61495068 + 0.934565677715 + + + 2835.50366335 + 0.817673433821 + + + 2820.39015561 + 0.707790335889 + + + 2823.94627508 + 0.620629954011 + + + 2825.72433481 + 0.529760145174 + + + 2825.13164824 + 0.436195034233 + + + 2833.72560361 + 0.34412470602 + + + 2831.05851401 + 0.222048102522 + + + 2831.05851401 + 0.107807620677 + + + 2831.05851401 + 0.0290140968518 + + + 2833.28108868 + 4.13792755331 + + + 2835.50366335 + 3.87653491707 + + + 2768.33251787 + 0.769310575471 + + + 2722.15235536 + 0.70651934125 + + + 2677.2563471 + 0.774686865432 + + + 2637.37700738 + 0.762473336455 + + + 2578.79628939 + 0.725798454531 + + + 2541.23477752 + 0.770227604514 + + + 2497.67231407 + 0.846097011629 + + + 2432.970696 + 0.783770097093 + + + 2397.65645408 + 0.771605668005 + + + 2358.39096831 + 0.845886457818 + + + 2288.75029543 + 0.861427969452 + + + 2225.24816211 + 0.813501596454 + + + 2183.97177545 + 0.800273185309 + + + 2128.72491946 + 0.867201297924 + + + 2097.60887413 + 0.922687826871 + + + 2070.93797813 + 1.01977217303 + + + 2050.93480614 + 1.09276266744 + + + 2026.48648481 + 1.20615597418 + + + 1998.92655894 + 1.2635383834 + + + 1948.69637148 + 1.32005942594 + + + 1922.02547549 + 1.4426065036 + + + 1908.69002749 + 1.51436643419 + + + 1875.3514075 + 1.61840119421 + + + 1843.3463323 + 1.47414169661 + + + 1824.23219017 + 1.37245092586 + + + 1810.89674217 + 1.26697606635 + + + 1769.30284485 + 1.2123501921 + + + 1735.32920352 + 1.27217887341 + + + 1701.99058352 + 1.36517673969 + + + 1682.72826975 + 1.47267005987 + + + 1666.42938886 + 1.55889968511 + + + 1631.85600516 + 1.63919385815 + + + 1635.31334353 + 1.74081369766 + + + 1605.67901465 + 1.44655914741 + + + 1596.19602941 + 1.29993619347 + + + 1573.08125288 + 1.2066521196 + + + 1538.40908808 + 1.1153828665 + + + 1484.98647519 + 1.04037552375 + + + 1474.3001566 + 0.916873011133 + + + 1477.82805289 + 0.802870960375 + + + 1477.19303156 + 0.687496180445 + + + 1471.47783956 + 0.579733611036 + + + 1469.47507997 + 0.472252661481 + + + 1473.50990783 + 4.156512223 + + + 1475.28796756 + 4.04216808821 + + + 1472.50974923 + 3.87152054447 + + + 1470.84281823 + 3.7846729774 + + + 1473.50990783 + 3.70325703466 + + + 1474.65294623 + 3.58890542923 + + + 1473.50990783 + 3.47653829117 + + + 1473.50990783 + 3.39641466245 + + + 1473.50990783 + 3.2958600823 + + + 1473.50990783 + 3.20608812919 + + + 1474.65294623 + 3.08900686685 + + + 1473.50990783 + 2.98307612474 + + + 1477.51054222 + 2.86500329155 + + + 1470.84281823 + 2.72650250951 + + + 1473.06539289 + 2.61047616016 + + + 1474.65294623 + 2.4909178194 + + + 1473.50990783 + 2.3799917087 + + + 1473.50990783 + 2.28345445046 + + + 1474.17668023 + 2.21219188126 + + + 1475.28796756 + 2.08385963143 + + + 1470.84281823 + 1.94771314908 + + + 1474.65294623 + 1.8175702985 + + + 1473.06539289 + 1.70245450524 + + + 1473.50990783 + 1.61012429134 + + + 1473.50990783 + 1.50990054946 + + + 1473.50990783 + 1.42239720167 + + + 1474.65294623 + 1.30794914192 + + + 1473.50990783 + 1.19656969598 + + + 1470.84281823 + 1.12059776921 + + + 1464.17509423 + 0.371865648561 + + + 1465.90376341 + 0.264979507199 + + + 1464.91595245 + 0.18192522862 + + + 1470.84281823 + 0.0669162263363 + + + 1477.51054222 + 2.80930092895 + + + 1479.73311689 + 0.00367756163181 + + + 1475.28796756 + 3.99499831478 + + + 1439.7267729 + 0.563679020112 + + + 1407.86986935 + 0.944606889215 + + + 1413.0558769 + 0.811767407431 + + + 1413.0558769 + 0.714288272878 + + + 1413.0558769 + 0.613264442524 + + + 1415.27845157 + 1.03685895075 + + + 1381.93983157 + 0.518101399889 + + + 1382.57485291 + 0.356835580377 + + + 1381.19897335 + 0.189152509504 + + + 1384.16240624 + 0.0886057851247 + + + 1388.60755557 + 0.0248079804927 + + + 1373.04953291 + 0.85215584686 + + + 1378.97639868 + 0.753819190848 + + + 1381.93983157 + 0.670995945478 + + + 1373.04953291 + 0.620293355906 + + + 1361.93665958 + 0.966238866666 + + + 1356.75065202 + 1.14630157363 + + + 1357.49151024 + 1.05449507233 + + + 1348.60121158 + 1.26007398924 + + + 1346.37863691 + 1.34762461564 + + + 1334.15447625 + 1.53193031789 + + + 1326.37546492 + 1.73325727978 + + + 1326.37546492 + 1.65881866794 + + + 1317.48516625 + 1.84312941003 + + + 1307.85400936 + 2.08060946919 + + + 1308.59486758 + 1.9636356277 + + + 1301.92714359 + 2.1621285129 + + + 1295.25941959 + 2.28334702962 + + + 1288.59169559 + 2.44332088711 + + + 1281.92397159 + 2.6486077726 + + + 1286.36912092 + 2.52011926958 + + + 1273.03367292 + 2.85330051556 + + + 1277.47882226 + 2.72546187344 + + + 1268.58852359 + 2.91709832019 + + + 1257.47565026 + 3.02814865581 + + + 1255.25307559 + 3.11611283006 + + + 1241.9176276 + 3.24317001515 + + + 1205.61557471 + 3.36127166349 + + + 1163.63360879 + 3.33592270197 + + + 1170.79523827 + 3.20569549673 + + + 1175.24038761 + 3.15090712726 + + + 1150.79206628 + 3.4379905283 + + + 1141.90176761 + 3.54691740634 + + + 1112.26743873 + 3.67385148839 + + + 1081.89225162 + 3.54694906541 + + + 1068.55680362 + 3.46002056072 + + + 1057.44393029 + 3.38379280147 + + + 1037.44075829 + 3.32651572516 + + + 1026.32788496 + 3.22246210387 + + + 1015.21501163 + 3.15420991018 + + + 999.656988966 + 3.03708539577 + + + 986.321540969 + 2.95431290625 + + + 996.323126967 + 2.85450686009 + + + 972.986092971 + 2.79170092631 + + + 979.65381697 + 2.6880286538 + + + 955.20549564 + 2.91307987831 + + + 932.979748977 + 2.74467322871 + + + 921.866875645 + 2.65781138206 + + + 894.24344765 + 2.55082108709 + + + 890.009972095 + 2.49470721658 + + + 853.775269959 + 2.66417483136 + + + 841.854187658 + 2.87391686953 + + + 844.076762324 + 2.78175813858 + + + 818.517153661 + 2.99573050876 + + + 808.515567663 + 3.02953769498 + + + 781.844671667 + 2.96953293885 + + + 779.622097001 + 2.8826845318 + + + 770.731798336 + 2.80291543665 + + + 764.064074337 + 2.70956170083 + + + 750.728626339 + 2.62683197271 + + + 728.502879676 + 2.47191879846 + + + 729.243737898 + 2.36951365671 + + + 729.772922342 + 2.2319043018 + + + 731.169969275 + 2.1101410491 + + + 727.613849809 + 1.97622719356 + + + 732.948029008 + 1.91313967205 + + + 726.280305009 + 1.79615463088 + + + 686.273961016 + 2.54668348871 + + + 664.048214352 + 2.65624006824 + + + 627.153474891 + 2.73712151469 + + + 587.369388364 + 2.7046175595 + + + 548.474331704 + 2.6473217704 + + + 524.026010374 + 2.8015972354 + + + 519.580861042 + 2.91832916401 + + + 510.690562376 + 3.00102529311 + + + + + + + + Perkin Elmer (Model # 5500) + XPS spectrum of just untreated nanosilica particless after 3 minutes of Argon cleaning + + Only untreated silica nanoparticle spectrum + + + Binding Energy + eV + Intensity + C.P.S + + + + Binding Energy (eV) + Intensity (C.P.S) + + + + 988.553954707 + 38485.3407183 + + + 974.945477898 + 38468.0991523 + + + 959.958915053 + 38851.6925336 + + + 945.316044449 + 39013.5618929 + + + 930.22743583 + 39530.5320018 + + + 917.723372117 + 39832.4985239 + + + 903.101519772 + 40411.9226876 + + + 891.02252608 + 40879.9991704 + + + 876.11669559 + 41261.0370804 + + + 860.761049452 + 41991.2936113 + + + 847.476087976 + 42789.2194434 + + + 831.903102942 + 43767.8384891 + + + 818.301436788 + 44748.5849862 + + + 802.668989067 + 46332.0609357 + + + 788.413367863 + 48809.2073085 + + + 778.523606789 + 49115.2821615 + + + 769.001515968 + 51529.9571908 + + + 770.929299241 + 54470.7894409 + + + 759.645107787 + 47162.2532088 + + + 750.561418392 + 51696.5333718 + + + 748.041717492 + 55201.2637137 + + + 748.508341611 + 61456.4343501 + + + 751.876649635 + 58059.3004894 + + + 749.385265176 + 65713.3332536 + + + 749.398826247 + 67700.4821688 + + + 744.180241093 + 48453.6087488 + + + 742.885255141 + 45057.4517304 + + + 741.592927468 + 42050.8210619 + + + 740.304124902 + 39560.7362051 + + + 739.642895563 + 35849.8226229 + + + 737.072167281 + 31877.3406404 + + + 729.893282142 + 28220.1590773 + + + 714.786893209 + 27684.7409504 + + + 697.110226483 + 27901.9137482 + + + 683.378451801 + 28453.6690311 + + + 670.439780167 + 28744.9256461 + + + 654.033279458 + 29238.9811125 + + + 640.082836682 + 29844.3271819 + + + 626.2876534 + 30422.7313818 + + + 612.076764544 + 31171.8823198 + + + 597.300436822 + 31893.1475068 + + + 584.206914711 + 32788.953835 + + + 569.578614553 + 32423.5584861 + + + 558.158352136 + 36236.4989904 + + + 557.155275169 + 38342.2483054 + + + 551.386744288 + 31691.2198229 + + + 545.641776731 + 28493.0037133 + + + 540.530696773 + 24999.2250919 + + + 541.781099742 + 21862.4889189 + + + 541.125068492 + 18913.2687099 + + + 534.379283311 + 55424.3613078 + + + 536.894187753 + 51216.7899434 + + + 533.440930407 + 42166.0165371 + + + 536.803575143 + 37939.0221919 + + + 536.103754541 + 121754.42772 + + + 535.450049285 + 119146.043067 + + + 536.06815673 + 116538.161817 + + + 535.406361062 + 112744.262187 + + + 534.753464847 + 110254.429032 + + + 534.735665942 + 107646.29608 + + + 535.13937748 + 104682.676437 + + + 534.125648908 + 80379.2837896 + + + 535.80279123 + 77653.2705451 + + + 535.784992324 + 75045.137594 + + + 535.767193419 + 72437.0046428 + + + 535.749394513 + 69828.8716916 + + + 533.819022309 + 66508.6746487 + + + 534.434972311 + 63584.6560718 + + + 533.428255429 + 102429.526775 + + + 533.338451861 + 89270.3105209 + + + 533.320652955 + 86662.1775697 + + + 533.30285405 + 84054.0446185 + + + 531.870851199 + 60580.3446545 + + + 531.853052293 + 57972.2117033 + + + 530.417004237 + 33905.7542504 + + + 528.662193964 + 25250.8237079 + + + 525.669921528 + 21628.8887719 + + + 522.66881706 + 16712.7666519 + + + 520.737366134 + 13234.5009452 + + + 511.944976502 + 10757.2528748 + + + 497.891302322 + 9695.26749495 + + + 485.104550639 + 9987.90147754 + + + 469.456723782 + 9317.8212283 + + + 455.212509785 + 9325.11600103 + + + 442.35242465 + 9225.42433319 + + + 427.232336158 + 9270.93149094 + + + 412.959959357 + 9292.82445342 + + + 398.404949339 + 9313.4080586 + + + 381.701485577 + 9259.376095 + + + 370.000808724 + 9254.74478383 + + + 356.919630269 + 9296.98751953 + + + 342.530220703 + 9326.85731911 + + + 326.252069878 + 9474.53070286 + + + 312.347241293 + 9516.44742494 + + + 300.600310401 + 9833.57957333 + + + 285.046794627 + 9671.61312911 + + + 272.071554333 + 9263.4033221 + + + 253.540582171 + 9425.42729814 + + + 237.876081361 + 9566.00469176 + + + 222.756810081 + 9731.26083717 + + + 208.99546944 + 10092.0052981 + + + 194.499959905 + 10548.6173408 + + + 181.150780787 + 11254.6405919 + + + 164.60826228 + 9936.12643913 + + + 154.252688268 + 14459.3652878 + + + 155.783214353 + 21309.5946858 + + + 155.126677453 + 18286.2797907 + + + 155.172388278 + 24984.4394153 + + + 146.676727976 + 10079.1936819 + + + 136.104420827 + 7692.13032837 + + + 122.622720767 + 7615.66335379 + + + 111.796571176 + 5304.71099675 + + + 104.827914419 + 9157.6886107 + + + 104.25646168 + 18602.0395656 + + + 103.372449374 + 13306.4037291 + + + 104.309453876 + 26367.1626702 + + + 104.287744605 + 23186.0308131 + + + 97.8100987797 + 5807.25140711 + + + 87.3351560957 + 3192.47033501 + + + 72.3519481053 + 2588.59475007 + + + 57.9397542822 + 2829.57242625 + + + 45.0086516778 + 2676.92373902 + + + 31.8163658668 + 3077.73980877 + + + 26.5882407695 + 5728.25303265 + + + 17.0261496053 + 2281.54442585 + + + 6.21173014768 + 1689.44765389 + + + + + + + + Novocontrol Alpha Analyzer (type K) in combination with a Novocontrol active BDS-1200 sample cell + + + + + + + + Measured at 25 Celsius + + Frequency + Hz + Real Part of Dielectric Permittivity + + + + Frequency (Hz) + Real Part of Dielectric Permittivity + + + + 0.002078949 + 3.21 + + + 0.005239995 + 2.88 + + + 0.013207416 + 2.595 + + + 0.033289313 + 2.385 + + + 0.082305244 + 2.2425 + + + 0.203493333 + 2.175 + + + 0.512905286 + 2.1 + + + 1.292778627 + 2.055 + + + 3.258450684 + 2.025 + + + 7.902591204 + 2.01 + + + 20.30583336 + 1.995 + + + 50.20459806 + 1.965 + + + 126.540773 + 1.95 + + + 318.9462293 + 1.95 + + + 773.5276395 + 1.95 + + + 1949.677704 + 1.935 + + + 4914.165902 + 1.9275 + + + 12386.16334 + 1.935 + + + 30623.82819 + 1.9275 + + + 78688.41195 + 1.92 + + + 190839.8845 + 1.92 + + + 481012.2468 + 1.905 + + + + + + + + Measured at 25 Celsius + + Frequency + Hz + Loss tangent + + + + Frequency (Hz) + tan delta + + + + 0.002132876 + 0.189265537 + + + 0.005323618 + 0.152777778 + + + 0.013287653 + 0.12405838 + + + 0.033643142 + 0.093691149 + + + 0.08278107 + 0.066148776 + + + 0.209594224 + 0.045433145 + + + 0.523143327 + 0.032015066 + + + 1.305756117 + 0.02306968 + + + 3.25914324 + 0.016949153 + + + 8.134761557 + 0.013182674 + + + 20.30421516 + 0.010122411 + + + 50.67894742 + 0.007768362 + + + 126.4937202 + 0.006355932 + + + 315.7259981 + 0.005178908 + + + 788.0462816 + 0.004237288 + + + 1966.949018 + 0.003766478 + + + 4909.468555 + 0.003295669 + + + 12430.33287 + 0.003060264 + + + 30585.61668 + 0.002589454 + + + 77440.03084 + 0.002589454 + + + 190546.0718 + 0.002354049 + + + 489390.0918 + 0.002354049 + + + + + + + + 25 Celsius + + + + Breakdown Strength + kV/mm + Probability of Failure + % + + + + Breakdown Strength (kV/mm) + Probability of Failure (%) + + + + 134.3096058 + 12.5086297 + + + 135.4974638 + 18.69779897 + + + 136.6958274 + 24.93299398 + + + 137.9047896 + 31.18775889 + + + 145.3864394 + 37.44027712 + + + 150.5983687 + 43.73113085 + + + 168.8625957 + 49.92556641 + + + 208.5987317 + 56.22166161 + + + 271.6654549 + 62.45004225 + + + 281.4043353 + 68.73755053 + + + 460.765468 + 74.97001936 + + + 554.3522963 + 81.0239571 + + + 559.2550864 + 87.5667591 + + + 940.2240538 + 93.3498204 + + + + + + + 25 Celsius + + + Breakdown Strength + kV/mm + Weibull Parameter + + + + Breakdown Strength (kV/mm) + Weibull Parameter + + + + 134.527754422 + -0.856815879695 + + + 134.381128734 + -0.640376906827 + + + 136.248706873 + -0.486164138659 + + + 136.496879483 + -0.365093588212 + + + 148.839039321 + -0.184502320226 + + + 167.598110021 + -0.113483282254 + + + 206.482712325 + -0.0505807057642 + + + 269.668610582 + 0.00961638356449 + + + 280.292146886 + 0.0569624088792 + + + 547.84911383 + 0.148948972348 + + + 558.490395869 + 0.18885490797 + + + 460.021956525 + 0.104984805984 + + + 144.972830719 + -0.265666935051 + + + + + + + + + DSC + + + 44 + % + + absolute + 1 + + + + + 109 + Celsius + + absolute + 0.5 + + + + + + + https://nanomine.org/nmr/blob?id=5ac5c7abe74a1d06fd9ac3c0 + Representative image of nanoparticle dispersion in matrix + SEM + + + diff --git a/whyis/materialsmine/tests/xml/L157_S5_Zhao_2008.xml b/whyis/materialsmine/tests/xml/L157_S5_Zhao_2008.xml new file mode 100644 index 00000000..fcf0f558 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L157_S5_Zhao_2008.xml @@ -0,0 +1,209 @@ + + + L157_S5_Zhao_2008 + L157_S1_Zhao_2008 + + + + research article + Composites Science and Technology + Mechanisms leading to improved mechanical performance in nanoscale alumina filled epoxy + Zhao, Su + Schadler, Linda S. + Duncan, Renee + Hillborg, Henrik + Auletta, Tommaso + Nanocomposites + Interface + Stress/strain curves + Fracture + Mechanisms + Elsevier + 2008 + 10.1016/j.compscitech.2008.01.009 + 68 + https://www.sciencedirect.com/science/article/pii/S0266353808000213?via%3Dihub + English + Department of Materials Science and Engineering and Rensselaer Nanotechnology Center, Rensselaer Polytechnic Institute, 110 8th Street, Troy, NY 12180, USA + + + + 0266-3538 + 14 + + + + + + + + epoxy + ER + thermoset + Polyepoxide + homopolymer + Huntsman + Araldite F + + + + + alumina + Al2O3 + Nanophase Technologies Corporation + NanoTek + + 45 + nm + + + + + 0.061 + + + + + + + + + nanoparticles were dried in vacuum + + 190 + Celsius + + + + + + + Hauschild SpeedMixer (DAC-150) + high shear mixing + + epoxy + + + alumina + + + 3450 + + + + + + + hardener + Aradur HY905 + + + + + catalyst + DY062 + + + + + curing + + 80 + Celsius + + + + + + + post-curing + + 135 + Celsius + + + + + + + casting + + + + + + + JEOL CM12 + + + JEOL 6330F + + + model Q100 + TA Instruments + + 10 + C/min + + + + Nicolet 4700 FT-IR spectrometer + + + model Q50 + TA Instruments + + + + + + + 4.03 + GPa + + absolute + 0.1 + + + + 92 + GPa + + absolute + 1.5 + + + + 4.7 + % + + absolute + 0.5 + + + + + + + 112 + Celsius + + absolute + 1 + + + + + diff --git a/whyis/materialsmine/tests/xml/L168_S4_Luo_2013.xml b/whyis/materialsmine/tests/xml/L168_S4_Luo_2013.xml new file mode 100644 index 00000000..17ec1e91 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L168_S4_Luo_2013.xml @@ -0,0 +1,904 @@ + + + L168_S4_Luo_2013 + L168_S1_Luo_2013 + + + + research article + ACS Applied Materials & Interfaces + Nano Ag-Deposited BaTiO3 Hybrid Particles as Fillers for Polymeric Dielectric Composites: Toward High Dielectric Constant and Suppressed Loss + Luo, Suibin + Yu, Shuhui + Sun, Rong + Wong, Ching-Ping + Ag-deposited BaTiO3 + hetero-epitaxial interface + polymer matrix + dielectric composites + American Chemical Society + 2014 + 10.1021/am404556c + 6 + https://pubs.acs.org/doi/10.1021/am404556c + English + Center for Advanced Materials, Shenzhen Institutes of Advanced Technology, Chinese Academy of Sciences , Shenzhen, Guangdong 518055, China + 2017-07-10 + + + + 1944-8244 + 1 + + + + + + + + poly(vinylidene flouride) + PVDF + Shanghai 3F Co. + + + + + Silver nitrate + AgNO3 + Guoyao Chemical Co. China + + + Ethylene glycol + Shanghai Lingfeng Chemical Co. China + + + barium titanate + BaTiO3 + Shangdong Guoci Functional Materials Co., China + GC-BT-01 + + 100 + nm + + + + + + ethylene glycol + + + + + AgNO3 (5g) was dissolved in 300 mL of ethylene glycol in a 500 mL three-neck flask + stirring + + AgNO3 + + + ethylene glycol + + + + + + Followed by the addition of 5 g of BaTiO3 under magnetic stirring + BaTiO3 + + 5 + g + + + + + + Followed by the addition of 5 g of BaTiO3 under magnetic stirring. The crystal seeds of Ag formed after about 30 min, and the color of the mixture turned to shallow brown red, at room temperature. + stirring + + + 23 + Celsius + + + + + + The temperature of the mixture was increased to 140 deg C in the oil base for 25 min. + + 140 + Celsius + + + + + + Used + + + + The BT-Ag suspension was obtained which was rinsed and centrifuged three times with ethanol. At last, the obtained BT-Ag hybrid particles were dried at room temperature for 24 h. + + 23 + Celsius + + + + + + + + 0.33 + + + + + + + + + BT-Ag and PVDF powders were mixed in ethanol solution. + + Ethanol + + + poly(vinylidene fluoride) + + + BaTiO3 + + + Ag + + + + + + The suspension was stirred under ultrasonic treatment with the frequency and power of 40 kHz and 1kW, respectively, for 1 h. + stirring + + + + + + The suspension was further magnetically stirred for 6 h. + stirring + + + + + + The suspension was dried at 70 deg C in an oven for 12 h. then molded by hot pressing at 180 deg C and 15 MPa for 15 min. + + 70 + Celsius + + + + + + + hot-pressing + + + + null + + + + + + FEI Tecnai Spirit + + + FEI Nova NanoSEM450 + + + CS9912BX + The measurement of DC breakdown strength was carried out with a dielectric strength tester (CS9912BX, Allwin Instrument Science and Technology co. Ltd, China). + + + Agilent 4294A impedance analyzer + The dielectric and electrical properties were measured using an Agilent 4294A impedance analyzer impedance analyzer in the frequency range of 100 Hz to 10 MHz. Effects of temperature on dielectric properties were investigated via Agilent 4294A connected with a THMS 600 Temperature Controlled stage and a T95-Linkpad Temperature programmer (Linkam Scientific Instruments) in a temperature range between -50 and 130 deg C. + + + XRD, D/max-2500/PC, Rigaku Co. + + + + + + + + Dielectric constant on frequency (Hz) at room temp for PVDF with 0.33 vol frac BT-Ag + + + Frequency (Hz) + Dielectric constant, Dk + + + + 103.43386580610871 + 59.28838331283703 + + + 196.45140173268106 + 55.79415381704672 + + + 385.93153242735247 + 54.72637404219091 + + + 784.2023736308834 + 53.66568914956014 + + + 1540.5765554188256 + 51.38823195534957 + + + 3130.409645257355 + 50.32754706271879 + + + 6360.907228304632 + 50.47653958944284 + + + 12496.091412919868 + 49.408759814587086 + + + 24548.746742478295 + 49.55065745908615 + + + 48226.357083404444 + 46.063522845520765 + + + 101359.65009385569 + 46.219610254469785 + + + 192511.85465114895 + 45.144735597389115 + + + 391178.85087022046 + 42.874373285403465 + + + 794864.7819399758 + 41.81368839277269 + + + 1561523.0060004997 + 35.90719894049761 + + + 3067633.8336662822 + 36.049096584996676 + + + 6233348.487129236 + 31.35937943430139 + + + 9036738.8144 + 30.227745719421023 + + + + + + + + imaginary electric modulus on frequency (Hz) at room temp for PVDF with 0.33 vol frac BT-Ag + + + Frequency (Hz) + Imaginary electric modulus + + + + 103.483728547 + 0.00231467679057 + + + 142.906736659 + 0.00198622386672 + + + 203.77147212 + 0.00188671527689 + + + 281.14806522 + 0.00160186539651 + + + 402.084588483 + 0.00153120052655 + + + 567.32694168 + 0.00141781774209 + + + 796.102642785 + 0.00139475331388 + + + 1118.18824198 + 0.00128249257183 + + + 1586.83533781 + 0.00123966355031 + + + 2228.83397357 + 0.00119647102823 + + + 3162.96700199 + 0.00117265055955 + + + 4442.63380286 + 0.0011374905378 + + + 6304.59885616 + 0.00112087345926 + + + 8946.93744768 + 0.00112408268383 + + + 12437.9604084 + 0.00110116870465 + + + 17650.8698316 + 0.00111081011307 + + + 27230.0559693 + 0.00112857696199 + + + 37855.0045806 + 0.00117118595696 + + + 50966.8772557 + 0.00123760451089 + + + 70853.7424288 + 0.00130661577058 + + + 99519.6064249 + 0.00146176845879 + + + 139783.047775 + 0.00164510626463 + + + 198367.923673 + 0.0018964946282 + + + 281506.475705 + 0.00217394937966 + + + 395397.797038 + 0.00252825523007 + + + 555367.039109 + 0.00291851246913 + + + 788128.519002 + 0.00346669819917 + + + 1118443.33337 + 0.00394742079628 + + + 1570940.87807 + 0.00454827119044 + + + 2229342.4357 + 0.00512401522537 + + + 3163688.56714 + 0.00575816440088 + + + 4443647.29738 + 0.00629856238885 + + + 6241449.14533 + 0.00688071250748 + + + 8857320.8796 + 0.00729229336608 + + + + + + + + Loss tangent on frequency (Hz) at room temp for PVDF with 0.33 vol frac BT-Ag + + + Frequency (Hz) + Loss Tangent + + + + 104.178419275 + 0.0871497397247 + + + 140.864614981 + 0.089915770557 + + + 197.972521696 + 0.0931375076183 + + + 280.146167417 + 0.0807910481562 + + + 395.145293097 + 0.0730353713188 + + + 557.186112476 + 0.0703680928935 + + + 785.787236565 + 0.0652796944815 + + + 1103.03909993 + 0.0634106245356 + + + 1578.8044445 + 0.0593145673836 + + + 2282.32234504 + 0.0583872581965 + + + 3154.34750644 + 0.0605447975717 + + + 4397.14105848 + 0.058275981094 + + + 6303.80079475 + 0.0573554159738 + + + 8795.32832983 + 0.0575914583123 + + + 12530.7396707 + 0.0564786872878 + + + 17481.7339195 + 0.058367025996 + + + 24902.3473062 + 0.0599781086241 + + + 35471.285653 + 0.0623460254169 + + + 47952.9910203 + 0.0684887462743 + + + 70467.8649812 + 0.071753998624 + + + 98288.468484 + 0.0774527350827 + + + 141414.675957 + 0.0863549032786 + + + 199262.61072 + 0.0960326391582 + + + 280735.255493 + 0.108091030624 + + + 395496.539871 + 0.121154288044 + + + 557078.691012 + 0.137060169628 + + + 784690.543855 + 0.152649080071 + + + 1116745.97525 + 0.170072376688 + + + 1556705.30063 + 0.186032210805 + + + 2216059.87022 + 0.198744776752 + + + 3122115.48285 + 0.210948165654 + + + 4399939.59162 + 0.217999087509 + + + 6266802.85926 + 0.221843205593 + + + 8474508.92767 + 0.222854815616 + + + + + + + + + + dielectric constant on temperature (C) at 1 kHz for PVDF with 0.33 vol frac BT-Ag + + + Temperature, C + Dielectric Constant, Dk + + + + -49.787595582 + 27.4179231286 + + + -29.940526763 + 35.3617426884 + + + -10.0934579439 + 45.0468557806 + + + 10.0254885302 + 51.2508612418 + + + 29.8725573492 + 56.5827405031 + + + 50.5352591334 + 58.436471001 + + + 69.8385726423 + 64.6360381609 + + + 89.9575191164 + 69.0987500898 + + + 109.804587935 + 77.0425696496 + + + 129.379779099 + 89.3381436065 + + + + + + + + loss tangent on temperature (C) at 1 kHz for PVDF with 0.33 vol frac BT-Ag + + + Temperature, C + Loss tangent + + + + -49.6080483363 + 0.0932629874823 + + + -29.8651094215 + 0.119976294412 + + + -10.3992367957 + 0.0760666069209 + + + 9.96629181001 + 0.063812552398 + + + 29.7175565899 + 0.068608019427 + + + 50.0701338498 + 0.0904483825272 + + + 70.4097597641 + 0.146383163251 + + + 90.1383596889 + 0.21084386112 + + + 110.164840565 + 0.291132953658 + + + 130.168194039 + 0.43230493481 + + + + + + + + at 10 V/s + + 1.68 + V/m + + + + + conductivity on frequency (Hz) at room temp for PVDF with 0.33 vol frac BT-Ag + + + Frequency (Hz) + Conductivity (S/m) + + + + 104.330282686 + 3.25871544443e-07 + + + 139.134212709 + 4.55581622124e-07 + + + 197.824989306 + 6.21884798796e-07 + + + 281.258971543 + 8.95261745874e-07 + + + 395.654079827 + 1.22894311865e-06 + + + 550.676244532 + 1.65842001398e-06 + + + 782.938327814 + 2.35316935959e-06 + + + 1101.40058504 + 3.16460957547e-06 + + + 1565.89819328 + 4.63370975611e-06 + + + 2202.82155454 + 6.26108104215e-06 + + + 3098.73897251 + 8.66961753663e-06 + + + 4405.69624143 + 1.23508846849e-05 + + + 6264.09673017 + 1.69949839343e-05 + + + 8811.7712105 + 2.35851013105e-05 + + + 12395.3589111 + 3.3440061423e-05 + + + 17436.8169392 + 4.60330728579e-05 + + + 24790.9557047 + 6.61363642062e-05 + + + 34874.4274424 + 8.97921806362e-05 + + + 49583.8114933 + 0.000126912973223 + + + 70497.4368602 + 0.00017912053397 + + + 98115.8802513 + 0.000250478301461 + + + 139503.275561 + 0.000343665957728 + + + 198349.103276 + 0.000470684417141 + + + 279013.284123 + 0.000669386460468 + + + 388324.519267 + 0.00092714198719 + + + 552122.333662 + 0.00128630668019 + + + 776689.493245 + 0.00175359993085 + + + 1104330.01758 + 0.00236934849323 + + + 1537008.46596 + 0.00322307668211 + + + 2208786.09587 + 0.00445797718727 + + + 3107251.41351 + 0.00592333926009 + + + 4417980.49558 + 0.00808196708459 + + + 6148971.27652 + 0.010959881249 + + + 8743017.77775 + 0.0145437580673 + + + + + + + + + + https://nanomine.org/nmr/blob?id=5963c49ae74a1d5e0d19807c + TEM image of as-synthesized BT-Ag hybrid nanoparticles + TEM + + + https://nanomine.org/nmr/blob?id=5963c4b6e74a1d5e0d198091 + TEM image of as-synthesized BT-Ag hybrid nanoparticles after being ultrasonically treated for 30 min in ethanol solution + TEM + + + https://nanomine.org/nmr/blob?id=5963c4d4e74a1d5e0d1980a5 + HRTEM image of an individual BT-Ag hybrid nanoparticle + TEM + + + https://nanomine.org/nmr/blob?id=5963c4f0e74a1d5e0d1980ba + SEM image of Ag-deposited BT hybrid particle + SEM + + + https://nanomine.org/nmr/blob?id=5963c82ce74a1d5e0d198e62 + SEM image of fractured cross-section of BT-Ag - PVDF composite with 0.33 vol frac of Bt-Ag + SEM + + + diff --git a/whyis/materialsmine/tests/xml/L172_S18_Huo_2015.xml b/whyis/materialsmine/tests/xml/L172_S18_Huo_2015.xml new file mode 100644 index 00000000..b6118c81 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L172_S18_Huo_2015.xml @@ -0,0 +1,1042 @@ + + + L172_S18_Huo_2015 + + + + research article + The Journal of Physical Chemistry C + Composite Based on Fe3O4@BaTiO3 Particles and Polyvinylidene Fluoride with Excellent Dielectric Properties and High Energy Density + Huo, Xiaoyun + Li, Weiping + Zhu, Jiujun + Li, Lili + Li, Ya + Luo, Laihui + Zhu, Yuejin + American Chemical Society + 2015 + 10.1021/acs.jpcc.5b08809 + 119 + https://pubs.acs.org/doi/10.1021/acs.jpcc.5b08809 + English + Department of Microelectronic Science and Engineering, Faculty of Science, Ningbo University, Ningbo 315211, China + 2016-07-25 + + + + 1932-7447 + 46 + + + + + + + + Polyvinylidene Fluoride + 6369 + PVDF + thermoplastic + homopolymer + 3F Corporation + + + + + Iron Oxide - Barium Titanate core-shell nanoparticles + Fe3O4@BaTiO3 + + Less than 100nm + 100 + nm + + + + + + Distilled Water + + 75 + mL + + + + + + Add PVP to distilled water + Polyvinylpyrrolidone + + 0.002 + g + + + + + + Add BaTiO3 + Barium Titanate + + 3 + g + + + + + + Stirring at 70C + stirring + + + 70 + Celsius + + + + + + Add FECl3.6H2O to solution + Iron Chloride Hexahydrate + + 0.023 + mol + + + + + + Add FeSO4.7H2O to solution + Iron Sulfate Heptahydrate + + 0.046 + mol + + + + + + Cool from 70C to 55C + + 55 + Celsius + + inert (nitrogen, argon, etc) + + + + + Add ammonia solution + 25% Ammonia solution + + Adjust pH to 11-12 + + + + + + Add Ammonia under vigorous stirring + stirring + + + 55 + Celsius + + + + + + Ethanol + + + + + Rinse suspension with Ethanol six times + stirring + + Ethanol + + + + + + Dry obtained particles under vacuum + + 45 + Celsius + + vacuum + + + + + Barium Titanate and Iron Sulfate + + 0.254 + + + + + + Solution Blending + + + + N,N-dimethylformamide + + + + + Add required Fe3O4@BaTiO3 nanoparticles + Fe3O4@BaTiO3 + + 25.4 + vol% + + + + + + Sonicate PVDF-NP Solution + ultra-sonication + + + + + + casting + + Cast onto a glass sheet + + + + + + Dry film under vacuum + + 120 + Celsius + + + vacuum + + + + + Anneal Films + + 135 + Celsius + + + + + + + + + JEOL JEM-2100F + + + Hitachi SU-70 + + Secondary Electrons + 200000 + + + 5 + kV + + + 6.4 + mm + + + + Agilent 4294A + Impedance Analyzer + + + Bruker D8 Advance + + + + + + + measured at 100 Hz + 3902.02702703 + + + measured at 100 Hz + 0.904205607477 + + + + + + Frequency dependent Dielectric constant + + Frequency + Hertz + Dielectric Constant + + + + Frequency (Hz) + Dielectric Constant + + + + 103.879001354 + 3947.51478845 + + + 110.394186681 + 3639.34904762 + + + 128.186908073 + 3491.41803931 + + + 149.806502553 + 3268.93634494 + + + 178.647299392 + 3058.78741855 + + + 213.423221872 + 2834.52158382 + + + 253.824898419 + 2652.00865734 + + + 298.421589724 + 2477.61637036 + + + 356.465927604 + 2314.10497953 + + + 429.873694176 + 2139.76307397 + + + 518.398474117 + 1990.32742981 + + + 624.869967174 + 1837.44302365 + + + 737.328347689 + 1724.25953813 + + + 877.951172291 + 1601.49748276 + + + 1053.72110363 + 1486.60862831 + + + 1282.36391518 + 1372.08258112 + + + 1525.11937385 + 1276.57942196 + + + 1793.08078482 + 1180.99025016 + + + 2152.06394515 + 1078.89891535 + + + 2582.91721332 + 992.402268585 + + + 3114.82270327 + 900.217075988 + + + 3691.26507227 + 827.425045638 + + + 4430.27360576 + 752.349229117 + + + 5275.21275689 + 681.076742112 + + + 6361.54824281 + 613.876729166 + + + 7705.14659338 + 549.435089945 + + + 9163.75469462 + 496.904213602 + + + 10773.8139987 + 448.610119174 + + + 12930.7819562 + 403.681766654 + + + 15519.5849881 + 360.981019072 + + + 18715.5652596 + 322.481774727 + + + 22179.1475572 + 291.88430599 + + + 26619.516642 + 262.502292395 + + + 31696.3750477 + 236.687696973 + + + 38042.1375932 + 214.018495458 + + + 45297.5114833 + 194.214053919 + + + 54366.2851631 + 177.062854782 + + + 64734.9907834 + 161.88168328 + + + 77695.2387386 + 148.056534729 + + + 94554.0240164 + 134.754175398 + + + 112453.393453 + 125.524937904 + + + 133264.497871 + 115.720931452 + + + 159944.673695 + 107.593035653 + + + 193112.110266 + 99.1734198766 + + + 228578.052932 + 92.6403479689 + + + 272172.323443 + 86.5368184101 + + + 328742.597514 + 80.2547147136 + + + 394401.9043 + 74.8317258874 + + + 466835.659521 + 70.2519093752 + + + 568132.49922 + 65.0992103043 + + + 675681.739965 + 61.1023731877 + + + 801634.414315 + 57.2922990792 + + + 953440.324674 + 55.7772280809 + + + + + + + + Frequency dependent Dielectric loss + + Frequency + Hertz + Dielectric Loss + + + + Frequency (Hz) + Dielectric loss + + + + 106.553612888 + 1.18281226977 + + + 129.784549006 + 1.15548709768 + + + 151.073066026 + 1.13730891116 + + + 180.157702079 + 1.11739395523 + + + 212.259801858 + 1.09805792244 + + + 254.755207043 + 1.07565359702 + + + 308.543595982 + 1.05185985607 + + + 360.241137439 + 1.0347237312 + + + 433.508131333 + 1.01191415958 + + + 520.298486976 + 0.989336157221 + + + 619.529505428 + 0.967858108821 + + + 743.562210287 + 0.946785306616 + + + 907.729940202 + 0.923686273431 + + + 1082.486405 + 0.902613471227 + + + 1275.37344886 + 0.882351161415 + + + 1530.70917893 + 0.883566900004 + + + 1853.89935677 + 0.894508547302 + + + 2187.54720393 + 0.904234456012 + + + 2604.75490756 + 0.915349780252 + + + 3126.23902389 + 0.931588574258 + + + 3752.12669958 + 0.9500851685 + + + 4503.32001555 + 0.970492209096 + + + 5454.13994707 + 0.993504403811 + + + 6504.17275249 + 1.01527191378 + + + 7663.14403303 + 1.03692363912 + + + 9197.34131309 + 1.06045686466 + + + 11139.2453766 + 1.08520582879 + + + 13283.7765376 + 1.10361558456 + + + 16045.9856969 + 1.12167798645 + + + 19135.1641083 + 1.13603528026 + + + 22860.0621948 + 1.14282315404 + + + 27491.2314034 + 1.14859791234 + + + 32771.4678615 + 1.1463401121 + + + 39080.6415663 + 1.14008774222 + + + 46044.3774515 + 1.13036183351 + + + 55526.3914399 + 1.11431408414 + + + 66930.7031728 + 1.09250026032 + + + 79816.2240255 + 1.07119588886 + + + 94038.5878658 + 1.04803896336 + + + 113164.456421 + 1.02094536053 + + + 135193.327708 + 0.994199111576 + + + 160446.003973 + 0.968263355017 + + + 191678.817541 + 0.942530221556 + + + 227482.382764 + 0.916391841899 + + + 270458.62866 + 0.893813839537 + + + 328120.007271 + 0.867154429057 + + + 379998.211727 + 0.849931465717 + + + 475609.830095 + 0.823301001393 + + + 588569.023306 + 0.798986229619 + + + 689005.672478 + 0.783876335731 + + + 838695.141311 + 0.764289436246 + + + 957694.410559 + 0.761993041134 + + + + + + + + Conductivity of Film for AC electric field at 100Hz + 0.0000250646 + s/m + + Conductivity of Film for AC electric field + + Frequency + Hertz + Conductivity + s/m + + + + Frequency (Hz) + Conductivity (s/m) + + + + 102.359526534 + 2.51010123645e-05 + + + 126.002044465 + 2.87145406788e-05 + + + 148.45420808 + 3.08893698409e-05 + + + 179.025690541 + 3.37946931652e-05 + + + 212.156948078 + 3.65601555137e-05 + + + 256.253190293 + 4.02850491005e-05 + + + 307.434287491 + 4.37559794972e-05 + + + 363.896032944 + 4.72988018628e-05 + + + 433.298068243 + 5.15383892699e-05 + + + 520.046368274 + 5.63076670473e-05 + + + 619.229302796 + 6.15241343437e-05 + + + 743.201905684 + 6.69432715631e-05 + + + 904.466373745 + 7.32354948953e-05 + + + 1075.68465805 + 7.95454116267e-05 + + + 1274.75544687 + 8.6606210866e-05 + + + 1517.87604867 + 9.58883144023e-05 + + + 1847.23402219 + 0.000107016391502 + + + 2196.92114067 + 0.000119340574492 + + + 2603.49273317 + 0.000130923197172 + + + 3124.72415628 + 0.000145244682534 + + + 3720.66969172 + 0.000161132772955 + + + 4465.56516757 + 0.000179473985229 + + + 5434.53064766 + 0.000200302387078 + + + 6463.30412173 + 0.000221062757143 + + + 7659.43073772 + 0.000241166221974 + + + 9120.23281939 + 0.000265419084598 + + + 11099.1963863 + 0.000297406702425 + + + 13200.3086195 + 0.000321230433603 + + + 15988.2954761 + 0.000352407515846 + + + 18775.0586265 + 0.000380181428813 + + + 22668.4084438 + 0.000414258664061 + + + 26831.5677252 + 0.000447800248024 + + + 32653.6444224 + 0.000482128798097 + + + 38835.0803902 + 0.000518674646112 + + + 45658.3514829 + 0.00055617953583 + + + 55587.6266432 + 0.00060076650182 + + + 66690.0668468 + 0.000646563305761 + + + 79314.7029385 + 0.000691420131734 + + + 96066.458954 + 0.000746508151186 + + + 112810.862271 + 0.000795753087295 + + + 134326.08293 + 0.00085993812884 + + + 161218.793047 + 0.000918759479086 + + + 196201.026951 + 0.00100712531803 + + + 233342.488689 + 0.0010813056366 + + + 274340.448311 + 0.0011621422814 + + + 329264.689301 + 0.00126956432226 + + + 400710.543469 + 0.00138612502413 + + + 476566.289739 + 0.00150254996886 + + + 577220.038856 + 0.00164903852053 + + + 706060.996152 + 0.00184328472728 + + + 833131.395345 + 0.00201718616849 + + + 968691.03952 + 0.00214689820655 + + + + + + + Percolation threshold for Fe3O4@BaTiO3-PVDF nanocomposite + 26 + vol% + + + log(fc-f) + log sigma + log (s/m) + + + + log(fc-f) + log sig + + + + -1.38894261537 + -4.89795918367 + + + -1.19209272559 + -5.25765306122 + + + -1.1207779279 + -5.51020408163 + + + -1.00908056602 + -5.72448979592 + + + -0.929083410368 + -6.32142857143 + + + + + + + + + 200nm + + https://nanomine.org/nmr/blob?id=5ad39e23e74a1d06fd9ca77e + SEM image of Fe3O4@BaTiO3 nanoparticles + SEM + grayscale + + 1000 + 744 + + + + https://nanomine.org/nmr/blob?id=5ad39e48e74a1d06fd9ca7a0 + Image of single Fe3O4@BaTiO3 nanoparticle + TEM + grayscale + + 990 + 752 + + + + diff --git a/whyis/materialsmine/tests/xml/L199_S1_Duncan_2010.xml b/whyis/materialsmine/tests/xml/L199_S1_Duncan_2010.xml new file mode 100644 index 00000000..573e16b7 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L199_S1_Duncan_2010.xml @@ -0,0 +1,342 @@ + + + L199_S1_Duncan_2010 + + + + research article + Composites Science and Technology + Measurement of the critical aspect ratio and interfacial shear strength in MWNT/polymer composites + Duncan, Renée K. + Chen, Xinyu G. + Bult, J.B. + Brinson, L.C. + Schadler, L.S. + Carbon nanotubes + Polymer matrix composites + Fragmentation + Interfacial strength + Mechanical properties + Elsevier + 2010 + 10.1016/j.compscitech.2009.12.010 + 70 + https://www.sciencedirect.com/science/article/pii/S0266353809004357?via%3Dihub + English + Rensselaer Polytechnic Institute, Troy, NY 12180, USA + 2017-06-21 + + + + 0266-3538 + 4 + + + + + + + + poly(bisphenol A carbonate) + PC + GE Plastics + Lexan 124 + + + + + multi-walled carbon nanotubes + MWNT + + + + + vapor deposition of xylene–ferrocene in a quartz tube furnace + + 727 + Celsius + + + + + + + 0.05 + + + + + + + + + PC was dried to remove residual moisture + + 125 + Celsius + + + vacuum + + + + + ultra-sonication + + PC + + + tetrahydrofuran + + + + + + + stirring + + PC solution + + + MWNT dispersion + + + + + + + Precipitation of the composite + dissolving + + PC solution + + + MWNT dispersion + + + methanol + + + + + + the mixture was dried after filtration + + 60 + Celsius + + + vacuum + + + + + + + + + + + 190 + Celsius + + + + + + + + + Phillips CM12 + + + JEOL 6335 + + + + + + + Number of MWNT within grip region dissolved in THF + + + Aspect ratio (L/d) + Number of MWNT within grip region dissolved in THF + + + + 0-199 + 0.0 + + + 200-399 + 0.0 + + + 400-599 + 0.0 + + + 600-799 + 0.0 + + + 800-999 + 18.4393465415 + + + 1000-1199 + 17.0142509559 + + + 1200-1399 + 10.4362182829 + + + 1400-1599 + 16.7014250956 + + + 1600-1799 + 11.9742787626 + + + 1800-1999 + 22.540841154 + + + >2000 + 21.8456725756 + + + + + + Number of MWNT along the fracture edge dissolved in THF + + + Aspect ratio (L/d) + Number of MWNT along the fracture edge dissolved in THF + + + + 0-49.99 + 0.0 + + + 50-99.99 + 0.0 + + + 100-149.99 + 3.09094256259 + + + 150-199.99 + 0.0 + + + 200-249.99 + 7.79270986745 + + + 250-299.99 + 13.9304123711 + + + 300-349.99 + 34.486377025 + + + 350-399.99 + 43.1148748159 + + + >400 + 11.1800441826 + + + + + + Number of MWNT along the fracture for ARNT/PC + + + Aspect ratio (L/d) + Number of MWNT along the fracture for ARNT/PC + + + + 0-16 + 0.0 + + + 16-31 + 8.95470779757 + + + 32-48 + 16.0864952961 + + + 49-64 + 29.1779569873 + + + 65-80 + 27.8728191726 + + + 81-96 + 14.8469887788 + + + >97 + 23.6376183327 + + + + + + + + + + https://nanomine.org/nmr/blob?id=594ac431e74a1d5e0d156d7e + SEM + + + https://nanomine.org/nmr/blob?id=594ac43de74a1d5e0d156d8f + magnification: 2500, accelerating voltage: 23 kV + SEM + + + https://nanomine.org/nmr/blob?id=594ac4ade74a1d5e0d156da8 + magnification: 1300, accelerating voltage: 120 kV + TEM + + + https://nanomine.org/nmr/blob?id=594ac4ede74a1d5e0d156ddc + magnification: 1500, accelerating voltage: 12 kV + SEM + + + diff --git a/whyis/materialsmine/tests/xml/L203_S9_Ma_2009.xml b/whyis/materialsmine/tests/xml/L203_S9_Ma_2009.xml new file mode 100644 index 00000000..2e17bced --- /dev/null +++ b/whyis/materialsmine/tests/xml/L203_S9_Ma_2009.xml @@ -0,0 +1,951 @@ + + + L203_S9_Ma_2009 + L203_S1_Ma_2009 + + + + research article + ACS Applied Materials & Interfaces + Enhanced Electrical Conductivity of Nanocomposites Containing Hybrid Fillers of Carbon Nanotubes and Carbon Black + Ma, Peng-Cheng + Liu, Ming-Yang + Zhang, Hao + Wang, Sheng-Qi + Wang, Rui + Wang, Kai + Wong, Yiu-Kei + Tang, Ben-Zhong + Hong, Soon-Hyung + Paik, Kyung-Wook + Kim, Jang-Kyo + conducting nanocomposites + carbon nanotubes + carbon black + synergic effect + American Chemical Society + 2009 + 10.1021/am9000503 + 1 + https://pubs.acs.org/doi/10.1021/am9000503 + English + Departments of Mechanical Engineering and Chemistry, The Hong Kong University of Science and Technology (HKUST), Clear Water Bay, Kowloon, Hong Kong, China + 2017-08-10 + + + + 1944-8244 + 5 + + + + + + + + diglycidyl ether of bisphenol A + DGEBA + Shell Chemicals, London, U.K. + Epon 828 + m-phenylenediamine + + + + + carbon black + Vulcan XC72, Cabot Corp., Boston, MA + + 40 + nm + + absolute + 20 + + + + + + 0.004 + + + + + + + + + acetone + + + + + The conducting filler and DGEBA were mixed in 200 mL of acetone, and then the mixture was dispersed using a high-speed shear mixer (HSM- 100 L, Ross, Hauppauge, NY) at 3000 rpm for 1 h. + HSM- 100 L, Ross, Hauppauge, NY + high shear mixing + + 200 mL acetone + + + 3000 + rpm + + + + 80 + Celsius + + + + + + The mixture was distilled at 80 °C to remove the solvent + + 80 + Celsius + + + + + + followed by degassing in a vacuum oven at 80 °C for 5 h to eliminate the remaining solvent and entrapped air. + + 80 + Celsius + + + + 0 + Pa + + + + + + The mPDA hardener was added into the mixture in a ratio of 14.5:100 by weight with gentle stirring of the mixture. + mPDA hardener + + + + + hot-pressing + + + + + The composite was molded into a flat plate and cured at 80 °C for 2 h, followed by postcure at 150 °C for 2 h. + + 80 + Celsius + + + + + + + The composite was molded into a flat plate and cured at 80 °C for 2 h, followed by postcure at 150 °C for 2 h. + + 150 + Celsius + + + + + + + + + JEOL 2010F + The dispersion states of fillers in nanocomposites were evaluated on a TEM (JEOL 2010F) + + + JEOL-6700F + A scanning electron microscope (SEM; JEOL-6700F) was employed to examine the morphologies of fracture surfaces. + + + Zwick-Roell HIT5.5P + Specimens were tested on an impact tester (Zwick-Roell HIT5.5P) with an impact energy of 2.7 J. + + + Sony Tektronix 370A + The direct-current (dc) electrical conductivity of nanocomposites was measured at room temperature using a programmable curve tracer (Sony Tektronix 370A). Square specimens of 10mm× 10mmwere cut from the plate and were polished on both sides into a thickness of 0.8 mm. Silver paste of a thickness of about 0.05 mm was applied on the sample surface to reduce the contact resistance between the sample and the electrodes. To minimize any potential problems associated with the silver paste, the samples were heated at 40 °C to remove the solvent quickly. Then, the edges of the samples were grinded again to remove the silver paste that was possibly attached on them. + + + Hewlett-Packard 4284A + The alternating-current (ac) conductivity of nanocomposites was measured with a precision LCR meter (Hewlett-Packard 4284A) in the frequency range of 20-106 Hz. The equipment was calibrated using an internal calibration calculator during the measurement. + + + Leica Quantimet 500+ Image Processing System + The electrical conducting networks in the nanocomposites were visualized by examining the polished samples with a thickness of 0.1 mm using the transmission mode of an optical microscope (Leica Quantimet 500+ Image Processing System). + + + + + + + flexural stress (MPa) vs flexural strain (%) + + + Flexural strain (%) + Flexural stress (MPa) + + + + 0.0455199451544 + 0.97757885763 + + + 0.0984788280365 + 1.81445012788 + + + 0.179423054029 + 5.30622335891 + + + 0.1570619867 + 3.71905370844 + + + 0.224083753163 + 7.26854219949 + + + 0.341314431514 + 12.347485081 + + + 0.433387994902 + 15.622826087 + + + 0.491957257436 + 17.2532821824 + + + 0.550558700481 + 19.5186061381 + + + 0.620298988801 + 21.7550724638 + + + 0.684450107351 + 23.6163895993 + + + 0.753087481772 + 26.072173913 + + + 0.832297373221 + 28.3153736857 + + + 0.843503017436 + 29.6043478261 + + + 0.922369928714 + 31.360540738 + + + 0.893651956553 + 29.9506393862 + + + 0.996215269668 + 34.1277813299 + + + 1.0476737362 + 35.5836487639 + + + 1.11125833147 + 37.2573913043 + + + 1.16150351957 + 39.502514919 + + + 1.24238777279 + 41.8111253197 + + + 1.21165977244 + 39.9930946292 + + + 1.31216477615 + 44.7719181586 + + + 1.29535250667 + 42.76342711 + + + 1.39583469147 + 47.0920716113 + + + 1.37066368038 + 45.0143222506 + + + 1.46276723015 + 48.8812446718 + + + 1.44597485409 + 47.2652173913 + + + 1.54090004963 + 51.8535805627 + + + 1.53384593521 + 50.0499786871 + + + 1.61337348731 + 53.065601023 + + + 1.64019535865 + 54.7451150895 + + + 1.71380081897 + 56.312084399 + + + 1.68028115923 + 54.3641943734 + + + 1.75063185335 + 57.6539641944 + + + 1.79742407255 + 57.7116794544 + + + 1.91449092284 + 59.5585677749 + + + 1.8893155235 + 57.3942455243 + + + 1.96461353245 + 59.3854219949 + + + 2.02317913811 + 60.9437340153 + + + 2.10410142284 + 64.0026427962 + + + 2.09848153531 + 63.021483376 + + + 2.16548136052 + 66.1381074169 + + + 2.17795715977 + 65.0126598465 + + + 2.25468573874 + 67.7541346974 + + + 2.24070915744 + 66.7441176471 + + + 2.32156561841 + 68.5044330776 + + + 2.39127226346 + 70.077173913 + + + 2.46655754649 + 71.8172890026 + + + 2.550199377 + 73.5833759591 + + + 2.61990675343 + 75.1705456095 + + + 2.70075151239 + 76.7 + + + 2.77184667339 + 78.1933823529 + + + 2.85367831878 + 79.5692729266 + + + 2.92028915683 + 80.8987851662 + + + 2.99943221451 + 82.2159298502 + + + 3.08172391236 + 83.510400682 + + + 3.17145293044 + 85.0109974425 + + + 3.25267459145 + 86.1268258028 + + + 3.33630073571 + 87.5834490318 + + + 3.41434558119 + 88.8202046036 + + + 3.50352948091 + 90.0322250639 + + + 3.58991513886 + 90.9845268542 + + + 3.65403597848 + 92.2484910486 + + + 3.73761637347 + 92.8025575448 + + + 3.80451790184 + 93.9799488491 + + + 3.8936816156 + 94.7937340153 + + + 3.97449126855 + 95.6306052856 + + + 4.05530238424 + 96.4963341858 + + + 4.13889916204 + 97.3736061381 + + + 4.22248306764 + 97.9969309463 + + + 4.30607399443 + 98.7587723785 + + + 4.39174451366 + 99.3388107417 + + + 4.47324882683 + 100.143938619 + + + 4.56160965772 + 100.81673365 + + + 4.64039908501 + 101.044296675 + + + 4.7184110813 + 101.632992327 + + + 4.8075528538 + 102.013913043 + + + 4.89672549034 + 103.003729753 + + + 4.94549030177 + 103.515952685 + + + 4.97468731428 + 102.602608696 + + + 5.05826653907 + 103.133589088 + + + 5.14556836645 + 103.845410628 + + + 5.22261533745 + 103.710741688 + + + 5.29704844291 + 104.337364511 + + + 5.34794526547 + 103.739599318 + + + 5.40686130437 + 104.362099622 + + + 5.49836185265 + 104.182082978 + + + 5.5691956863 + 104.444549994 + + + 5.65990138987 + 104.282122762 + + + 5.74106323135 + 104.217811472 + + + 5.82701039849 + 104.368695652 + + + 5.91532007491 + 104.032298137 + + + 5.99410555974 + 104.182082978 + + + 6.07765679724 + 104.160920716 + + + 6.16675790528 + 103.739599318 + + + 6.25031314097 + 103.797314578 + + + 6.32829793009 + 103.849258312 + + + 6.41184380417 + 103.72228474 + + + 6.4953765135 + 103.335592498 + + + 6.57892268013 + 103.214390452 + + + 6.66246094791 + 102.937357204 + + + 6.74599453489 + 102.56797954 + + + 6.82953982387 + 102.429462916 + + + 6.91307809165 + 102.152429668 + + + 6.99662513593 + 102.048542199 + + + 7.08016340371 + 101.771508951 + + + 7.16369640559 + 101.390588235 + + + 7.24720834386 + 100.594117647 + + + 7.25047759129 + 0.256138107417 + + + 7.26382226436 + 98.6895140665 + + + 7.26373449933 + 96.958056266 + + + 7.2636467343 + 95.2265984655 + + + 7.26355896926 + 93.495140665 + + + 7.26347120423 + 91.7636828645 + + + 7.2633834392 + 90.0322250639 + + + 7.26329567417 + 88.3007672634 + + + 7.26320790914 + 86.5693094629 + + + 7.26312014411 + 84.8378516624 + + + 7.26303237907 + 83.1063938619 + + + 7.26294461404 + 81.3749360614 + + + 7.26285684901 + 79.6434782609 + + + 7.26276908398 + 77.9120204604 + + + 7.26268131895 + 76.1805626598 + + + 7.26259355392 + 74.4491048593 + + + 7.26250578888 + 72.7176470588 + + + 7.26241802385 + 70.9861892583 + + + 7.26233025882 + 69.2547314578 + + + 7.26224249379 + 67.5232736573 + + + 7.26215472876 + 65.7918158568 + + + 7.26206696373 + 64.0603580563 + + + 7.26197919869 + 62.3289002558 + + + 7.26189143366 + 60.5974424552 + + + 7.26180366863 + 58.8659846547 + + + 7.2617159036 + 57.1345268542 + + + 7.26162813857 + 55.4030690537 + + + 7.26154037354 + 53.6716112532 + + + 7.2614526085 + 51.9401534527 + + + 7.26136484347 + 50.2086956522 + + + 7.26127707844 + 48.4772378517 + + + 7.26118931341 + 46.7457800512 + + + 7.26110154838 + 45.0143222506 + + + 7.26101378334 + 43.2828644501 + + + 7.26092601831 + 41.5514066496 + + + 7.26083825328 + 39.8199488491 + + + 7.26075048825 + 38.0884910486 + + + 7.26066272322 + 36.3570332481 + + + 7.26057495819 + 34.6255754476 + + + 7.26048719315 + 32.8941176471 + + + 7.26039942812 + 31.1626598465 + + + 7.26031166309 + 29.431202046 + + + 7.26022389806 + 27.6997442455 + + + 7.26013613303 + 25.968286445 + + + 7.260048368 + 24.2368286445 + + + 7.25996060296 + 22.505370844 + + + 7.25987283793 + 20.7739130435 + + + 7.2597850729 + 19.042455243 + + + 7.25969730787 + 17.3109974425 + + + 7.25960954284 + 15.5795396419 + + + 7.25952177781 + 13.8480818414 + + + 7.25943401277 + 12.1166240409 + + + 7.25934624774 + 10.3851662404 + + + 7.25925848271 + 8.6537084399 + + + 7.25917071768 + 6.92225063939 + + + 7.25908295265 + 5.19079283887 + + + 7.25899518762 + 3.45933503836 + + + 7.25890742258 + 1.72787723785 + + + 0.255895025071 + 8.38235294118 + + + 0.298562831401 + 10.1470588235 + + + + + + 3.26 + GPa + + absolute + 0.13 + + + + 104.5 + MPa + + absolute + 4.5 + + + + + + + 1.92e-12 + S/cm + + ac conductivity (S per cm) on frequency (Hz) for CB filler + + + Frequency (Hz) + Conductivity (S/cm) + + + + 20.0061530355 + 6.85492547876e-13 + + + 99.0588367665 + 1.03301822604e-11 + + + 989.028396717 + 9.83852294873e-11 + + + 10031.5704019 + 1.44545049108e-09 + + + 100157.72762 + 1.75674001132e-08 + + + 1000000.0 + 2.19369613757e-07 + + + + + + + + + + https://nanomine.org/nmr/blob?id=598dc024e74a1d1577263541 + TEM image of CB filler + TEM + grayscale + + + diff --git a/whyis/materialsmine/tests/xml/L217_S2_Ash_2002.xml b/whyis/materialsmine/tests/xml/L217_S2_Ash_2002.xml new file mode 100644 index 00000000..4b693ece --- /dev/null +++ b/whyis/materialsmine/tests/xml/L217_S2_Ash_2002.xml @@ -0,0 +1,289 @@ + + + L217_S2_Ash_2002 + L217_S1_Ash_2002 + + + + research article + Polymer Composites + Mechanical properties of Al2O3/polymethylmethacrylate nanocomposites + Ash, Benjamin J. + Rogers, Diana F. + Wiegand, Christopher J. + Schadler, Linda S. + Siegel, Richard W. + Benicewicz, Brian C. + Apple, Tom + Wiley Subscription Services, Inc., A Wiley Company + 2002 + 10.1002/pc.10497 + 23 + http://onlinelibrary.wiley.com/doi/10.1002/pc.10497/abstract + English + Department of Materials Science and Engineering, Rensselaer Nanotechnology Center, Troy, NY 12180‐3590, USA + 2017-07-13 + + + + 1548-0569 + 6 + + + + + + + + poly(methyl methacrylate) + PMMA + Cambridge Isotope Laboratories + + 142000 + g/mol + + 1.5 + + + + + alumina + gamma-Al2O3 + Nanophase Technologies Corporation + + 39 + nm + + + + 43 + m^2/gram + + + + + + + Twenty grams of nanoparticles were suspended in ethanol through 10 minutes of sonication (VCX-400 Sonics Materials Vibracell) at 70% power. The power setting refers to the percentage of maximum sonic power (400 watts) that is directed into the sample. + VCX-400 Sonics Materials Vibracell + ultra-sonication + + ethanol + + + + + + Used + + + + The resulting slurry was centrifuged for 3 minutes at 3000 rpm to remove particles larger than 100 nm. This procedure was used to achieve a narrower particle size distribution than is available from the supplier. + + 3000 + RPM + + + + + + + The silane coupling agent was added to a 95/5 mixture of ethanol and water adjusted to a pH of 4.5 by addition of acetic acid. + + + + + This solution was reacted at room temperature for 10 minutes for silanol formation. + + + + + + The silanol solution was then dropped into the ethanol/nanoparticle sluny at a rate of approximately 20 ml/min while sonicating the mixture at 70% power. + VCX-400 Sonics Materials Vibracell + ultra-sonication + + + + + The slurry was then evaporated at reduced pressure for 2 hours at 60°C to remove the solvent. + + 60 + Celsius + + + + + + + The particles were cured under vacuum at 60°C for a period of 24 hours. + + 60 + Celsius + + + + + + + + 0.02 + + + + + + + + + Coated or uncoated nanoparticles were added to MMA monomer and dispersed via sonication at 70% power for 10 minutes. During the last two minutes of the sonication, the initiator (AIBN) and chain transfer agent (1 - decanethiol) were added. + VCX-400 Sonics Materials Vibracell + ultra-sonication + + 2,2-azobisisobutyronitrile + + + 1 - decanethiol + + + + + + + The polymerization was carried out at 55°C under a nitrogen blanket for 21 hours with two additional sonication steps of 40% power at the 1 and 2 hour points. + VCX-400 Sonics Materials Vibracel + ultra-sonication + + + 55 + Celsius + + + + + + The polymer was then broken into small pieces and dried in a vacuum oven for 2 hours at 115°C to drive off water and residual monomer. + + 115 + Celsius + + + + 0 + Pa + + + + + + hot-pressing + + + + + The resulting nanocomposite was compression molded into tensile specimens (AS" D638-95 Qpe IV) in a hydraulic press (Carver 12 Ton) at 180°C and 2.5 mTons. + + 180 + Celsius + + + + + + Specimens were allowed to cool to room temperature under pressure for a period of 6 hours and, after removal, were sanded (400 grit) to remove flashing. + + 23 + Celsius + + + + + + + + + The speed and duration requirements were chosen by observing the gross distribution of remaining particles through transmission electron microscope (TEM) measurements. + + + JEOL + + + Rheometric Scientific DMTA V + Dynamic mechanical thermal analysis (DMTA) was carried out on a Rheometric Scientific DMTA V using single cantilever bending mode at 1 Hz with 0.1% strain. Temperature ramps from 15°C to 200°C at 2°C mix1 were conducted to determine the Tg of the materials. + + + Seiko Instruments SSC5200 + In specific cases, Tg was also obtained through differential scanning calorimetry (DSC) (Seiko Instruments SSC5200) with a temperature ramp from 25°C to 190°C at 10°C per min. + + + Chemagnetics CMX spectrometer + 7.5 mm coil and a quadrupolar echo sequence. An echo delay of 25 ps was used and the 90" pulse width was 3 ps. Eight scans were acquired for each spectrum with a pulse delay of 5 s. + + + + + + + 2.500735763 + GPA + + + 56 + MPa + + + + + Dynamic Mechanical Thermal Analysis (DMTA) in Single Cantilever Bending at 1 Hz, 0.1% Strain, and 2°C per min and Differential Scanning Calorimetry (DSC) at 10°C per min. + + 102 + Celsius + + absolute + 1 + + + + 97 + Celsius + + absolute + 3 + + + + + + + https://nanomine.org/nmr/blob?id=5967e116e74a1d147250479b + typical nano-alumina particle dispersion-morphology from nanophase technology corporation + + + diff --git a/whyis/materialsmine/tests/xml/L256_S3_Potschke_2004.xml b/whyis/materialsmine/tests/xml/L256_S3_Potschke_2004.xml new file mode 100644 index 00000000..2bf491c7 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L256_S3_Potschke_2004.xml @@ -0,0 +1 @@ +L256_S3_Potschke_2004L256_S1_Potschke_2004research articlePolymerRheological and dielectrical characterization of melt mixed polycarbonate-multiwalled carbon nanotube compositesPötschke, PetraAbdel-Goad, MahmoudAlig, IngoDudkin, SergejLellinger, DirkPolycarbonateMultiwalled carbon nanotubeNanocompositeElsevier200410.1016/j.polymer.2004.10.04045https://www.sciencedirect.com/science/article/pii/S0032386104010225?via%3DihubEnglishLeibniz Institute of Polymer Research Dresden, Hohe Str. 6, 01069 Dresden, Germany2017-08-020032-386126polycarbonateGE EuropeLexan 121Prior to mixing the materials were dried for about 16 h at 80 °C in a vacuum oven.80CelsiusvacuumSheets with a thickness of about 350 mm (for dielectric measurements) and about 500 mm (for rheological measurements) were formed by compression molding from extruded strands at 260 °C using a Vogt-press. The strands were heated to 260 °C for about 5 min, pressed with a force of about 50 kN for 5 min and cooled to room temperature. For dielectric measurements, discs with diameter of 20 mm were cut from the sheets and gold layers were sputtered onto both flat sides of these samples as electrodes. For rheological measurements, discs with a diameter of 25 mm were punched from the sheets.multi-walled carbon nanotubesHyperion Catalysis International, Inc. (Cambridge, MA, USA)1.75g / cm^3a mean diameter of about 12 nm12nma mean diameter of about 12 nm12nmPrior to mixing the materials were dried for about 16 h at 80 °C in a vacuum oven.80Celsiusvacuum0.0025A DACA Micro Compounder (DACA Instruments, Goleta, CA, USA) was operated at 265 °C, 50 rpm for 5 min in order to get 23 compositions with MWNT contents between 0.1 and 12.5 wt% MWNT, corresponding to contents between 0.07 and 8.5 vol.% (assuming a MWNT density of 1.75 g/cm3DACA Micro Compoundermechanical mixing50rpm265Celsiushot-pressingSheets with a thickness of about 350 mm (for dielectric measurements) and about 500 mm (for rheological measurements) were formed by compression molding from extruded strands at 260 °C using a Vogt-press. The strands were heated to 260 °C for about 5 min, pressed with a force of about 50 kN for 5 min and cooled to room temperature.260CelsiusSolartron SI1260 Impedance/Gain Phase AnalyzerThe dielectric measurements were performed at room temperature in a frequency range from 10K3 to 107 Hz using a frequency response analysis system consisting of Solartron SI1260 Impedance/Gain Phase Analyzer and Novocontrol broadband dielectric converter with the BDC active sample cell.plateThe melt rheological properties were determined using an ARES-rheometer (Rheometrics Scientific). The measurements were performed in dynamic mode and 25 mm parallel plates geometry with gap settings of about 1 mm under liquid nitrogen atmosphere. The strain amplitude was selected to be within the linear viscoelastic range. The rheological properties of the samples were measured at eight temperatures in the temperature range between 170 and 280 °C (steps of 10 K between 170 and 200 °C, steps of 20 K up to 280 °C) as a function of the angular frequency u. The frequency was varied between 100 and 0.01 rad/s.ARES-rheometer (Rheometrics Scientific)170Celsiusshear storage modulus (Pa) on frequency (rad per sec) at 170 deg CFrequencyrad/secShear Storage ModulusPafrequency (rad per sec)shear storage modulus (Pa)0.010157613176466307.28607530.0178489915878126140.4947440.0315958400828232779.4995310.0567622111742418822.7870950.101210075602701963.5966590.1804439012891101529.274360.3192846403291569911.322580.5691023326832116167.461911.021789743012630387.216541.780898429683123880.77243.197029562413544542.413845.739003196893921252.5536610.22578602014250992.5901818.35516177494515992.7955331.98637924644846448.9635657.4128242795019788.80583100.7866266765173117.41471220Celsiusshear storage modulus (Pa) on frequency (rad per sec) at 220 deg CFrequencyrad/secShear Storage ModulusPaFrequency (rad / sec)Shear Storage Modulus (Pa)0.1131.2642474610.176753662299200.038529660.316227766017379.9624295660.55894415764751.192658491.01658.042767181.767536622994168.254554773.1431739831510478.92066235.623413251926344.0586749.9395888689365568.215461617.8908748992150637.42237731.6227766017309980.84576946.6037702554588626.50917169.0993057865771754.239079102.4533859391042705.60632shear loss modulus (Pa) on frequency (rad per sec) at 220 deg CFrequencyrad/secShear Loss ModulusPaFrequency (rad / sec)Shear Loss Modulus (Pa)0.09939163236443211.397979280.1763869420465475.376733390.3149439104619469.19541840.55892022256616610.83059530.99189666736629138.66288261.7710597596950392.82345343.1622776601788398.92056475.61198637259148589.33587310.0816953308237629.92604714.7178551023315853.04416321.4859953315393788.12532931.9460348524484017.39291746.352988395562008.04635156.3486339813774059.703603100.0843042.83085tangent delta on frequency (rad per sec) at 220 deg CFrequencyrad/secTangent DeltadimensionlessFrequency (rad / sec)Tangent Delta0.6765399047313.66345511171.0036586752312.28961173111.4566741414110.67011088282.137454640498.73139554633.153628036137.062837209374.627484410275.615281008466.753056705494.511516727459.963546618753.6288130074214.62003639012.9179955098521.33555211122.3790642347331.47874767941.938403736746.69926780821.5223206704467.40736880221.20437205636101.1016232391.00934955106280Celsiusshear storage modulus (Pa) on frequency (rad per sec) at 280 deg CFrequencyrad/secShear Storage ModulusPaFrequency (rad / sec)Shear Storage Modulus (Pa)0.055807638808624.77933251570.099329510795429.31576609060.17677229943843.29554808650.31460218106860.65260219920.55994629781471.75647276740.996532747621101.5908136221.77359860039132.1753650063.15639431182195.205707875.58428384852330.7283680079.93618928951714.41601950417.78239025971626.9074597731.6377345514161.3777343556.287419120211103.504318199.560663237429626.9442475170Celsiuscomplex viscosity (Pa-sec) on frequency (rad per sec) at 170 deg CFrequencyrad/secComplex ViscosityPa-secFrequency (rad / sec)Complex Viscosity (Pa-sec)0.009870034354621643725.30930.017643386877219303614.7860.031306049587216419172.36680.055548787065613965737.72320.099311105660310500744.42650.1775542386287673931.028550.3150557038056344130.49390.5632967232414421529.94940.9849922849642698425.763491.76116221091793550.456093.149023330861158666.149235.58965971719619180.13095910.0686724102427459.20839717.737869176260873.07088931.7186430674151830.78031456.718893800188367.058248398.458450696745036.20022220Celsiuscomplex viscosity (Pa-sec) on frequency (rad per sec) at 220 deg CFrequencyrad/secComplex ViscosityPa-secFrequency (rad / sec)Complex Viscosity (Pa-sec)0.09881910783231894.11641860.17581498580731087.00261510.31280295797330106.77195160.55652645346529533.53269980.99014950310329157.44977311.7616342087428602.28581463.1342287964528057.69229435.5762939319226999.41534719.9211180914625650.209056814.509448416323449.299313621.473372502521300.308808431.404402989419348.260656645.928348097516590.198295767.56949060813688.745095499.407800414311222.5814066280Celsiuscomplex viscosity (Pa-sec) on frequency (rad per sec) at 280 deg CFrequencyrad/secComplex ViscosityPa-secFrequency (rad / sec)Complex Viscosity (Pa-sec)0.055853308500524.56214548120.099419251478629.08895976850.17696691261343.01389943710.31500225252260.32989906420.56070605306370.69734788430.998060412026102.353102191.77655400831130.5276380463.14391277941195.0628081085.59618514345327.4549162889.90339607248708.46988728217.83465676071633.2004306531.74580473614229.2428743956.179570525711185.837430599.419251478629899.6254778 \ No newline at end of file diff --git a/whyis/materialsmine/tests/xml/L260_S5_Haggenmueller_2006.xml b/whyis/materialsmine/tests/xml/L260_S5_Haggenmueller_2006.xml new file mode 100644 index 00000000..7b7ab9ac --- /dev/null +++ b/whyis/materialsmine/tests/xml/L260_S5_Haggenmueller_2006.xml @@ -0,0 +1,264 @@ + + + L260_S5_Haggenmueller_2006 + L260_S1_Haggenmueller_2006 + + + + research article + Polymer + Interfacial in situ polymerization of single wall carbon nanotube/nylon 6,6 nanocomposites + Haggenmueller, Reto + Du, Fangming + Fischer, John E. + Winey, Karen I. + Nanocomposite + Single wall carbon nanotube + In situ polymerization + Elsevier + 2006 + 10.1016/j.polymer.2006.01.087 + 47 + https://www.sciencedirect.com/science/article/pii/S0032386106001297?via%3Dihub + English + Department of Materials Science and Engineering, University of Pennsylvania, Philadelphia, PA 19104-6272, USA + 2017-07-31 + + + + 0032-3861 + 7 + + + + + + + + Poly[imino(1,6-dioxo-1,6-hexanediyl)imino-1,6-hexanediyl] + nylon 6,6 + + viscosity averaged + 35000 + g/mol + + + + + + single-walled carbon nanotubes + SWNT + + dodecylamine + C12H27N + Aldrich + + the surface areas per chain are ~0.13 nm^2, which corresponds to a surface coverage of only 2.9% + 7.69 + chains/nm^2 + + + + + Functionalization was initiated by refluxing the SWNT at 115 °C in 2.6 M nitric acid for 12 or 48 h while stirring to decorate the SWNT with carboxylic acid groups (–COOH). + stirring + + SWNT + + + nitric acid + 2.6 + M + + + + 115 + Celsius + + + + + washing in water + + + + SWNT-COOH was dried + + + + + dimethyl formamide (DMF) + + + + + these nanotubes were suspended in dimethyl formamide (DMF) to which thionyl chloride (SOCl2) was subsequently added and stirred at 70 °C for 24 h to transform the –COOH groups to chloric acid (–COCl) + stirring + + SWNT-COOH + + + dimethyl formamide (DMF) + + + thionyl chloride (SOCl2) + + + + 70 + Celsius + + + + + washing with anhydrous THF + + + + SWNT-COCl was dried + + + + + the nanotubes were stirred in excess f12 (dodecylamine, C12H27N, Aldrich) at 95 °C for 96 h. + stirring + + SWNT-COCl + + + dodecylamine (C12H27N) + + + + 95 + Celsius + + + + + + + + + 0.02 + + + 2wt% SWNT-f12 + + + + + + + toluene + + + + + The SWNT were suspended in toluene. The in situ polymerization of nylon 6,6 in the presence of the nanotubes was performed with the same reagent ratios as described in S1 for the neat nylon 6,6. + Waring, model 51BL31 + blending + + adipoyl chloride + + + toluene + + + 1,6-hexamethylene diamine + + + deionized water + + + sodium hydroxide + + + + + + + To adjust the nanotube loading, the SWNT/nylon composites were dissolved in formic acid, along with commercial nylon 6,6 ( Mv = 22000 g/mol, Scientific Polymer Products) and precipitated in water. + dissolving + + SWNT/nylon 6,6 composites + + + commercial nylon 6,6 + + + formic acid + + + + + precipitated in water + + + + + + Perkin–Elmer differential scanning calorimeter (DSC 7) + + + Perkin–Elmer 2000 FTIR spectrometer + + + SDT 2960 DTA/TGA analyzer + TA instruments + + + Renishaw micro-Raman spectrometer + + + + + + + on individual melt-spun fiber with diameter of 125±7 μm + 2.39908256881 + GPa + + + + + on individual melt-spun fiber with diameter of 171±9 μm + 1.58256880734 + GPa + + + + + + 3.55e-7 + S/m + + + + Perkin–Elmer differential scanning calorimeter (DSC 7) + + + tested at a heating rate of 10 °C/min, the total crystallinity (~29%) did not change upon blending + 0.29 + + + + The melting temperature (261 °C) did not change upon blending + 261 + Celsius + + + + diff --git a/whyis/materialsmine/tests/xml/L300_S5_Nakane_1999.xml b/whyis/materialsmine/tests/xml/L300_S5_Nakane_1999.xml new file mode 100644 index 00000000..b9806248 --- /dev/null +++ b/whyis/materialsmine/tests/xml/L300_S5_Nakane_1999.xml @@ -0,0 +1,571 @@ + + + L300_S5_Nakane_1999 + L300_S1_Nakane_1999 + + + + poly(vinyl alcohol) + PVA + Kuraray Co., Ltd., Japan + Poval 117 + + + + The polymer underwent resaponification with an aqueous solution of sodium hydroxide + + + Subsequently, it was dilated with pure water in a cellophane tube (Visking Tube) for 3 weeks with occasional change of water. + + + + + + silica + Tetraethoxysilane + TEOS + Shin-etsu Kagaku Co., Ltd., Japan + + + + 0.4 + + + + + + + + + Aqueous HCl was added dropwise to TEOS while stirring + stirring + + 0 + Celsius + + + + + PVA was dropped slowly into silica sol + + + + The mixture was heated in a water bath + + 50 + Celsius + + + + + + + casting + + The mixture was cast in a polystyrene Petri dish + + + + + The sol was aged in a sealed dish for 1 week at 40 C. + + + + The wet gel was dried in air and further in vacuo. + + 40 + Celsius + + atmosphere + + + + + + + (DVE-V4, Rheology Co., Ltd., Japan) + + + (RAD-rA model, Rigaku Co., Ltd., Japan) + + + (TG/DTA220, Seiko Co. Ltd., Japan) + + + + + + + + Strain + percentage + Stress + MPa + + + + Strain (%) + Stress (Mpa) + + + + 0.488947522403 + 24.9897478167 + + + 0.206702455438 + 10.2678907707 + + + 0.0792094406024 + 4.02476970038 + + + 0.458310507435 + 19.158611338 + + + 0.160242593969 + 15.5440079659 + + + 0.90212884315 + 41.2782263019 + + + 0.940644788598 + 32.5323892337 + + + 1.3802561525 + 60.5980280682 + + + 1.22448532952 + 51.9931198677 + + + 0.93220689301 + 47.4921877784 + + + 1.80212313252 + 79.3363291472 + + + 1.9786885736 + 73.9835174962 + + + 1.79906431079 + 67.1880712416 + + + 2.00943420192 + 88.0281205131 + + + 2.30809720581 + 99.0291856973 + + + 2.1881058389 + 94.3884072907 + + + 2.54316050748 + 106.063545902 + + + 2.71920844731 + 111.225327822 + + + 2.81124282387 + 115.638172539 + + + 2.90484571504 + 120.767514725 + + + + + + 52.89440172 + MPa + + + 2.492069658 + MPa + + + + + + tensile + DMA + + + + + 110 + Hz + + + + + + + + Temperature + celsius + Storage Modulus + MPa + + + + Temperature ( C) + Log E' (Mpa) + + + + 38.0465329212 + 3.62951713042 + + + 41.1492153113 + 3.60139413433 + + + 45.313920496 + 3.58634652845 + + + 49.9418732349 + 3.55952824103 + + + 54.7873185446 + 3.50450097462 + + + 59.9212066927 + 3.44325002037 + + + 64.3406431134 + 3.39307140246 + + + 69.1877057087 + 3.33854674261 + + + 75.0697865488 + 3.26409269718 + + + 80.3338691644 + 3.20564055275 + + + 85.5643379116 + 3.13581206148 + + + 90.4834820923 + 3.09517753963 + + + 94.5240895122 + 3.07403168239 + + + 99.3867867985 + 3.0412572934 + + + 104.210632809 + 3.0184046003 + + + 109.381862887 + 3.01775156902 + + + 114.299093587 + 3.03245631411 + + + 119.200619019 + 3.04024589486 + + + 124.015036887 + 3.04119158233 + + + 129.649728027 + 3.0717817723 + + + 134.068624748 + 3.0950444387 + + + 139.427533391 + 3.10422957922 + + + 144.071734062 + 3.11127216046 + + + 149.047953961 + 3.11173322539 + + + 154.026320204 + 3.09906119327 + + + 158.638213609 + 3.08738528479 + + + 163.934687276 + 3.07016161374 + + + 169.258497436 + 3.05477555369 + + + 174.054845044 + 3.02929972325 + + + 178.121525307 + 3.00637958957 + + + + + + + + tensile + DMA + + + + + 110 + Hz + + + + + + + + Temperature + celsius + Tan delta + + + + Temperature ( C) + Tan delta + + + + 40.3923865262 + 0.0698148450086 + + + 44.7061201907 + 0.0739126516004 + + + 48.6801332886 + 0.0793925956124 + + + 52.6491687439 + 0.0843243778817 + + + 55.493698125 + 0.0926799902251 + + + 56.4515950246 + 0.101814101458 + + + 58.7657750302 + 0.111554690116 + + + 62.0459712886 + 0.117231650804 + + + 64.7241421491 + 0.125653268808 + + + 67.2802181225 + 0.132542248591 + + + 71.4368416974 + 0.134117272468 + + + 75.6502167922 + 0.128146417884 + + + 79.65609227 + 0.121675747126 + + + 80.988677771 + 0.115677045359 + + + 83.6234173566 + 0.107901010469 + + + 85.6495170592 + 0.100081890008 + + + 88.5291773232 + 0.0932084402686 + + + 91.5208795315 + 0.0852404626735 + + + 94.6723589156 + 0.0786888994034 + + + 97.8870489159 + 0.0710322658122 + + + 101.863903963 + 0.0653876461836 + + + 106.100161254 + 0.0617402890742 + + + 109.898326264 + 0.0570935651093 + + + 113.081175099 + 0.0529889466358 + + + 116.786610309 + 0.0473989510695 + + + 120.39360718 + 0.0418549538968 + + + 124.683511102 + 0.0397364241021 + + + 129.048986069 + 0.0364785527375 + + + 132.831345642 + 0.034788224467 + + + 137.18434643 + 0.0339310018468 + + + 141.984760265 + 0.0333266438831 + + + 146.049891339 + 0.0320728640703 + + + 150.449107738 + 0.0317957812489 + + + 154.994578904 + 0.030870941688 + + + 159.680519372 + 0.0291449700261 + + + 163.720241257 + 0.0310376934981 + + + 167.934671384 + 0.0301753086894 + + + 171.676673058 + 0.0303633415471 + + + 175.646659745 + 0.0309686051712 + + + 179.519183292 + 0.030853661026 + + + + + + + + + + 452.3885182 + Celsius + + + 70.16129032 + Celsius + + + + + + + 50 + micrometers + + + + diff --git a/whyis/materialsmine/vocab.ttl b/whyis/materialsmine/vocab.ttl new file mode 100644 index 00000000..34e3cc1e --- /dev/null +++ b/whyis/materialsmine/vocab.ttl @@ -0,0 +1,48 @@ +@prefix : . +@prefix dc: . +@prefix np: . +@prefix owl: . +@prefix rdf: . +@prefix sio: . +@prefix xml: . +@prefix xsd: . +@prefix auth: . +@prefix foaf: . +@prefix prov: . +@prefix rdfg: . +@prefix rdfs: . +@prefix skos: . +@prefix flaskld: . +@base . +@prefix whyis: . +@prefix bibo: . + + + + a . + + rdfs:subClassOf owl:Class. + + a owl:Class; + whyis:hasConstraints "class_constraints.json"; + whyis:hasOutgoing "outgoing_class.json"; + whyis:hasIncoming "incoming_class.json"; + whyis:newInstanceView "new_instance_view.html"; + whyis:hasView "class_view.html"; + whyis:hasFacets "pnc_facets.json"; + whyis:hasFacetValues "facet_values_20210625_HARDCODED.json". + + a whyis:ChartVizGallery. + +whyis:DatasetClass a owl:Class; + rdfs:subClassOf owl:Class; + whyis:newInstanceView "dataset_new.html". + +:MetamaterialDataset a whyis:DatasetClass. +:NanomaterialDataset a whyis:DatasetClass. + +whyis:ChartVizGallery whyis:hasView "chart_gallery.html". + +:NanomaterialChart a whyis:ChartClass. +:MetamaterialChart a whyis:ChartClass. + diff --git a/whyis/materialsmine/whyis.conf b/whyis/materialsmine/whyis.conf new file mode 100644 index 00000000..3f746d8c --- /dev/null +++ b/whyis/materialsmine/whyis.conf @@ -0,0 +1,142 @@ +# -*- config:utf-8 -*- +from whyis import autonomic, importer +from materialsmine.agent import * +import whyis_unit_converter.unit_converter_agent as converter + + +SITE_NAME = "MaterialsMine" +SITE_DESCRIPTION = 'A knowledge graph for Material Informatics.' +LOD_PREFIX = 'http://materialsmine.org' +SECURITY_EMAIL_SENDER = "Whyis " +DEFAULT_LANGUAGE = 'en' +BASE_RATE_PROBABILITY = 0.5 +VOCAB_FILE = "vocab.ttl" + +# EMAIL CONFIGURATION +## MAIL_SERVER = "", +## MAIL_PORT = 587, +## MAIL_USE_TLS = True, +## MAIL_USE_SSL = False, +## MAIL_DEBUG = False, +## MAIL_USERNAME = '', +## MAIL_PASSWORD = '', +## DEFAULT_MAIL_SENDER = "Whyis ", +DEFAULT_ANONYMOUS_READ = True + +NAMESPACES = [ + importer.LinkedData( + prefix = LOD_PREFIX+'/dcat/', + url = 'http://www.w3.org/ns/dcat#%s', + headers={'Accept':'text/turtle'}, + format='turtle' + ), + importer.LinkedData( + prefix = LOD_PREFIX+'/doi/', + url = 'http://dx.doi.org/%s', + headers={'Accept':'text/turtle'}, + format='turtle', + postprocess_update= ['''insert { + graph ?g { + ?pub a . + } + } where { + graph ?g { + ?pub ?doi. + } + }''', + '''delete { + ?author ?orcid. + } insert { + graph ?g { + ?author ?orcid. + } + } where { + graph ?g { + ?author a ; + ?orcid. + } + } + '''] + ), + importer.LinkedData( + prefix = LOD_PREFIX+'/orcid/', + url = 'http://orcid.org/%s', + headers={'Accept':'application/ld+json'}, + format='json-ld', + replace=[ + ('\\"http:\\/\\/schema\\.org\\",', '{"@vocab" : "http://schema.org/"},'), + ('https://doi.org/', 'http://dx.doi.org/'), + ('https://', 'http://'), + ], + postprocess_update= ['''delete { + ?org ?p ?o. + ?s ?p ?org. + } insert { + graph ?g { + ?s ?p ?o. + } + } where { + graph ?g { + { + ?org a ; + [ + a ; + ?propertyID; + ?idValue; + ]. + ?org ?p ?o. + bind(IRI(concat("%s/organization/", str(?propertyID),"/",str(?idValue))) as ?s) + } union { + ?org a ; + [ + a ; + ?propertyID; + ?idValue; + ]. + ?s ?p ?org. + bind(IRI(concat("%s/organization/", str(?propertyID),"/",str(?idValue))) as ?o) + } + } + }''' % (LOD_PREFIX, LOD_PREFIX) , + ''' + insert { + graph ?g { + ?s ?name. + } + } where { + graph ?g { + ?s ?name. + } + } + '''] + ), + importer.LinkedData( + prefix = LOD_PREFIX+'/dbpedia/', + url = 'http://dbpedia.org/resource/%s', + headers={'Accept':'text/turtle'}, + format='turtle', + postprocess_update= '''insert { + graph ?g { + ?article ?abstract. + } + } where { + graph ?g { + ?article ?abstract. + } + } + ''' + ) +] + +INFERENCERS = { + "SDDAgent": autonomic.SDDAgent(), + "SETLr": autonomic.SETLr(), + "SETLMaker": autonomic.SETLMaker(), + "CacheUpdater" : autonomic.CacheUpdater(), + "UnitConverter": converter.UnitConverter(), + "EntityExtractor" : autonomic.nlp.EntityExtractor(), + "EntityResolver" : autonomic.nlp.EntityResolver(), +} + +INFERENCE_TASKS = [ +] diff --git a/whyis/materialsmine/wsgi.py b/whyis/materialsmine/wsgi.py new file mode 100644 index 00000000..a21ebdac --- /dev/null +++ b/whyis/materialsmine/wsgi.py @@ -0,0 +1 @@ +from whyis.wsgi import * diff --git a/whyis/materialsmine/xml_files/download_xml.py b/whyis/materialsmine/xml_files/download_xml.py new file mode 100644 index 00000000..04e22ba7 --- /dev/null +++ b/whyis/materialsmine/xml_files/download_xml.py @@ -0,0 +1,41 @@ +import os +import logging +import json +import requests +from SPARQLWrapper import JSON, SPARQLWrapper + + +def download(): + logging.basicConfig(level=logging.INFO) + endpoint = SPARQLWrapper("https://materialsmine.org/wi/sparql") + endpoint.setQuery( + """ + SELECT DISTINCT ?article WHERE { + ?doi a . + ?doi ?article . + } + """ + ) + endpoint.setReturnFormat(JSON) + results = endpoint.query().convert() + uris = [r["article"]["value"].replace("http://nanomine.org/sample/", "").replace("-", "_").title() + for r in results["results"]["bindings"]] + files = [uri + ".xml" for uri in uris] + for f in files: + if (os.path.exists(f)): + logging.info("File " + f + " already exists, skipping") + else: + logging.debug("Downloading file " + str(f)) + r = requests.get("http://nanomine.org/nmr/xml/" + f) + try: + j = json.loads(r.text) + xml_str = j["data"][0]["xml_str"] + with open(f, "w") as outfile: + outfile.write(xml_str) + except Exception as e: + logging.error("Something went wrong with file " + f) + logging.error(e) + + +if __name__ == "__main__": + download() From b759d27c0a70fa3091ce15513bd8e2e72698e182 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Tue, 25 Jan 2022 14:46:21 -0800 Subject: [PATCH 079/306] Add basic tests for chart edit template. Modify after vega implementation --- app/src/components/explorer/ChartEdit.vue | 2 +- .../unit/pages/explorer/ChartEdit.spec.js | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 app/tests/unit/pages/explorer/ChartEdit.spec.js diff --git a/app/src/components/explorer/ChartEdit.vue b/app/src/components/explorer/ChartEdit.vue index 4a382c27..3a419992 100644 --- a/app/src/components/explorer/ChartEdit.vue +++ b/app/src/components/explorer/ChartEdit.vue @@ -48,7 +48,7 @@
- +
diff --git a/app/tests/unit/pages/explorer/ChartEdit.spec.js b/app/tests/unit/pages/explorer/ChartEdit.spec.js new file mode 100644 index 00000000..295e2f96 --- /dev/null +++ b/app/tests/unit/pages/explorer/ChartEdit.spec.js @@ -0,0 +1,45 @@ +import VueMaterial from 'vue-material' +import { enableAutoDestroy, mount, createLocalVue, resetAutoDestroyState } from '@vue/test-utils' +import ChartEdit from '@/components/explorer/ChartEdit.vue' +import store from '@/store' + +document.body.createTextRange = (elem) => { + const textRange = { + getBoundingClientRect: () => 1, + getClientRects: () => 1 + } + return textRange +} + +describe('ChartEdit.vue', () => { + let wrapper + beforeEach(async () => { + const localVue = createLocalVue() + localVue.use(VueMaterial) + wrapper = mount(ChartEdit, { + localVue, + store + }) + }) + enableAutoDestroy(afterEach) + afterAll(resetAutoDestroyState) + + it('renders yasqe', () => { + expect(wrapper.findComponent('.yasqe').exists()).toBeTruthy() + }) + it('renders yasr', () => { + expect(wrapper.findComponent('.yasr').exists()).toBeTruthy() + }) + it('renders a vjson editor if spec', async () => { + await wrapper.vm.setBaseSpec('test') + expect(wrapper.findComponent('.jsoneditor-container').exists()).toBeTruthy() + }) + it('renders the save tab correctly', () => { + const titleField = wrapper.findComponent('.chart-title-field') + const descriptionField = wrapper.findComponent('.chart-description-field') + const submitButton = wrapper.findComponent('#saveChartButton') + expect(titleField.text()).toContain('Title') + expect(descriptionField.text()).toContain('Description') + expect(submitButton.text()).toContain('Save Chart') + }) +}) From 3ea703a4202598ca227f781831d71dc2d0bed455 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Tue, 25 Jan 2022 16:19:57 -0800 Subject: [PATCH 080/306] #65: Simple unit test for chart view --- app/src/components/explorer/ChartView.vue | 13 ++------ .../unit/pages/explorer/ChartView.spec.js | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 app/tests/unit/pages/explorer/ChartView.spec.js diff --git a/app/src/components/explorer/ChartView.vue b/app/src/components/explorer/ChartView.vue index 0427a744..cd29705c 100644 --- a/app/src/components/explorer/ChartView.vue +++ b/app/src/components/explorer/ChartView.vue @@ -138,6 +138,7 @@ import VJsoneditor from 'v-jsoneditor' import Dialog from '@/components/dialog.vue' import { getDefaultChart, buildSparqlSpec } from '@/modules/vega-chart' +import { mapGetters } from 'vuex' export default { name: 'chart-view', @@ -148,17 +149,11 @@ export default { data () { return { error: { status: false, message: null }, - filter: false, loading: true, spec: null, - chart: { - title: 'Test title', - description: 'Here is a description of a chart which depicts some data that was recorded by researchers. The research corresponds to a paper which was published in a journal at a date. The data is stored in a database which can be accessed via a link.' - }, + chart: null, chartTags: [], args: null, - authenticated: true, - // authenticated: EventServices.authUser, allowEdit: false, vizOfTheDay: false, voyager: { @@ -176,6 +171,7 @@ export default { } }, computed: { + ...mapGetters('auth', ['isAuthenticated']), specViewerSpec () { return this.specViewer.includeData ? this.spec : this.chart && this.chart.baseSpec } @@ -211,9 +207,6 @@ export default { }, created () { this.loading = true - // EventServices - // .$on('isauthenticated', (data) => this.authenticated = data) - // .$on('allowChartEdit', (data) => this.allowEdit = data) } } diff --git a/app/tests/unit/pages/explorer/ChartView.spec.js b/app/tests/unit/pages/explorer/ChartView.spec.js new file mode 100644 index 00000000..9a695523 --- /dev/null +++ b/app/tests/unit/pages/explorer/ChartView.spec.js @@ -0,0 +1,31 @@ +import VueMaterial from 'vue-material' +import { enableAutoDestroy, shallowMount, createLocalVue, resetAutoDestroyState } from '@vue/test-utils' +import ChartView from '@/components/explorer/ChartView.vue' + +describe('ChartView.vue', () => { + let wrapper + beforeEach(async () => { + const localVue = createLocalVue() + localVue.use(VueMaterial) + wrapper = shallowMount(ChartView, { + localVue + }) + }) + enableAutoDestroy(afterEach) + afterAll(resetAutoDestroyState) + + const chart = { + title: 'Test Title', + description: 'Test chart description' + } + + it('renders title from chart data', async () => { + await wrapper.setData({ chart }) + const title = wrapper.findComponent('.md-headline') + expect(title.text()).toContain('Test Title') + }) + it('renders description from chart data', async () => { + await wrapper.setData({ chart }) + expect(wrapper.text()).toContain('Test chart description') + }) +}) From 765b87377a23fe1868ba9f80142ec1942d275b41 Mon Sep 17 00:00:00 2001 From: Kevin Z - Razer Date: Tue, 25 Jan 2022 19:51:12 -0500 Subject: [PATCH 081/306] #67: create vue components for sample page --- app/src/pages/explorer/sample/Sample.vue | 2 + .../CuratedProcessingStepsParameters.vue | 84 +++++++++++++++++++ ...CuratedPropertiesOfNanocompositeSample.vue | 62 ++++++++++++++ .../MaterialComponentsAndAttributes.vue | 68 +++++++++++++++ .../sample/components/OtherSamples.vue | 58 +++++++++++++ .../sample/components/SampleHeader.vue | 60 +++++++++++++ .../sample/components/SampleImages.vue | 54 ++++++++++++ app/src/pages/explorer/sample/sample.html | 8 ++ 8 files changed, 396 insertions(+) create mode 100644 app/src/pages/explorer/sample/Sample.vue create mode 100644 app/src/pages/explorer/sample/components/CuratedProcessingStepsParameters.vue create mode 100644 app/src/pages/explorer/sample/components/CuratedPropertiesOfNanocompositeSample.vue create mode 100644 app/src/pages/explorer/sample/components/MaterialComponentsAndAttributes.vue create mode 100644 app/src/pages/explorer/sample/components/OtherSamples.vue create mode 100644 app/src/pages/explorer/sample/components/SampleHeader.vue create mode 100644 app/src/pages/explorer/sample/components/SampleImages.vue create mode 100644 app/src/pages/explorer/sample/sample.html diff --git a/app/src/pages/explorer/sample/Sample.vue b/app/src/pages/explorer/sample/Sample.vue new file mode 100644 index 00000000..ae909561 --- /dev/null +++ b/app/src/pages/explorer/sample/Sample.vue @@ -0,0 +1,2 @@ + + diff --git a/app/src/pages/explorer/sample/components/CuratedProcessingStepsParameters.vue b/app/src/pages/explorer/sample/components/CuratedProcessingStepsParameters.vue new file mode 100644 index 00000000..a3f480f4 --- /dev/null +++ b/app/src/pages/explorer/sample/components/CuratedProcessingStepsParameters.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/app/src/pages/explorer/sample/components/CuratedPropertiesOfNanocompositeSample.vue b/app/src/pages/explorer/sample/components/CuratedPropertiesOfNanocompositeSample.vue new file mode 100644 index 00000000..f455abb6 --- /dev/null +++ b/app/src/pages/explorer/sample/components/CuratedPropertiesOfNanocompositeSample.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/app/src/pages/explorer/sample/components/MaterialComponentsAndAttributes.vue b/app/src/pages/explorer/sample/components/MaterialComponentsAndAttributes.vue new file mode 100644 index 00000000..bdeb6e9c --- /dev/null +++ b/app/src/pages/explorer/sample/components/MaterialComponentsAndAttributes.vue @@ -0,0 +1,68 @@ + + + + diff --git a/app/src/pages/explorer/sample/components/OtherSamples.vue b/app/src/pages/explorer/sample/components/OtherSamples.vue new file mode 100644 index 00000000..2c8f1cba --- /dev/null +++ b/app/src/pages/explorer/sample/components/OtherSamples.vue @@ -0,0 +1,58 @@ + + + + diff --git a/app/src/pages/explorer/sample/components/SampleHeader.vue b/app/src/pages/explorer/sample/components/SampleHeader.vue new file mode 100644 index 00000000..13eb89f5 --- /dev/null +++ b/app/src/pages/explorer/sample/components/SampleHeader.vue @@ -0,0 +1,60 @@ + + + + diff --git a/app/src/pages/explorer/sample/components/SampleImages.vue b/app/src/pages/explorer/sample/components/SampleImages.vue new file mode 100644 index 00000000..ca95500c --- /dev/null +++ b/app/src/pages/explorer/sample/components/SampleImages.vue @@ -0,0 +1,54 @@ + + + + diff --git a/app/src/pages/explorer/sample/sample.html b/app/src/pages/explorer/sample/sample.html new file mode 100644 index 00000000..cd06668e --- /dev/null +++ b/app/src/pages/explorer/sample/sample.html @@ -0,0 +1,8 @@ +
+ + + + + + +
From dae8d62bb51a9282b778d484777ef9d737fb5d29 Mon Sep 17 00:00:00 2001 From: Kevin Z - Razer Date: Tue, 25 Jan 2022 19:52:07 -0500 Subject: [PATCH 082/306] #67: add explorer route to sample page --- app/src/router/module/explorer.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/router/module/explorer.js b/app/src/router/module/explorer.js index 49604436..25566c32 100644 --- a/app/src/router/module/explorer.js +++ b/app/src/router/module/explorer.js @@ -4,6 +4,12 @@ const explorerRoutes = [ name: 'ExplorerHome', component: () => import('@/pages/explorer/Home.vue'), meta: { requiresAuth: false } + }, + { + path: '/explorer/sample/:label', + name: 'Sample View', + component: () => import('@/pages/explorer/sample/Sample.vue'), + meta: { requiresAuth: false } } ] From 9f1447bb8e6bb62a04bfde03f784821679898214 Mon Sep 17 00:00:00 2001 From: Kevin Z - Razer Date: Tue, 25 Jan 2022 19:55:04 -0500 Subject: [PATCH 083/306] #67: add queries and helper functions --- .../explorer/sample/queries/classQuery.js | 15 ++++++++ .../sample/queries/curatedPropertiesQuery.js | 17 +++++++++ .../explorer/sample/queries/imagesQuery.js | 12 +++++++ .../sample/queries/materialComponentQuery.js | 36 +++++++++++++++++++ .../sample/queries/otherSamplesQuery.js | 10 ++++++ .../sample/queries/processingStepsQuery.js | 33 +++++++++++++++++ .../pages/explorer/sample/queries/settings.js | 19 ++++++++++ .../explorer/sample/queries/titleQuery.js | 14 ++++++++ .../pages/explorer/sample/services/damien.js | 19 ++++++++++ .../explorer/sample/services/getClass.js | 21 +++++++++++ 10 files changed, 196 insertions(+) create mode 100644 app/src/pages/explorer/sample/queries/classQuery.js create mode 100644 app/src/pages/explorer/sample/queries/curatedPropertiesQuery.js create mode 100644 app/src/pages/explorer/sample/queries/imagesQuery.js create mode 100644 app/src/pages/explorer/sample/queries/materialComponentQuery.js create mode 100644 app/src/pages/explorer/sample/queries/otherSamplesQuery.js create mode 100644 app/src/pages/explorer/sample/queries/processingStepsQuery.js create mode 100644 app/src/pages/explorer/sample/queries/settings.js create mode 100644 app/src/pages/explorer/sample/queries/titleQuery.js create mode 100644 app/src/pages/explorer/sample/services/damien.js create mode 100644 app/src/pages/explorer/sample/services/getClass.js diff --git a/app/src/pages/explorer/sample/queries/classQuery.js b/app/src/pages/explorer/sample/queries/classQuery.js new file mode 100644 index 00000000..e00c3483 --- /dev/null +++ b/app/src/pages/explorer/sample/queries/classQuery.js @@ -0,0 +1,15 @@ +import { commonPrefixes } from './settings' + +const query = ( + route +) => `${commonPrefixes}SELECT DISTINCT (REPLACE(STR(?doi),"http://dx.doi.org/","") AS ?DOI) ?sample_label ?process_label WHERE { + ?sample a mm:PolymerNanocomposite ; + rdfs:label ?sample_label ; + prov:wasGeneratedBy [ a ?ProcessType ] . + ?doi a dct:BibliographicResource ; + sio:hasPart ?sample. + ?ProcessType rdfs:label ?process_label . + FILTER(REGEX(STR(?ProcessType),"materialsmine")) +} VALUES ?sample {}` + +export default query diff --git a/app/src/pages/explorer/sample/queries/curatedPropertiesQuery.js b/app/src/pages/explorer/sample/queries/curatedPropertiesQuery.js new file mode 100644 index 00000000..0d731255 --- /dev/null +++ b/app/src/pages/explorer/sample/queries/curatedPropertiesQuery.js @@ -0,0 +1,17 @@ +import { commonPrefixes } from './settings' + +const query = ( + route +) => `${commonPrefixes}SELECT DISTINCT ?AttrType ?value (GROUP_CONCAT(DISTINCT ?unit; SEPARATOR="; ") AS ?Units) WHERE { + ?sample a mm:PolymerNanocomposite ; + sio:hasAttribute ?attr . + FILTER NOT EXISTS { ?attr sio:inRelationTo ?otherAttr } + ?attr a ?AttrType ; + sio:hasValue ?value . + OPTIONAL { + ?attr sio:hasUnit [ rdfs:label ?unit ] + } +} GROUP BY ?attr ?AttrType ?value +VALUES ?sample { }` + +export default query diff --git a/app/src/pages/explorer/sample/queries/imagesQuery.js b/app/src/pages/explorer/sample/queries/imagesQuery.js new file mode 100644 index 00000000..ef549dc9 --- /dev/null +++ b/app/src/pages/explorer/sample/queries/imagesQuery.js @@ -0,0 +1,12 @@ +import { commonPrefixes } from './settings' + +const query = (route) => `${commonPrefixes}SELECT DISTINCT * WHERE { + ?sample a mm:PolymerNanocomposite ; + sio:isRepresentedBy ?image . + ?image a sio:Image . + FILTER(!REGEX(STR(?image),"localhost")) + FILTER(!REGEX(STR(?image),"XMLCONV")) + FILTER(!REGEX(STR(?image),"nanomine")) +} VALUES ?sample { }` + +export default query diff --git a/app/src/pages/explorer/sample/queries/materialComponentQuery.js b/app/src/pages/explorer/sample/queries/materialComponentQuery.js new file mode 100644 index 00000000..e014c8fe --- /dev/null +++ b/app/src/pages/explorer/sample/queries/materialComponentQuery.js @@ -0,0 +1,36 @@ +import { commonPrefixes } from './settings' + +const query = ( + route +) => `${commonPrefixes}SELECT DISTINCT ?std_name ?role ?attrType ?attrValue (GROUP_CONCAT(DISTINCT ?AttrUnit; SEPARATOR="; ") AS ?attrUnits) ?fullLabel WHERE { + { + ?sample a mm:PolymerNanocomposite ; + rdfs:label ?fullLabel ; + sio:hasComponentPart ?component . + ?component a ?compound ; + sio:hasRole [ a [ rdfs:label ?role ] ] . + ?compound rdfs:label ?std_name . + ?component sio:hasAttribute ?attr. + ?attr a ?attrType ; + sio:hasValue ?attrValue . + OPTIONAL { + ?attr sio:hasUnit [ rdfs:label ?AttrUnit ] + } + } UNION + { + ?sample a mm:PolymerNanocomposite ; + rdfs:label ?fullLabel ; + sio:hasComponentPart/sio:isSurroundedBy ?compound . + ?compound sio:hasRole [ a [ rdfs:label ?role ] ] ; + rdfs:label ?std_name . + ?compound sio:hasAttribute ?attr. + ?attr a ?attrType ; + sio:hasValue ?attrValue . + OPTIONAL { + ?attr sio:hasUnit [ rdfs:label ?AttrUnit ] + } + } +} GROUP BY ?std_name ?role ?attrType ?attrValue ?fullLabel ORDER BY ?std_name ?role ?AttrType +VALUES ?sample {}` + +export default query diff --git a/app/src/pages/explorer/sample/queries/otherSamplesQuery.js b/app/src/pages/explorer/sample/queries/otherSamplesQuery.js new file mode 100644 index 00000000..dca3ddcb --- /dev/null +++ b/app/src/pages/explorer/sample/queries/otherSamplesQuery.js @@ -0,0 +1,10 @@ +import { commonPrefixes } from './settings' + +const query = (route) => `${commonPrefixes}SELECT DISTINCT ?sample WHERE { + ?doi sio:hasPart ?this, ?sample . + ?sample a mm:PolymerNanocomposite . + FILTER(?this != ?sample) +} +VALUES ?this { }` + +export default query diff --git a/app/src/pages/explorer/sample/queries/processingStepsQuery.js b/app/src/pages/explorer/sample/queries/processingStepsQuery.js new file mode 100644 index 00000000..e37bba38 --- /dev/null +++ b/app/src/pages/explorer/sample/queries/processingStepsQuery.js @@ -0,0 +1,33 @@ +import { commonPrefixes } from './settings' + +const query = ( + route +) => `${commonPrefixes}SELECT ?step ?param_label (GROUP_CONCAT(?ParamDescr; SEPARATOR="; ") AS ?Descr) +WHERE { + { + SELECT ?step ?param_label (MIN(?AttrLabel) AS ?attr) ?value (MIN(?unit) AS ?unit_label) WHERE { + ?sample a mm:PolymerNanocomposite ; + prov:wasGeneratedBy [ a ?ProcessType ; + sio:hasPart ?step ] . + OPTIONAL { + ?step sio:hasParameter ?param . + ?param sio:hasAttribute [ a ?AttrType ; sio:hasValue ?value ] . + ?AttrType rdfs:label ?AttrLabel . + } + OPTIONAL { + ?step sio:hasParameter ?param . + ?param sio:hasAttribute [ a ?AttrType ; sio:hasValue ?value ; sio:hasUnit [ rdfs:label ?unit ] ] . + ?AttrType rdfs:label ?AttrLabel . + } + ?step a [ rdfs:label ?step_type ] . + ?param a ?param_type . + ?param_type rdfs:label ?param_label . + FILTER(REGEX(STR(?ProcessType),"materialsmine")) + FILTER(REGEX(STR(?param_type),"materialsmine")) + } GROUP BY ?step ?param_label ?value ORDER BY ?attr + VALUES ?sample { } + } + BIND(IF(BOUND(?unit_label), CONCAT(?attr, ": ", ?value, " ", ?unit_label), CONCAT(?attr, ": ", ?value)) AS ?ParamDescr) +} GROUP BY ?step ?param_label ORDER BY ?step` + +export default query diff --git a/app/src/pages/explorer/sample/queries/settings.js b/app/src/pages/explorer/sample/queries/settings.js new file mode 100644 index 00000000..b34ef644 --- /dev/null +++ b/app/src/pages/explorer/sample/queries/settings.js @@ -0,0 +1,19 @@ +const urlEndpoint = 'https://materialsmine.org/wi/sparql' + +export const commonPrefixes = `PREFIX rdf: +PREFIX rdfs: +PREFIX dct: +PREFIX sio: +PREFIX mm: +PREFIX prov: ` + +export const requestOptions = { + headers: { accept: 'application/sparql-results+json' } +} +export const encodeQuery = (query) => + `${urlEndpoint}?query=${encodeURIComponent(query)}&output=json` + +export const querySparqlEndpoint = ({ query, route }) => { + const sparqlQuery = query(route) + return encodeQuery(sparqlQuery) +} diff --git a/app/src/pages/explorer/sample/queries/titleQuery.js b/app/src/pages/explorer/sample/queries/titleQuery.js new file mode 100644 index 00000000..373bd69b --- /dev/null +++ b/app/src/pages/explorer/sample/queries/titleQuery.js @@ -0,0 +1,14 @@ +import { commonPrefixes } from './settings' + +const query = (route) => `${commonPrefixes} +SELECT DISTINCT (REPLACE(STR(?doi),"http://dx.doi.org/","") AS ?DOI) ?sample_label ?process_label WHERE { + ?sample a mm:PolymerNanocomposite ; + rdfs:label ?sample_label ; + prov:wasGeneratedBy [ a ?ProcessType ] . + ?doi a dct:BibliographicResource ; + sio:hasPart ?sample. + ?ProcessType rdfs:label ?process_label . + FILTER(REGEX(STR(?ProcessType),"materialsmine")) +} VALUES ?sample { }` + +export default query diff --git a/app/src/pages/explorer/sample/services/damien.js b/app/src/pages/explorer/sample/services/damien.js new file mode 100644 index 00000000..1b7a6fdd --- /dev/null +++ b/app/src/pages/explorer/sample/services/damien.js @@ -0,0 +1,19 @@ +export function parseSPARQL (response) { + const queryResults = [] + for (let i = 0; i < response.results.bindings.length; i++) { + const newObject = {} + const row = response.results.bindings[i] + for (const variable of response.head.vars) { + if (row !== undefined && row[variable] !== undefined && row[variable]) { + if (!isNaN(row[variable].value)) { + newObject[variable] = +row[variable].value + } else { + newObject[variable] = row[variable].value + } + queryResults[i] = newObject + } + } + } + + return queryResults +} diff --git a/app/src/pages/explorer/sample/services/getClass.js b/app/src/pages/explorer/sample/services/getClass.js new file mode 100644 index 00000000..65a54421 --- /dev/null +++ b/app/src/pages/explorer/sample/services/getClass.js @@ -0,0 +1,21 @@ +import { requestOptions, querySparqlEndpoint } from '../queries/settings' +import { parseSPARQL } from './damien' + +const parseTitleData = (data) => { + const parsedData = parseSPARQL(data) + if (!parsedData.length) return null + const [processLabelObject] = parsedData + const { process_label: processLabel } = processLabelObject + return processLabel +} + +export default async function getClass ({ + query, + route, + options = requestOptions +}) { + const urlEncodedQuery = querySparqlEndpoint({ query, route }) + const res = await fetch(urlEncodedQuery, options) + const classes = await res.json().then(parseTitleData) + return classes +} From 815b58be886dc87acf12cc0cdd936abfeece8354 Mon Sep 17 00:00:00 2001 From: Kevin Z - Razer Date: Tue, 25 Jan 2022 19:55:34 -0500 Subject: [PATCH 084/306] #67: create a sample page parent component --- app/src/pages/explorer/sample/sample.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 app/src/pages/explorer/sample/sample.js diff --git a/app/src/pages/explorer/sample/sample.js b/app/src/pages/explorer/sample/sample.js new file mode 100644 index 00000000..6d16d92a --- /dev/null +++ b/app/src/pages/explorer/sample/sample.js @@ -0,0 +1,21 @@ +import SampleHeader from './components/SampleHeader.vue' +import SampleImages from './components/SampleImages.vue' +import MaterialComponentsAndAttributes from './components/MaterialComponentsAndAttributes.vue' +import CuratedProcessingStepsParameters from './components/CuratedProcessingStepsParameters.vue' +import OtherSamples from './components/OtherSamples.vue' +import CuratedPropertiesOfNanocompositeSample from './components/CuratedPropertiesOfNanocompositeSample.vue' + +export default { + name: 'Sample', + components: { + SampleHeader, + SampleImages, + MaterialComponentsAndAttributes, + CuratedProcessingStepsParameters, + CuratedPropertiesOfNanocompositeSample, + OtherSamples + }, + created () { + this.$store.commit('setAppHeaderInfo', { icon: 'science', name: 'Sample' }) + } +} From 72d09c3775e7bc68ba0c32ad3d771a4b889139b8 Mon Sep 17 00:00:00 2001 From: Kevin Z - Razer Date: Tue, 25 Jan 2022 19:57:23 -0500 Subject: [PATCH 085/306] #67: add data processing functions --- .../sample/services/getCuratedProperties.js | 30 ++++++++++ .../sample/services/getMaterialData.js | 55 +++++++++++++++++++ .../sample/services/getOtherSamples.js | 19 +++++++ .../sample/services/getProcessingSteps.js | 23 ++++++++ .../sample/services/getSampleHeader.js | 20 +++++++ .../sample/services/getSampleImages.js | 21 +++++++ 6 files changed, 168 insertions(+) create mode 100644 app/src/pages/explorer/sample/services/getCuratedProperties.js create mode 100644 app/src/pages/explorer/sample/services/getMaterialData.js create mode 100644 app/src/pages/explorer/sample/services/getOtherSamples.js create mode 100644 app/src/pages/explorer/sample/services/getProcessingSteps.js create mode 100644 app/src/pages/explorer/sample/services/getSampleHeader.js create mode 100644 app/src/pages/explorer/sample/services/getSampleImages.js diff --git a/app/src/pages/explorer/sample/services/getCuratedProperties.js b/app/src/pages/explorer/sample/services/getCuratedProperties.js new file mode 100644 index 00000000..127a466e --- /dev/null +++ b/app/src/pages/explorer/sample/services/getCuratedProperties.js @@ -0,0 +1,30 @@ +import { requestOptions, querySparqlEndpoint } from '../queries/settings' +import { parseSPARQL } from './damien' + +const parseCuratedProperties = (data) => { + const parseData = parseSPARQL(data) + const curatedProperties = parseData.map((property) => { + const { AttrType, value, Units: units } = property + const type = AttrType.split('/') + .pop() + .match(/[A-Z][a-z]+|[0-9]+/g) + .join(' ') + return { + type, + units, + value + } + }) + return curatedProperties +} + +export default async function getCuratedProperties ({ + query, + route, + options = requestOptions +}) { + const urlEncodedQuery = querySparqlEndpoint({ query, route }) + const res = await fetch(urlEncodedQuery, options) + const curatedProperties = await res.json().then(parseCuratedProperties) + return curatedProperties +} diff --git a/app/src/pages/explorer/sample/services/getMaterialData.js b/app/src/pages/explorer/sample/services/getMaterialData.js new file mode 100644 index 00000000..16778ac8 --- /dev/null +++ b/app/src/pages/explorer/sample/services/getMaterialData.js @@ -0,0 +1,55 @@ +import { requestOptions, querySparqlEndpoint } from '../queries/settings' +import { parseSPARQL } from './damien' + +function parsePropertyData (data) { + const seen = new Set() + const filteredArr = data + .filter((item) => { + const duplicate = seen.has(item.std_name) + seen.add(item.std_name) + return !duplicate + }) + .map((item) => { + return { + classType: item.std_name, + role: item.role + } + }) + + filteredArr.forEach((element) => { + const materialProperties = data + .filter((item) => item.std_name === element.classType) + .map((item) => { + const { attrUnits, attrValue: value, attrType } = item + const units = attrUnits || '' + const type = attrType + .split('/') + .pop() + .match(/[A-Z][a-z]+|[0-9]+/g) + .join(' ') + return { + type, + units, + value + } + }) + element.materialProperties = materialProperties + }) + return filteredArr +} +const parseMaterialData = (data) => { + const parsedSPARQL = parseSPARQL(data) + const materialData = parsePropertyData(parsedSPARQL) + return materialData +} + +export default async function getMaterialData ({ + query, + route, + options = requestOptions +}) { + const urlEncodedQuery = querySparqlEndpoint({ query, route }) + const res = await fetch(urlEncodedQuery, options) + const materialData = await res.json().then(parseMaterialData) + return materialData +} diff --git a/app/src/pages/explorer/sample/services/getOtherSamples.js b/app/src/pages/explorer/sample/services/getOtherSamples.js new file mode 100644 index 00000000..e0829b70 --- /dev/null +++ b/app/src/pages/explorer/sample/services/getOtherSamples.js @@ -0,0 +1,19 @@ +import { requestOptions, querySparqlEndpoint } from '../queries/settings' +import { parseSPARQL } from './damien' + +const parseOtherSamples = (data) => { + const parsedData = parseSPARQL(data) + const links = parsedData.map(({ sample }) => sample.split('/').pop()) + return links +} + +export default async function getOtherSamples ({ + query, + route, + options = requestOptions +}) { + const urlEncodedQuery = querySparqlEndpoint({ query, route }) + const res = await fetch(urlEncodedQuery, options) + const samples = await res.json().then(parseOtherSamples) + return samples +} diff --git a/app/src/pages/explorer/sample/services/getProcessingSteps.js b/app/src/pages/explorer/sample/services/getProcessingSteps.js new file mode 100644 index 00000000..e5c10c20 --- /dev/null +++ b/app/src/pages/explorer/sample/services/getProcessingSteps.js @@ -0,0 +1,23 @@ +import { requestOptions, querySparqlEndpoint } from '../queries/settings' +import { parseSPARQL } from './damien' + +const parseTitleData = (data) => { + const parsedData = parseSPARQL(data) + const steps = parsedData.map( + ({ param_label: parameterLabel, Descr: description }) => { + return { parameterLabel, description } + } + ) + return steps +} + +export default async function getProcessingSteps ({ + query, + route, + options = requestOptions +}) { + const urlEncodedQuery = querySparqlEndpoint({ query, route }) + const res = await fetch(urlEncodedQuery, options) + const classes = await res.json().then(parseTitleData) + return classes +} diff --git a/app/src/pages/explorer/sample/services/getSampleHeader.js b/app/src/pages/explorer/sample/services/getSampleHeader.js new file mode 100644 index 00000000..d85c7e4c --- /dev/null +++ b/app/src/pages/explorer/sample/services/getSampleHeader.js @@ -0,0 +1,20 @@ +import { requestOptions, querySparqlEndpoint } from '../queries/settings' +import { parseSPARQL } from './damien' + +const parseTitleData = (data) => { + const parsedData = parseSPARQL(data) + if (!parsedData.length) return null + const [sampleData] = parsedData + return sampleData +} + +export default async function getSampleHeader ({ + query, + route, + options = requestOptions +}) { + const urlEncodedQuery = querySparqlEndpoint({ query, route }) + const res = await fetch(urlEncodedQuery, options) + const title = await res.json().then(parseTitleData) + return title +} diff --git a/app/src/pages/explorer/sample/services/getSampleImages.js b/app/src/pages/explorer/sample/services/getSampleImages.js new file mode 100644 index 00000000..1c11d38f --- /dev/null +++ b/app/src/pages/explorer/sample/services/getSampleImages.js @@ -0,0 +1,21 @@ +import { requestOptions, querySparqlEndpoint } from '../queries/settings' +import { parseSPARQL } from './damien' + +const parseImagesData = (data) => { + const parsedData = parseSPARQL(data) + const images = parsedData.map((item) => { + return { src: item.image, alt: item.sample } + }) + return images +} + +export default async function getImages ({ + query, + route, + options = requestOptions +}) { + const urlEncodedQuery = querySparqlEndpoint({ query, route }) + const res = await fetch(urlEncodedQuery, options) + const images = await res.json().then(parseImagesData) + return images +} From ecc14241dc90e075a47c8cc303b23432c2372adf Mon Sep 17 00:00:00 2001 From: Kevin Z - Razer Date: Tue, 25 Jan 2022 19:57:47 -0500 Subject: [PATCH 086/306] #67: add a unit test for sample components --- app/tests/unit/pages/explorer/Sample.spec.js | 168 +++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 app/tests/unit/pages/explorer/Sample.spec.js diff --git a/app/tests/unit/pages/explorer/Sample.spec.js b/app/tests/unit/pages/explorer/Sample.spec.js new file mode 100644 index 00000000..ec354712 --- /dev/null +++ b/app/tests/unit/pages/explorer/Sample.spec.js @@ -0,0 +1,168 @@ +import Sample from '@/pages/explorer/sample/Sample.vue' +import SampleHeader from '@/pages/explorer/sample/components/SampleHeader.vue' +import SampleImages from '@/pages/explorer/sample/components/SampleImages.vue' +import MaterialComponentsAndAttributes from '@/pages/explorer/sample/components/MaterialComponentsAndAttributes.vue' +import CuratedProcessingStepsParameters from '@/pages/explorer/sample/components/CuratedProcessingStepsParameters.vue' +import OtherSamples from '@/pages/explorer/sample/components/OtherSamples.vue' +import CuratedPropertiesOfNanocompositeSample from '@/pages/explorer/sample/components/CuratedPropertiesOfNanocompositeSample.vue' + +import VueRouter from 'vue-router' +import Vuex from 'vuex' +import { createLocalVue, mount, shallowMount } from '@vue/test-utils' + +// Data extracted from keyword l382-s2-huang-2019 + +const localVue = createLocalVue() +localVue.use(VueRouter) +localVue.use(Vuex) + +const store = new Vuex.Store() +const router = new VueRouter() + +describe('Sample.vue', () => { + let wrapper = null + + beforeAll(() => { + wrapper = mount(Sample, { + localVue, + store, + router + }) + }) + + it('mounts sample header component to Sample page', () => { + expect(wrapper.findComponent(SampleHeader)).toBeTruthy() + }) + + it('mounts sample images component to Sample page', () => { + expect(wrapper.findComponent(SampleImages)).toBeTruthy() + }) + + it('mounts material components and attributes component to Sample page', () => { + expect(wrapper.findComponent(MaterialComponentsAndAttributes)).toBeTruthy() + }) + + it('mounts curated processing steps parameters component to Sample page', () => { + expect( + wrapper.findComponent(CuratedProcessingStepsParameters) + ).toBeTruthy() + }) + + it('mounts other samples component to Sample page', () => { + expect(wrapper.findComponent(OtherSamples)).toBeTruthy() + }) + + it('mounts curated properties of nanocomposite sample component to Sample page', () => { + expect( + wrapper.findComponent(CuratedPropertiesOfNanocompositeSample) + ).toBeTruthy() + }) +}) + +describe('SampleHeader.vue', () => { + it('renders loading placeholder for sample header', async () => { + const wrapper = shallowMount(SampleHeader, { + localVue, + store, + router + }) + expect(wrapper.vm.$data.loading).toBe(true) + }) + + it('renders sample header', async () => { + const wrapper = shallowMount(SampleHeader, { + localVue, + store, + router + }) + // set sample data + await wrapper.setData({ + sample: { + DOI: '10.1021/acs.macromol.8b02071', + sample_label: 'gold nanoparticle in PS(40 kDa)-b-P4VP(5.6 kDa)' + }, + loading: false + }) + + expect( + wrapper.findComponent('[data-test="sample_label"]').text() + ).toContain('gold nanoparticle in PS(40 kDa)-b-P4VP(5.6 kDa)') + expect(wrapper.findComponent('[data-test="DOI"]').text()).toContain( + '10.1021/acs.macromol.8b02071' + ) + }) +}) + +describe('SampleImages.vue', () => { + it('renders loading placeholder for sample images', async () => { + const wrapper = shallowMount(SampleImages, { + localVue, + store, + router + }) + expect(wrapper.vm.$data.loading).toBe(true) + }) + + it('renders sample images', async () => { + const wrapper = shallowMount(SampleImages, { + localVue, + store, + router + }) + await wrapper.setData({ + images: [ + { + alt: 'http://materialsmine.org/sample/l382-s2-huang-2019', + src: 'https://qa.materialsmine.org/nmr/blob?id=5ed680a88d37da6c5907a969' + } + ], + loading: false + }) + // console.log( + // wrapper.findComponent('[data-test="sample_image"]').attributes() + // ); + expect( + wrapper.findComponent('[data-test="sample_image"]').html() + ).toContain( + 'http://materialsmine.org/sample/l382-s2-huang-2019' + ) + }) +}) + +describe('MaterialComponentsAndAttributes.vue', () => { + it('renders loading placeholder for material components', async () => { + const wrapper = shallowMount(MaterialComponentsAndAttributes, { + localVue, + store, + router + }) + expect(wrapper.vm.$data.loading).toBe(true) + }) + + it('renders material components', async () => { + const wrapper = shallowMount(MaterialComponentsAndAttributes, { + localVue, + store, + router + }) + await wrapper.setData({ + materialsData: [ + { + classType: 'Gold', + role: 'Filler', + materialProperties: [ + { + type: 'Density', + units: 'Gram per Cubic Centimeter', + value: 19.3 + } + ] + } + ], + loading: false + }) + expect( + wrapper.findComponent('[data-test="material-properties"]').text() + ).toContain('Gold') + }) +}) From 371a689a36954724b3482fbaf6461e57b72d1fb9 Mon Sep 17 00:00:00 2001 From: Rory Schadler Date: Fri, 28 Jan 2022 14:30:06 -0500 Subject: [PATCH 087/306] #80: Refactor unit test file structure to match --- app/tests/unit/pages/{ => nanomine}/howto.spec.js | 0 app/tests/unit/pages/{ => nanomine}/news.spec.js | 0 app/tests/unit/pages/{ => nanomine}/teams.spec.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename app/tests/unit/pages/{ => nanomine}/howto.spec.js (100%) rename app/tests/unit/pages/{ => nanomine}/news.spec.js (100%) rename app/tests/unit/pages/{ => nanomine}/teams.spec.js (100%) diff --git a/app/tests/unit/pages/howto.spec.js b/app/tests/unit/pages/nanomine/howto.spec.js similarity index 100% rename from app/tests/unit/pages/howto.spec.js rename to app/tests/unit/pages/nanomine/howto.spec.js diff --git a/app/tests/unit/pages/news.spec.js b/app/tests/unit/pages/nanomine/news.spec.js similarity index 100% rename from app/tests/unit/pages/news.spec.js rename to app/tests/unit/pages/nanomine/news.spec.js diff --git a/app/tests/unit/pages/teams.spec.js b/app/tests/unit/pages/nanomine/teams.spec.js similarity index 100% rename from app/tests/unit/pages/teams.spec.js rename to app/tests/unit/pages/nanomine/teams.spec.js From 801907bd8748fda6980f851d704a05334b418e96 Mon Sep 17 00:00:00 2001 From: Rory Schadler Date: Fri, 28 Jan 2022 15:17:08 -0500 Subject: [PATCH 088/306] #80: Remove erroneous reference to Vue Was using Vue.nextTick() instead of localVue.nextTick() when the test was running on an instance of LocalVue, not Vue --- app/tests/unit/pages/nanomine/howto.spec.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/tests/unit/pages/nanomine/howto.spec.js b/app/tests/unit/pages/nanomine/howto.spec.js index e7975ae1..58da8df9 100644 --- a/app/tests/unit/pages/nanomine/howto.spec.js +++ b/app/tests/unit/pages/nanomine/howto.spec.js @@ -1,5 +1,4 @@ import { mount, createLocalVue } from '@vue/test-utils' -import Vue from 'vue' import Vuex from 'vuex' import HowTo from '@/pages/nanomine/howTo/HowTo.vue' @@ -29,7 +28,7 @@ describe('HowTo.vue', () => { window.open.mockClear() const wrapper = mount(HowTo, { store, localVue }) - await Vue.nextTick() // wait for videos to load + await localVue.nextTick() // wait for videos to load const videoTitle = wrapper.find('.howto_item .howto_item-header') expect(videoTitle.exists()).toBeTruthy() @@ -47,7 +46,7 @@ describe('HowTo.vue', () => { window.open.mockClear() const wrapper = mount(HowTo, { store, localVue }) - await Vue.nextTick() // wait for videos to load + await localVue.nextTick() // wait for videos to load const videoTitle = wrapper.findAll('.howto_item .howto_item-header') @@ -64,7 +63,7 @@ describe('HowTo.vue', () => { window.open.mockClear() const wrapper = mount(HowTo, { store, localVue }) - await Vue.nextTick() // wait for videos to load + await localVue.nextTick() // wait for videos to load const videoIcons = wrapper.findAll('.material-icons') From c27e20837575ba97d6639a4d2f6544ea680a5586 Mon Sep 17 00:00:00 2001 From: tholulomo <94853475+tholulomo@users.noreply.github.com> Date: Sun, 30 Jan 2022 02:20:04 -0500 Subject: [PATCH 089/306] feat(#83): Nest routes based on category (#92) * #83: Mocks for jest testing * #83: unit test for metamine home page * #83: Test for nanomine home page * #83: Re-usable base component for nanomine pages * Re-usable base component for metamine pages * #83: Re-usable base component for data explorer * #83: Migrating metamine landing page, close #27 * #83: Moved drawer file into component/nanomine dir * #83: Add image assets for nanomine and metamine landing pages * #83: Code refactor, partial contribution to #80 * #83: Update to jest config specifically for mock images and docs * #83: Updates to style sheet for landing pages * #83: Refactor drawer for reusability - metamine & explorer * #83: Refactored Nanomine page header * #83: Refactor Nanomine page footer * #83: Refactor explorer page to use explorer base component * #83: Migrated Nanomine landing page, close #22 * #83: Refactored router * #83: Nested routes based on category * #83: Updated test due to refactored codes * #83: Testing explorer landing page * #83: Linter error fixes * #83: jest config update * #83: Updates to drawer component for import * #83: Separate handlers in jest config and updated test * #83: Added additional handler to jest and updated file imports * #83: Updated file mock * #83: Linter error fixes * #83: Renamed file to avoid conflict * #83: Drawer rename causing errors * #83: Re added drawer file --- app/jest.config.js | 3 +- app/src/assets/css/base/_reset.scss | 9 + app/src/assets/css/modules/_button.scss | 4 + app/src/assets/css/modules/_navigation.scss | 4 +- app/src/assets/css/modules/_pages.scss | 177 +++++++++++++++++- .../assets/css/modules/_resetvuematerial.scss | 26 ++- app/src/assets/css/modules/_section.scss | 5 +- app/src/assets/css/modules/_visualize.scss | 20 +- .../img/chartgifs/characterization-radial.gif | Bin 0 -> 1566928 bytes .../assets/img/chartgifs/crossfiltering.gif | Bin 0 -> 500897 bytes .../img/chartgifs/matrix-filler-combo.gif | Bin 0 -> 1179148 bytes .../assets/img/chartgifs/meta-analysis.gif | Bin 0 -> 682665 bytes .../assets/img/chartgifs/tensile-chart.gif | Bin 0 -> 298679 bytes app/src/assets/img/sponsors3.png | Bin 0 -> 326909 bytes app/src/components/Drawer.vue | 89 +++++++++ app/src/components/explorer/Drawer.vue | 26 --- .../{drawer.vue => nanomine/Drawers.vue} | 21 ++- app/src/components/nanomine/PageFooter.vue | 4 - app/src/components/nanomine/PageHeader.vue | 29 +-- app/src/pages/About.vue | 14 -- .../explorer/{basesample.vue => Base.vue} | 10 +- app/src/pages/explorer/Home.vue | 86 ++++----- app/src/pages/metamine/Base.vue | 50 +++++ app/src/pages/metamine/Home.vue | 130 +++++++++++++ app/src/pages/metamine/Home/Home.vue | 29 --- app/src/pages/nanomine/Base.vue | 23 +++ app/src/pages/nanomine/Home/Home.vue | 145 +++++++++++--- app/src/router/index.js | 47 ++++- app/src/router/module/explorer.js | 2 +- app/src/router/module/metamine.js | 4 +- app/src/router/module/nanomine.js | 18 +- app/tests/jest/__mocks__/fileMock.js | 7 + app/tests/jest/script/test-setup.js | 2 + .../components/nanomine/pagefooter.spec.js | 5 +- .../components/nanomine/pageheader.spec.js | 8 +- app/tests/unit/pages/about.spec.js | 23 --- app/tests/unit/pages/explorer/Home.spec.js | 3 +- app/tests/unit/pages/metamine/home.spec.js | 31 +++ app/tests/unit/pages/nanomine/home.spec.js | 43 +++++ .../unit/pages/{ => nanomine}/howto.spec.js | 0 .../unit/pages/{ => nanomine}/news.spec.js | 0 .../unit/pages/{ => nanomine}/teams.spec.js | 0 42 files changed, 853 insertions(+), 244 deletions(-) create mode 100644 app/src/assets/img/chartgifs/characterization-radial.gif create mode 100644 app/src/assets/img/chartgifs/crossfiltering.gif create mode 100644 app/src/assets/img/chartgifs/matrix-filler-combo.gif create mode 100644 app/src/assets/img/chartgifs/meta-analysis.gif create mode 100644 app/src/assets/img/chartgifs/tensile-chart.gif create mode 100644 app/src/assets/img/sponsors3.png create mode 100644 app/src/components/Drawer.vue delete mode 100644 app/src/components/explorer/Drawer.vue rename app/src/components/{drawer.vue => nanomine/Drawers.vue} (83%) delete mode 100644 app/src/pages/About.vue rename app/src/pages/explorer/{basesample.vue => Base.vue} (79%) create mode 100644 app/src/pages/metamine/Base.vue create mode 100644 app/src/pages/metamine/Home.vue delete mode 100644 app/src/pages/metamine/Home/Home.vue create mode 100644 app/src/pages/nanomine/Base.vue create mode 100644 app/tests/jest/__mocks__/fileMock.js create mode 100644 app/tests/jest/script/test-setup.js delete mode 100644 app/tests/unit/pages/about.spec.js create mode 100644 app/tests/unit/pages/metamine/home.spec.js create mode 100644 app/tests/unit/pages/nanomine/home.spec.js rename app/tests/unit/pages/{ => nanomine}/howto.spec.js (100%) rename app/tests/unit/pages/{ => nanomine}/news.spec.js (100%) rename app/tests/unit/pages/{ => nanomine}/teams.spec.js (100%) diff --git a/app/jest.config.js b/app/jest.config.js index 243072d4..f4963d6e 100644 --- a/app/jest.config.js +++ b/app/jest.config.js @@ -1,7 +1,8 @@ module.exports = { preset: '@vue/cli-plugin-unit-jest', transform: { - '^.+\\.vue$': 'vue-jest' + '^.+\\.vue$': 'vue-jest', + '\\.(gif)$': '/tests/jest/__mocks__/fileMock.js' }, snapshotSerializers: [ '/node_modules/jest-serializer-vue' diff --git a/app/src/assets/css/base/_reset.scss b/app/src/assets/css/base/_reset.scss index 397c0bc7..5eec2270 100644 --- a/app/src/assets/css/base/_reset.scss +++ b/app/src/assets/css/base/_reset.scss @@ -40,4 +40,13 @@ img { background-color: $tertiary !important; color: $primary !important; text-shadow: none; +} + +#nanomine_app, +#metamine_app { + font-family: 'Avenir', Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: #2c3e50; + background-color: white; } \ No newline at end of file diff --git a/app/src/assets/css/modules/_button.scss b/app/src/assets/css/modules/_button.scss index 5d336fc3..955559d4 100644 --- a/app/src/assets/css/modules/_button.scss +++ b/app/src/assets/css/modules/_button.scss @@ -1,3 +1,4 @@ +a.btn, .btn { &, &:link, @@ -11,6 +12,7 @@ position: relative; font-size: $medium-size; font-weight: bold; + text-decoration: none !important; //Change for the '] } beforeEach(() => { wrapper = createWrapper(Dialog, { slots }, false) @@ -27,10 +29,24 @@ describe('@/components/Dialog.vue', () => { expect(wrapper.props('active')).toBe(testProps.active) }) - it('contains slot', () => { + it('contains content slot', () => { expect.assertions(2) const slotExist = wrapper.find('p') expect(slotExist.exists()).toBe(true) expect(slotExist.text()).toBe('Testing') }) + + it('contains title slot', () => { + expect.assertions(2) + const slotExist = wrapper.find('header') + expect(slotExist.exists()).toBe(true) + expect(slotExist.text()).toBe('Test Title') + }) + + it('contains actions slot', () => { + expect.assertions(2) + const slotExist = wrapper.find('button') + expect(slotExist.exists()).toBe(true) + expect(slotExist.text()).toBe('Test Close') + }) }) From 3366a4c843f6a68f3757bf0dc908a4dea77e6680 Mon Sep 17 00:00:00 2001 From: Kevin Z - Razer Date: Wed, 9 Feb 2022 19:42:27 -0500 Subject: [PATCH 121/306] #67: fix router issue --- app/src/router/module/explorer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/router/module/explorer.js b/app/src/router/module/explorer.js index af1cb171..d38d7515 100644 --- a/app/src/router/module/explorer.js +++ b/app/src/router/module/explorer.js @@ -6,8 +6,8 @@ const explorerRoutes = [ meta: { requiresAuth: false } }, { - path: '/explorer/sample/:label', - name: 'Sample View', + path: 'sample/:label', + name: 'SampleView', component: () => import('@/pages/explorer/Sample.vue'), meta: { requiresAuth: false } } From 7e19d1445d644db25b33c3cd88c29ba7fc091ae4 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Thu, 10 Feb 2022 03:22:06 -0800 Subject: [PATCH 122/306] #65: Modify unit tests to include dialog box buttons --- .../explorer/vega/view/vega-view-script.js | 19 ++--------------- .../pages/explorer/vega/view/vega-view.html | 14 ++++++------- .../unit/pages/explorer/VegaView.spec.js | 21 +++++++++++++++---- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/app/src/pages/explorer/vega/view/vega-view-script.js b/app/src/pages/explorer/vega/view/vega-view-script.js index fed29932..b253a904 100644 --- a/app/src/pages/explorer/vega/view/vega-view-script.js +++ b/app/src/pages/explorer/vega/view/vega-view-script.js @@ -75,25 +75,10 @@ export default { }, editChart () { }, - shareChart () { - this.setDialogData('Share chart', 'share') - this.toggleDialogBox() - }, - viewQuery () { - this.setDialogData('Chart Query', 'query') - this.toggleDialogBox() - }, - viewTable () { - this.setDialogData('Chart Data Table', 'data') - this.toggleDialogBox() - }, - viewVegaSpec () { - this.setDialogData('Chart Vega Spec', 'vega') - this.toggleDialogBox() - }, - setDialogData (title, type) { + renderDialog (title, type) { this.dialog.title = title this.dialog.type = type + this.toggleDialogBox() }, slugify (args) { // return Slug(args) diff --git a/app/src/pages/explorer/vega/view/vega-view.html b/app/src/pages/explorer/vega/view/vega-view.html index e08a555d..cce09e9a 100644 --- a/app/src/pages/explorer/vega/view/vega-view.html +++ b/app/src/pages/explorer/vega/view/vega-view.html @@ -1,40 +1,40 @@
- + Go Back arrow_back - + Share Chart share
- + Preview Chart Query preview
- + View Data as Table table_view
- + Preview Chart Spec integration_instructions
- + View Data in Voyager dynamic_form
- + Edit Chart edit diff --git a/app/tests/unit/pages/explorer/VegaView.spec.js b/app/tests/unit/pages/explorer/VegaView.spec.js index 14a2384e..ec86a9d1 100644 --- a/app/tests/unit/pages/explorer/VegaView.spec.js +++ b/app/tests/unit/pages/explorer/VegaView.spec.js @@ -1,4 +1,6 @@ import createWrapper from '../../../jest/script/wrapper' +// import { enableAutoDestroy } from '@vue/test-utils' + import VegaView from '@/pages/explorer/vega/view/VegaView.vue' import { getDefaultChart, loadChart, buildSparqlSpec } from '@/modules/vega-chart' import { querySparql } from '@/modules/sparql' @@ -30,7 +32,7 @@ const testChart = { } } }, - query: '', + query: 'Test Query', title: 'Test Title', description: 'Test chart description' } @@ -50,13 +52,24 @@ describe('VegaView.vue', () => { expect(wrapper.text()).toContain('Test chart description') }) + it('renders chart query dialog button', () => { + expect(wrapper.findComponent('#chartQueryBtn').exists()).toBeTruthy() + }) + + it('renders vega spec dialog button', () => { + expect(wrapper.findComponent('#vegaSpecBtn').exists()).toBeTruthy() + }) + + it('hides chart data dialog button if no data', () => { + expect(wrapper.findComponent('#dataTableBtn').exists()).toBeFalsy() + }) + it('opens share dialog on click', async () => { expect.assertions(2) - const shareButton = await wrapper.findAllComponents('.md-button').at(1) - const spy = jest.spyOn(wrapper.vm, 'shareChart') + const shareButton = await wrapper.findComponent('#shareChartBtn') + const spy = jest.spyOn(wrapper.vm, 'renderDialog') await shareButton.trigger('click') expect(spy).toHaveBeenCalled() expect(wrapper.findComponent('.dialog-box').exists()).toBeTruthy() - jest.restoreAllMocks() }) }) From 1f72af903103014a4743dddc000d7afae36d1ac9 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Thu, 10 Feb 2022 03:23:08 -0800 Subject: [PATCH 123/306] #65: Fix linter errors --- app/tests/unit/pages/explorer/VegaView.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/tests/unit/pages/explorer/VegaView.spec.js b/app/tests/unit/pages/explorer/VegaView.spec.js index ec86a9d1..8313f6eb 100644 --- a/app/tests/unit/pages/explorer/VegaView.spec.js +++ b/app/tests/unit/pages/explorer/VegaView.spec.js @@ -59,7 +59,7 @@ describe('VegaView.vue', () => { it('renders vega spec dialog button', () => { expect(wrapper.findComponent('#vegaSpecBtn').exists()).toBeTruthy() }) - + it('hides chart data dialog button if no data', () => { expect(wrapper.findComponent('#dataTableBtn').exists()).toBeFalsy() }) From f27267269133e2c26e7f813f2b7bf5ad6efe7050 Mon Sep 17 00:00:00 2001 From: tholulomo <94853475+tholulomo@users.noreply.github.com> Date: Thu, 10 Feb 2022 19:47:01 -0500 Subject: [PATCH 124/306] feat(#85): Create logger service - restful (#107) * #85: Updated gitignore file to ignore log files * #85: Added winston to package.json * #85: Moved all global middleware services into a single file * #84: Created a logger middleware service * #85: Imported all global middleware from globalmiddleware.js * #85: Linter fixes --- .gitignore | 2 + resfulservice/package.json | 3 +- .../src/middlewares/globalMiddleware.js | 34 ++++++++++++++ .../src/middlewares/loggerService.js | 46 +++++++++++++++++++ resfulservice/src/server.js | 20 +++----- 5 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 resfulservice/src/middlewares/globalMiddleware.js create mode 100644 resfulservice/src/middlewares/loggerService.js diff --git a/.gitignore b/.gitignore index 7a793f54..55c95df3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,6 @@ package-lock.json # Local DBs **/**/db +# Rest +**/**/*.log diff --git a/resfulservice/package.json b/resfulservice/package.json index c8aa0c39..3ec3513e 100644 --- a/resfulservice/package.json +++ b/resfulservice/package.json @@ -24,7 +24,8 @@ "multer": "^1.4.4", "node-schedule": "^2.1.0", "nodemailer": "^6.7.2", - "swagger-ui-express": "^4.2.0" + "swagger-ui-express": "^4.2.0", + "winston": "^3.5.1" }, "scripts": { "start": "nodemon src/server.js", diff --git a/resfulservice/src/middlewares/globalMiddleware.js b/resfulservice/src/middlewares/globalMiddleware.js new file mode 100644 index 00000000..95f13cb3 --- /dev/null +++ b/resfulservice/src/middlewares/globalMiddleware.js @@ -0,0 +1,34 @@ +const bodyParser = require('body-parser'); +const acceptedHeaders = require('./accept'); +const getEnv = require('./parseEnv'); +const { fileMgr, fileServer } = require('./fileStorage'); +const mmGraphQL = require('../graphql'); +const { logParser, mmLogger } = require('./loggerService'); + +const log = mmLogger(); + +/** + * globalMiddleWare - this function that instantiate all + * global middleware services for the REST API + * @param {*} app Express app object + */ +const globalMiddleWare = (app) => { + app.use(bodyParser.json()); + app.use(fileMgr); + app.use('/mm_fils', fileServer); + app.use(acceptedHeaders); + app.use('/graphql', mmGraphQL); + app.use(getEnv); + app.use( + (req, res, next) => logParser(log, req, next) + ); +}; + +/** + * This file imports all GLOBAL middleware services & + * exports them to the server.js file. + */ +module.exports = { + log, + globalMiddleWare +}; diff --git a/resfulservice/src/middlewares/loggerService.js b/resfulservice/src/middlewares/loggerService.js new file mode 100644 index 00000000..a107e296 --- /dev/null +++ b/resfulservice/src/middlewares/loggerService.js @@ -0,0 +1,46 @@ +const { createLogger, format, transports } = require('winston'); +const { combine, timestamp, label, printf, prettyPrint } = format; +const env = process.env; + +const logFormat = printf(({ level, message, label, timestamp }) => { + return `${timestamp} [${label}] ${level}: ${message}`; +}); + +const transport = { + file: new (transports.File)({ + filename: env?.logfile || 'rest_api.log', + level: 'debug', + maxfiles: 10, + maxsize: 52428800 + }) +}; + +exports.mmLogger = () => { + const logger = createLogger({ + levels: { + emerg: 0, + alert: 1, + crit: 2, + error: 3, + warning: 4, + notice: 5, + info: 6, + debug: 7 + }, + format: combine( + label({ label: 'rest-api' }), + timestamp(), + prettyPrint(), + logFormat + ), + transports: [ + transport.file + ] + }); + return logger; +}; + +exports.logParser = (logger, req, next) => { + req.logger = logger; + next(); +}; diff --git a/resfulservice/src/server.js b/resfulservice/src/server.js index e6c564c7..f037951d 100644 --- a/resfulservice/src/server.js +++ b/resfulservice/src/server.js @@ -1,21 +1,10 @@ const express = require('express'); const mongoose = require('mongoose'); -const bodyParser = require('body-parser'); -const acceptedHeaders = require('./middlewares/accept'); -const getEnv = require('./middlewares/parseEnv'); -const { fileMgr, fileServer } = require('./middlewares/fileStorage'); -const mmGraphQL = require('./graphql'); -// const testRoutes = require('./routes/test'); +const { globalMiddleWare, log } = require('./middlewares/globalMiddleware'); const env = process.env; const app = express(); - -app.use(bodyParser.json()); -app.use(fileMgr); -app.use('/mm_fils', fileServer); -app.use(acceptedHeaders); -app.use('/graphql', mmGraphQL); -app.use(getEnv); +globalMiddleWare(app); app.use((error, req, res, next) => { console.log(error); @@ -29,5 +18,8 @@ mongoose .connect(`mongodb://${env.DB_USERNAME}:${env.DB_PASSWORD}@${env.MONGO_ADDRESS}:${env.MONGO_PORT}/${env.MM_DB}`, { useNewUrlParser: true, useUnifiedTopology: true }) - .then(app.listen(process.env.PORT || 3000)) + .then(() => { + log.info('Rest server starting up...'); + app.listen(process.env.PORT || 3000); + }) .catch(err => console.log(err)); From b2d6c1d67191b5970f9eb19a6693ce2d7c46b79a Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Thu, 10 Feb 2022 17:26:16 -0800 Subject: [PATCH 125/306] #65: Update default vega-lite schema to v5 --- app/src/modules/vega-chart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/modules/vega-chart.js b/app/src/modules/vega-chart.js index 5516b1ee..9c9934a9 100644 --- a/app/src/modules/vega-chart.js +++ b/app/src/modules/vega-chart.js @@ -15,7 +15,7 @@ LIMIT 10 `.trim() const defaultSpec = { - $schema: 'https://vega.github.io/schema/vega-lite/v4.json', + $schema: 'https://vega.github.io/schema/vega-lite/v5.json', mark: 'bar', encoding: { x: { From 413b67543e32abdae44a2640903a6bd86c4cd750 Mon Sep 17 00:00:00 2001 From: Jamie McCusker Date: Fri, 11 Feb 2022 17:09:12 -0500 Subject: [PATCH 126/306] Added slightly different initialization setup for fuseki. --- docker-compose.yml | 28 +++++++++++++++++++--------- mockDB/fuseki-init.sh | 1 + whyis/Dockerfile | 4 ++-- whyis/Dockerfile.dev | 4 +--- whyis/docker-compose.yml | 10 ++++++---- whyis/materialsmine/system.conf | 8 ++++---- whyis/materialsmine/whyis.conf | 5 +---- 7 files changed, 34 insertions(+), 26 deletions(-) create mode 100644 mockDB/fuseki-init.sh diff --git a/docker-compose.yml b/docker-compose.yml index cb152a81..e0a15fa4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -58,36 +58,46 @@ services: depends_on: - redis - fuseki + volumes: + - ./mockDB/fuseki:/app/run + - ./whyis/materialsmine:/app command: /opt/venv/bin/celery -A wsgi.celery worker -l INFO -c 4 --uid=nobody --gid=nogroup environment: - CHOKIDAR_USEPOLLING=true - build: ./whyis + build: whyis celerybeat: depends_on: - redis - fuseki + volumes: + - ./mockDB/fuseki:/app/run + - ./whyis/materialsmine:/app command: /opt/venv/bin/celery -A wsgi.celery beat -l INFO --uid=nobody --gid=nogroup environment: - CHOKIDAR_USEPOLLING=true - build: ./whyis + build: whyis fuseki: - command: /opt/venv/bin/whyis fuseki # ; /opt/venv/bin/fuseki-server --mem /ds + command: /opt/venv/bin/fuseki-server --mem /ds #/opt/venv/bin/whyis fuseki environment: - CHOKIDAR_USEPOLLING=true - build: ./whyis - ports: - - '3030:3030' + build: whyis +# ports: +# - '3030:3030' volumes: - - ./mockDB/fuseki:/app/run + - ./materialsmine:/app + - ./whyis/materialsmine:/app whyis: depends_on: - redis - fuseki stdin_open: true - command: /opt/venv/bin/gunicorn wsgi:application --workers ${WEB_CONCURRENCY:-4} --timeout 90 -b :8000 + command: /opt/venv/bin/gunicorn wsgi:application --workers ${WEB_CONCURRENCY:-8} --timeout 90 -b :8000 environment: - CHOKIDAR_USEPOLLING=true - build: ./whyis + build: whyis + volumes: + - ./whyis/materialsmine:/app + - ./mockDB/fuseki:/app/run ports: - '8000:8000' volumes: diff --git a/mockDB/fuseki-init.sh b/mockDB/fuseki-init.sh new file mode 100644 index 00000000..6cb21547 --- /dev/null +++ b/mockDB/fuseki-init.sh @@ -0,0 +1 @@ +whyis init diff --git a/whyis/Dockerfile b/whyis/Dockerfile index 6fd76672..25fd9ec0 100644 --- a/whyis/Dockerfile +++ b/whyis/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y \ default-jdk-headless RUN python3.8 -m venv /opt/venv RUN /opt/venv/bin/pip install requests>=2.27.1 wheel gunicorn -RUN /opt/venv/bin/pip install whyis==2.0a7 whyis-unit-converter==0.0.2 -COPY /materialsmine /app +RUN /opt/venv/bin/pip install whyis==2.0b1 whyis-unit-converter==0.0.2 +COPY ./materialsmine /app WORKDIR '/app' CMD [ "/bin/bash" ] diff --git a/whyis/Dockerfile.dev b/whyis/Dockerfile.dev index fccb9b6f..f0dbe426 100644 --- a/whyis/Dockerfile.dev +++ b/whyis/Dockerfile.dev @@ -11,8 +11,6 @@ RUN apt-get update && apt-get install -y \ default-jdk-headless RUN python3.8 -m venv /opt/venv RUN /opt/venv/bin/pip install requests>=2.27.1 wheel gunicorn -COPY ./whyis /opt/whyis -RUN /opt/venv/bin/pip install -e /opt/whyis -RUN /opt/venv/bin/pip install whyis-unit-converter==0.0.2 +RUN /opt/venv/bin/pip install whyis==2.0b1 whyis-unit-converter==0.0.2 WORKDIR '/app' CMD [ "/bin/bash" ] diff --git a/whyis/docker-compose.yml b/whyis/docker-compose.yml index 1bc0f1b7..63de5280 100644 --- a/whyis/docker-compose.yml +++ b/whyis/docker-compose.yml @@ -12,7 +12,7 @@ services: command: /opt/venv/bin/celery -A wsgi.celery worker -l INFO -c 4 --uid=nobody --gid=nogroup volumes: - ./materialsmine:/app - - ./whyis:/opt/whyis + - ./mockDB/fuseki:/app/run environment: - CHOKIDAR_USEPOLLING=true build: @@ -25,7 +25,7 @@ services: command: /opt/venv/bin/celery -A wsgi.celery beat -l INFO --uid=nobody --gid=nogroup volumes: - ./materialsmine:/app - - ./whyis:/opt/whyis + - ./mockDB/fuseki:/app/run environment: - CHOKIDAR_USEPOLLING=true build: @@ -41,13 +41,14 @@ services: ports: - '3030:3030' volumes: + - ./materialsmine:/app - ./mockDB/fuseki:/app/run whyis: depends_on: - redis - fuseki stdin_open: true - command: /bin/bash #/opt/venv/bin/gunicorn wsgi:application --workers ${WEB_CONCURRENCY:-4} --timeout 90 -b :8000 + command: /opt/venv/bin/gunicorn wsgi:application --workers ${WEB_CONCURRENCY:-4} --timeout 90 -b :8000 environment: - CHOKIDAR_USEPOLLING=true build: @@ -55,6 +56,7 @@ services: context: . volumes: - ./materialsmine:/app - - ./whyis:/opt/whyis + - ./mockDB/fuseki:/app/run ports: + - '8000:8000' - '5000:5000' diff --git a/whyis/materialsmine/system.conf b/whyis/materialsmine/system.conf index 97de1e10..63bd5162 100644 --- a/whyis/materialsmine/system.conf +++ b/whyis/materialsmine/system.conf @@ -10,9 +10,9 @@ if authenticator_secret: print("Adding JWT authenticator") authenticator_config.append(JWTAuthenticator(key=authenticator_secret)) -AUTHENTICATORS = authenticator_config +APPLICATION_ROOT= '/whyis/' -DEBUG=False +AUTHENTICATORS = authenticator_config # LOGGING LOGGER_NAME = "whyis_log" @@ -31,9 +31,9 @@ PERMANENT_SESSION_LIFETIME = timedelta(days=7) ## MAIL_PASSWORD = '' ## DEFAULT_MAIL_SENDER = "Whyis Admin " EMBEDDED_FUSEKI = False -ADMIN_ENDPOINT = 'http://fuseki:3030/admin/sparql' +ADMIN_ENDPOINT = 'http://fuseki:3030/admin' -KNOWLEDGE_ENDPOINT = 'http://fuseki:3030/knowledge/sparql' +KNOWLEDGE_ENDPOINT = 'http://fuseki:3030/knowledge' EMBEDDED_CELERY = False CELERY_BROKER_URL = 'redis://redis:6379/0' diff --git a/whyis/materialsmine/whyis.conf b/whyis/materialsmine/whyis.conf index 9b65557c..24b6c7b8 100644 --- a/whyis/materialsmine/whyis.conf +++ b/whyis/materialsmine/whyis.conf @@ -21,10 +21,7 @@ VOCAB_FILE = "vocab.ttl" ## MAIL_USERNAME = '', ## MAIL_PASSWORD = '', ## DEFAULT_MAIL_SENDER = "Whyis ", -DEFAULT_ANONYMOUS_READ = True -WHYIS_TEMPLATE_DIR = 'templates' -WHYIS_CDN_DIR = 'static' -EXPLAIN_TEMPLATE_LOADING = True + NAMESPACES = [ importer.LinkedData( prefix = LOD_PREFIX+'/dcat/', From 0a3d23701d334d15f4545d71adb7ed6c5a691d60 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Fri, 11 Feb 2022 16:25:05 -0800 Subject: [PATCH 127/306] #109: Add min-width prop to dialog box --- app/src/assets/css/modules/_utility.scss | 18 ++++++++++++++++++ app/src/components/Dialog.vue | 15 ++++++++++++++- .../explorer/vega/view/vega-view-script.js | 9 ++++++--- .../pages/explorer/vega/view/vega-view.html | 6 +++--- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/app/src/assets/css/modules/_utility.scss b/app/src/assets/css/modules/_utility.scss index 5ccc8d5c..27c962db 100644 --- a/app/src/assets/css/modules/_utility.scss +++ b/app/src/assets/css/modules/_utility.scss @@ -173,6 +173,24 @@ .md-dialog-container{ overflow: scroll !important; } + &_size { + &-sm { + .md-dialog-container{ + min-width: 40vh !important; + } + } + &-md { + .md-dialog-container{ + min-width: 60vh !important; + } + } + &-lg { + .md-dialog-container{ + min-width: 80vh !important; + } + } + } + &_header { background-color: $secondary-mid !important; padding: 1rem 1.5rem !important; diff --git a/app/src/components/Dialog.vue b/app/src/components/Dialog.vue index 166db7ce..ca94d277 100644 --- a/app/src/components/Dialog.vue +++ b/app/src/components/Dialog.vue @@ -1,6 +1,6 @@ diff --git a/app/src/pages/explorer/sample/sample.html b/app/src/pages/explorer/sample/sample.html new file mode 100644 index 00000000..c1571f1a --- /dev/null +++ b/app/src/pages/explorer/sample/sample.html @@ -0,0 +1,58 @@ +
+ +
+
+

{{ this.$route.params.label }}

+ {{ header.sample_label }} + {{ header.process_label }} +
DOI: {{ header.DOI }}
+
+
+

Material Components and Attributes

+
    +
  • Class: {{ material.class }}
  • +
  • Role: {{ material.role }}
  • +
  • + {{ property.type }}: + {{ property.value }} + {{ property.units }} +
  • +
+
+
+

Sample Images

+ + +
+
+

Curated Properties of Nanocomposite Sample

+
Scalar attributes:
+
    +
  • + {{ property.type }}: + {{ property.value }} + {{ property.units }} +
  • +
+
+
+

Curated Processing Steps and Parameters

+
Class: {{ processLabel }}
+
Processing Steps:
+
    +
  • + {{ step.parameterLabel }} + {{ step.description }} +
  • +
+
+
+

Other Samples from this Research Article

+
+ + {{ link }} + +
+
+
+
diff --git a/app/src/pages/explorer/sample/sample.js b/app/src/pages/explorer/sample/sample.js new file mode 100644 index 00000000..a75acf79 --- /dev/null +++ b/app/src/pages/explorer/sample/sample.js @@ -0,0 +1,169 @@ +import { querySparql, parseSPARQL } from '@/modules/sparql' +import sampleQueries from '@/modules/queries/sampleQueries' +import Spinner from '@/components/Spinner' + +export default { + name: 'SampleView', + components: { + Spinner + }, + data () { + return { + header: null, + materialComponents: null, + curatedProperties: null, + processLabel: null, + processingSteps: null, + sampleImages: null, + otherSamples: null, + loading: false + } + }, + methods: { + async fetchData (query) { + const sampleId = this.$route.params.label + return await querySparql(query(sampleId)) + }, + parseHeader (data) { + const parsedData = parseSPARQL(data) + if (!parsedData.length) return null + const [sampleData] = parsedData + return sampleData + }, + parseOtherSamples (data) { + const parsedData = parseSPARQL(data) + if (!parsedData.length) return null + const links = parsedData.map(({ sample }) => sample.split('/').pop()) + return links + }, + parseProcessLabel (data) { + const parsedData = parseSPARQL(data) + if (!parsedData.length) return null + const [processLabelObject] = parsedData + const { process_label: processLabel } = processLabelObject + return processLabel + }, + parseMaterialData (data) { + const parsedData = parseSPARQL(data) + if (!parsedData.length) return null + const seen = new Set() + const filteredArr = parsedData + .filter((item) => { + const duplicate = seen.has(item.std_name) + seen.add(item.std_name) + return !duplicate + }) + .map((item) => { + return { + class: item.std_name, + role: item.role + } + }) + + filteredArr.forEach((element) => { + const materialProperties = parsedData + .filter((item) => item.std_name === element.class) + .map((item) => { + const { attrUnits, attrValue: value, attrType } = item + const units = attrUnits || '' + const type = attrType + .split('/') + .pop() + .match(/[A-Z][a-z]+|[0-9]+/g) + .join(' ') + return { + type, + units, + value + } + }) + element.materialProperties = materialProperties + }) + return filteredArr + }, + parseCuratedProperties (data) { + const parseData = parseSPARQL(data) + if (!parseData.length) return null + const curatedProperties = parseData.map((property) => { + const { AttrType, value, Units: units } = property + const type = AttrType.split('/') + .pop() + .match(/[A-Z][a-z]+|[0-9]+/g) + .join(' ') + return { + type, + units, + value + } + }) + return curatedProperties + }, + parseProcessingSteps (data) { + const parsedData = parseSPARQL(data) + if (!parsedData.length) return null + const steps = parsedData.map( + ({ param_label: parameterLabel, Descr: description }) => { + return { parameterLabel, description } + } + ) + return steps + }, + parseSampleImages (data) { + const parsedData = parseSPARQL(data) + if (!parsedData.length) return null + const images = parsedData.map((item) => { + return { src: item.image, alt: item.sample } + }) + return images + }, + async fetchSamplePageData () { + this.loading = true + // es 11 + await Promise.allSettled([ + this.fetchData(sampleQueries.materialComponents), + this.fetchData(sampleQueries.curatedProperties), + this.fetchData(sampleQueries.processLabel), + this.fetchData(sampleQueries.processingSteps), + this.fetchData(sampleQueries.sampleImages), + this.fetchData(sampleQueries.otherSamples), + this.fetchData(sampleQueries.header) + ]) + .then((res) => { + console.log(res) + const data = res.map((promise) => { + if (promise.status === 'fulfilled') return promise.value + console.error(promise.reason) + return null + }) + const [ + materialComponents, + curatedProperties, + processLabel, + processingSteps, + sampleImages, + otherSamples, + header + ] = data + this.materialComponents = this.parseMaterialData(materialComponents) + this.curatedProperties = + this.parseCuratedProperties(curatedProperties) + this.processLabel = this.parseProcessLabel(processLabel) + this.processingSteps = this.parseProcessingSteps(processingSteps) + this.sampleImages = this.parseSampleImages(sampleImages) + this.otherSamples = this.parseOtherSamples(otherSamples) + this.header = this.parseHeader(header) + this.loading = false + }) + .catch((e) => console.error(e)) + } + }, + + watch: { + $route: 'fetchSamplePageData' + }, + created () { + console.log('before') + this.fetchSamplePageData() + console.log('after') + } +} diff --git a/app/src/router/module/explorer.js b/app/src/router/module/explorer.js index 6564e97a..55731bbd 100644 --- a/app/src/router/module/explorer.js +++ b/app/src/router/module/explorer.js @@ -46,7 +46,7 @@ const explorerRoutes = [ { path: 'sample/:label', name: 'SampleView', - component: () => import('@/pages/explorer/Sample.vue'), + component: () => import('@/pages/explorer/sample/Sample.vue'), meta: { requiresAuth: false } } ] diff --git a/app/tests/unit/pages/explorer/Sample.spec.js b/app/tests/unit/pages/explorer/Sample.spec.js index efa3059f..93214c6c 100644 --- a/app/tests/unit/pages/explorer/Sample.spec.js +++ b/app/tests/unit/pages/explorer/Sample.spec.js @@ -1,168 +1,10 @@ -import Sample from '@/pages/explorer/Sample.vue' -import SampleHeader from '@/components/explorer/SampleHeader.vue' -import SampleImages from '@/components/explorer/SampleImages.vue' -import MaterialComponentsAndAttributes from '@/components/explorer/MaterialComponentsAndAttributes.vue' -import CuratedProcessingStepsParameters from '@/components/explorer/CuratedProcessingStepsParameters.vue' -import OtherSamples from '@/components/explorer/OtherSamples.vue' -import CuratedPropertiesOfNanocompositeSample from '@/components/explorer/CuratedPropertiesOfNanocompositeSample.vue' +// import Sample from "@/pages/explorer/sample/Sample.vue"; +// import createWrapper from "../../../jest/script/wrapper"; -import VueRouter from 'vue-router' -import Vuex from 'vuex' -import { createLocalVue, mount, shallowMount } from '@vue/test-utils' - -// Data extracted from keyword l382-s2-huang-2019 - -const localVue = createLocalVue() -localVue.use(VueRouter) -localVue.use(Vuex) - -const store = new Vuex.Store() -const router = new VueRouter() +HTMLCanvasElement.prototype.getContext = () => {} describe('Sample.vue', () => { - let wrapper = null - - beforeAll(() => { - wrapper = mount(Sample, { - localVue, - store, - router - }) - }) - - it('mounts sample header component to Sample page', () => { - expect(wrapper.findComponent(SampleHeader)).toBeTruthy() - }) - - it('mounts sample images component to Sample page', () => { - expect(wrapper.findComponent(SampleImages)).toBeTruthy() - }) - - it('mounts material components and attributes component to Sample page', () => { - expect(wrapper.findComponent(MaterialComponentsAndAttributes)).toBeTruthy() - }) - - it('mounts curated processing steps parameters component to Sample page', () => { - expect( - wrapper.findComponent(CuratedProcessingStepsParameters) - ).toBeTruthy() - }) - - it('mounts other samples component to Sample page', () => { - expect(wrapper.findComponent(OtherSamples)).toBeTruthy() - }) - - it('mounts curated properties of nanocomposite sample component to Sample page', () => { - expect( - wrapper.findComponent(CuratedPropertiesOfNanocompositeSample) - ).toBeTruthy() - }) -}) - -describe('SampleHeader.vue', () => { - it('renders loading placeholder for sample header', async () => { - const wrapper = shallowMount(SampleHeader, { - localVue, - store, - router - }) - expect(wrapper.vm.$data.loading).toBe(true) - }) - - it('renders sample header', async () => { - const wrapper = shallowMount(SampleHeader, { - localVue, - store, - router - }) - // set sample data - await wrapper.setData({ - sample: { - DOI: '10.1021/acs.macromol.8b02071', - sample_label: 'gold nanoparticle in PS(40 kDa)-b-P4VP(5.6 kDa)' - }, - loading: false - }) - - expect( - wrapper.findComponent('[data-test="sample_label"]').text() - ).toContain('gold nanoparticle in PS(40 kDa)-b-P4VP(5.6 kDa)') - expect(wrapper.findComponent('[data-test="DOI"]').text()).toContain( - '10.1021/acs.macromol.8b02071' - ) - }) -}) - -describe('SampleImages.vue', () => { - it('renders loading placeholder for sample images', async () => { - const wrapper = shallowMount(SampleImages, { - localVue, - store, - router - }) - expect(wrapper.vm.$data.loading).toBe(true) - }) - - it('renders sample images', async () => { - const wrapper = shallowMount(SampleImages, { - localVue, - store, - router - }) - await wrapper.setData({ - images: [ - { - alt: 'http://materialsmine.org/sample/l382-s2-huang-2019', - src: 'https://qa.materialsmine.org/nmr/blob?id=5ed680a88d37da6c5907a969' - } - ], - loading: false - }) - // console.log( - // wrapper.findComponent('[data-test="sample_image"]').attributes() - // ); - expect( - wrapper.findComponent('[data-test="sample_image"]').html() - ).toContain( - 'http://materialsmine.org/sample/l382-s2-huang-2019' - ) - }) -}) - -describe('MaterialComponentsAndAttributes.vue', () => { - it('renders loading placeholder for material components', async () => { - const wrapper = shallowMount(MaterialComponentsAndAttributes, { - localVue, - store, - router - }) - expect(wrapper.vm.$data.loading).toBe(true) - }) - - it('renders material components', async () => { - const wrapper = shallowMount(MaterialComponentsAndAttributes, { - localVue, - store, - router - }) - await wrapper.setData({ - materialsData: [ - { - classType: 'Gold', - role: 'Filler', - materialProperties: [ - { - type: 'Density', - units: 'Gram per Cubic Centimeter', - value: 19.3 - } - ] - } - ], - loading: false - }) - expect( - wrapper.findComponent('[data-test="material-properties"]').text() - ).toContain('Gold') + it('renders the header of the page', async () => { + expect(true) }) }) From 44ac17930fa750da646c2d784ec9c8d66eb483fe Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Fri, 18 Feb 2022 13:10:56 -0800 Subject: [PATCH 146/306] #113: Fix for error thrown in unit test --- app/src/pages/explorer/sample/sample.js | 7 +++++++ app/tests/unit/pages/explorer/Sample.spec.js | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/src/pages/explorer/sample/sample.js b/app/src/pages/explorer/sample/sample.js index a75acf79..f4e05cbd 100644 --- a/app/src/pages/explorer/sample/sample.js +++ b/app/src/pages/explorer/sample/sample.js @@ -25,18 +25,21 @@ export default { return await querySparql(query(sampleId)) }, parseHeader (data) { + if (!data) return null const parsedData = parseSPARQL(data) if (!parsedData.length) return null const [sampleData] = parsedData return sampleData }, parseOtherSamples (data) { + if (!data) return null const parsedData = parseSPARQL(data) if (!parsedData.length) return null const links = parsedData.map(({ sample }) => sample.split('/').pop()) return links }, parseProcessLabel (data) { + if (!data) return null const parsedData = parseSPARQL(data) if (!parsedData.length) return null const [processLabelObject] = parsedData @@ -44,6 +47,7 @@ export default { return processLabel }, parseMaterialData (data) { + if (!data) return null const parsedData = parseSPARQL(data) if (!parsedData.length) return null const seen = new Set() @@ -82,6 +86,7 @@ export default { return filteredArr }, parseCuratedProperties (data) { + if (!data) return null const parseData = parseSPARQL(data) if (!parseData.length) return null const curatedProperties = parseData.map((property) => { @@ -99,6 +104,7 @@ export default { return curatedProperties }, parseProcessingSteps (data) { + if (!data) return null const parsedData = parseSPARQL(data) if (!parsedData.length) return null const steps = parsedData.map( @@ -109,6 +115,7 @@ export default { return steps }, parseSampleImages (data) { + if (!data) return null const parsedData = parseSPARQL(data) if (!parsedData.length) return null const images = parsedData.map((item) => { diff --git a/app/tests/unit/pages/explorer/Sample.spec.js b/app/tests/unit/pages/explorer/Sample.spec.js index 93214c6c..cc97e424 100644 --- a/app/tests/unit/pages/explorer/Sample.spec.js +++ b/app/tests/unit/pages/explorer/Sample.spec.js @@ -1,10 +1,20 @@ -// import Sample from "@/pages/explorer/sample/Sample.vue"; -// import createWrapper from "../../../jest/script/wrapper"; +import Sample from "@/pages/explorer/sample/Sample.vue"; +import createWrapper from "../../../jest/script/wrapper"; +import { querySparql } from '@/modules/sparql' +jest.mock('@/modules/sparql') +querySparql.mockImplementation((uri) => {}) HTMLCanvasElement.prototype.getContext = () => {} +global.fetch = jest.fn(() => + Promise.resolve({ + json: () => Promise.resolve({}), + }) +); + describe('Sample.vue', () => { it('renders the header of the page', async () => { + const wrapper = createWrapper(Sample, {}, true) expect(true) }) }) From 10c86a4e4cfc92d2e740dae7a7275146990bf057 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Fri, 18 Feb 2022 13:13:04 -0800 Subject: [PATCH 147/306] Linting errors --- app/tests/unit/pages/explorer/Sample.spec.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/tests/unit/pages/explorer/Sample.spec.js b/app/tests/unit/pages/explorer/Sample.spec.js index cc97e424..cac4ab86 100644 --- a/app/tests/unit/pages/explorer/Sample.spec.js +++ b/app/tests/unit/pages/explorer/Sample.spec.js @@ -1,5 +1,5 @@ -import Sample from "@/pages/explorer/sample/Sample.vue"; -import createWrapper from "../../../jest/script/wrapper"; +import Sample from '@/pages/explorer/sample/Sample.vue' +import createWrapper from '../../../jest/script/wrapper' import { querySparql } from '@/modules/sparql' jest.mock('@/modules/sparql') querySparql.mockImplementation((uri) => {}) @@ -8,13 +8,14 @@ HTMLCanvasElement.prototype.getContext = () => {} global.fetch = jest.fn(() => Promise.resolve({ - json: () => Promise.resolve({}), + json: () => Promise.resolve({}) }) -); +) describe('Sample.vue', () => { it('renders the header of the page', async () => { const wrapper = createWrapper(Sample, {}, true) + console.log(wrapper) expect(true) }) }) From 5a4b24d311bfcf462f4cfc329aa5575758e05b9f Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Fri, 18 Feb 2022 16:11:58 -0800 Subject: [PATCH 148/306] #97: Set up for explorer results state management --- app/src/components/explorer/SearchHeader.vue | 16 ++++++++++------ app/src/store/modules/explorer/getters.js | 3 +++ app/src/store/modules/explorer/index.js | 1 + app/src/store/modules/explorer/mutations.js | 3 +++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/src/components/explorer/SearchHeader.vue b/app/src/components/explorer/SearchHeader.vue index e4ed8f12..f12f4a9f 100644 --- a/app/src/components/explorer/SearchHeader.vue +++ b/app/src/components/explorer/SearchHeader.vue @@ -13,16 +13,17 @@
Query "{{searchWord}}" found 12345 results
- - - - - - + + + + + +
diff --git a/app/src/store/modules/explorer/getters.js b/app/src/store/modules/explorer/getters.js index cfa1cebe..6962da13 100644 --- a/app/src/store/modules/explorer/getters.js +++ b/app/src/store/modules/explorer/getters.js @@ -2,6 +2,9 @@ export default { menuVisible (state) { return state.toggleMenuVisibility }, + getResultsTab (state) { + return state.resultsTab + }, getSearchKeyword (state) { return state.searchKeyword }, diff --git a/app/src/store/modules/explorer/index.js b/app/src/store/modules/explorer/index.js index 45b694da..6c5f65af 100644 --- a/app/src/store/modules/explorer/index.js +++ b/app/src/store/modules/explorer/index.js @@ -7,6 +7,7 @@ export default { state () { return { toggleMenuVisibility: false, + resultsTab: '', searchKeyword: '', searching: false } diff --git a/app/src/store/modules/explorer/mutations.js b/app/src/store/modules/explorer/mutations.js index 01d32e8e..b58c1d26 100644 --- a/app/src/store/modules/explorer/mutations.js +++ b/app/src/store/modules/explorer/mutations.js @@ -2,6 +2,9 @@ export default { setMenuVisible (state) { state.toggleMenuVisibility = !state.toggleMenuVisibility }, + setResultsTab (state, payload) { + state.resultsTab = payload + }, setSearchKeyword (state, payload) { state.searchKeyword = payload }, From 3f1c11460cb0cb9a402f540d1348956f3bd58244 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Fri, 18 Feb 2022 16:13:27 -0800 Subject: [PATCH 149/306] Fix linting errors --- app/src/components/explorer/SearchHeader.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/components/explorer/SearchHeader.vue b/app/src/components/explorer/SearchHeader.vue index f12f4a9f..f43ee334 100644 --- a/app/src/components/explorer/SearchHeader.vue +++ b/app/src/components/explorer/SearchHeader.vue @@ -56,7 +56,7 @@ export default { // } }, methods: { - ...mapMutations( 'explorer', ['setResultsTab']), + ...mapMutations('explorer', ['setResultsTab']) } } From d23df5b34105a9152fba6e77a987d04dab397dc9 Mon Sep 17 00:00:00 2001 From: Kevin Zuniga Cuellar Date: Sat, 19 Feb 2022 12:07:54 -0500 Subject: [PATCH 150/306] #113: add tests for state variables --- app/src/pages/explorer/Sample.vue | 248 ------------------- app/src/pages/explorer/sample/sample.html | 19 +- app/src/pages/explorer/sample/sample.js | 24 +- app/tests/unit/pages/explorer/Sample.spec.js | 131 +++++++++- 4 files changed, 143 insertions(+), 279 deletions(-) delete mode 100644 app/src/pages/explorer/Sample.vue diff --git a/app/src/pages/explorer/Sample.vue b/app/src/pages/explorer/Sample.vue deleted file mode 100644 index 077210b7..00000000 --- a/app/src/pages/explorer/Sample.vue +++ /dev/null @@ -1,248 +0,0 @@ - - - diff --git a/app/src/pages/explorer/sample/sample.html b/app/src/pages/explorer/sample/sample.html index c1571f1a..b9aa6562 100644 --- a/app/src/pages/explorer/sample/sample.html +++ b/app/src/pages/explorer/sample/sample.html @@ -1,13 +1,13 @@
-
+

{{ this.$route.params.label }}

{{ header.sample_label }} {{ header.process_label }} -
DOI: {{ header.DOI }}
+
DOI: {{ header.DOI }}
-
+

Material Components and Attributes

  • Class: {{ material.class }}
  • @@ -19,12 +19,11 @@

    Material Components and Attributes

-
+

Sample Images

- - +
-
+

Curated Properties of Nanocomposite Sample

Scalar attributes:
    @@ -37,16 +36,16 @@

    Curated Properties of Nanocomposite Sample

Curated Processing Steps and Parameters

-
Class: {{ processLabel }}
+
Class: {{ processLabel }}
Processing Steps:
    -
  • +
  • {{ step.parameterLabel }} {{ step.description }}
-
+

Other Samples from this Research Article

diff --git a/app/src/pages/explorer/sample/sample.js b/app/src/pages/explorer/sample/sample.js index f4e05cbd..4d73d10a 100644 --- a/app/src/pages/explorer/sample/sample.js +++ b/app/src/pages/explorer/sample/sample.js @@ -25,31 +25,27 @@ export default { return await querySparql(query(sampleId)) }, parseHeader (data) { - if (!data) return null + if (!data || data.length === 0) return null const parsedData = parseSPARQL(data) - if (!parsedData.length) return null const [sampleData] = parsedData return sampleData }, parseOtherSamples (data) { - if (!data) return null + if (!data || data.length === 0) return null const parsedData = parseSPARQL(data) - if (!parsedData.length) return null const links = parsedData.map(({ sample }) => sample.split('/').pop()) return links }, parseProcessLabel (data) { - if (!data) return null + if (!data || data.length === 0) return null const parsedData = parseSPARQL(data) - if (!parsedData.length) return null const [processLabelObject] = parsedData const { process_label: processLabel } = processLabelObject return processLabel }, parseMaterialData (data) { - if (!data) return null + if (!data || data.length === 0) return null const parsedData = parseSPARQL(data) - if (!parsedData.length) return null const seen = new Set() const filteredArr = parsedData .filter((item) => { @@ -86,7 +82,7 @@ export default { return filteredArr }, parseCuratedProperties (data) { - if (!data) return null + if (!data || data.length === 0) return null const parseData = parseSPARQL(data) if (!parseData.length) return null const curatedProperties = parseData.map((property) => { @@ -104,9 +100,8 @@ export default { return curatedProperties }, parseProcessingSteps (data) { - if (!data) return null + if (!data || data.length === 0) return null const parsedData = parseSPARQL(data) - if (!parsedData.length) return null const steps = parsedData.map( ({ param_label: parameterLabel, Descr: description }) => { return { parameterLabel, description } @@ -115,9 +110,8 @@ export default { return steps }, parseSampleImages (data) { - if (!data) return null + if (!data || data.length === 0) return null const parsedData = parseSPARQL(data) - if (!parsedData.length) return null const images = parsedData.map((item) => { return { src: item.image, alt: item.sample } }) @@ -125,7 +119,6 @@ export default { }, async fetchSamplePageData () { this.loading = true - // es 11 await Promise.allSettled([ this.fetchData(sampleQueries.materialComponents), this.fetchData(sampleQueries.curatedProperties), @@ -136,7 +129,6 @@ export default { this.fetchData(sampleQueries.header) ]) .then((res) => { - console.log(res) const data = res.map((promise) => { if (promise.status === 'fulfilled') return promise.value console.error(promise.reason) @@ -169,8 +161,6 @@ export default { $route: 'fetchSamplePageData' }, created () { - console.log('before') this.fetchSamplePageData() - console.log('after') } } diff --git a/app/tests/unit/pages/explorer/Sample.spec.js b/app/tests/unit/pages/explorer/Sample.spec.js index cac4ab86..74497c54 100644 --- a/app/tests/unit/pages/explorer/Sample.spec.js +++ b/app/tests/unit/pages/explorer/Sample.spec.js @@ -1,6 +1,8 @@ import Sample from '@/pages/explorer/sample/Sample.vue' import createWrapper from '../../../jest/script/wrapper' import { querySparql } from '@/modules/sparql' + +// mocking functions jest.mock('@/modules/sparql') querySparql.mockImplementation((uri) => {}) @@ -13,9 +15,130 @@ global.fetch = jest.fn(() => ) describe('Sample.vue', () => { - it('renders the header of the page', async () => { - const wrapper = createWrapper(Sample, {}, true) - console.log(wrapper) - expect(true) + let wrapper + // create wrapper and set loading to false + beforeAll(async () => { + wrapper = createWrapper(Sample, {}, false) + await wrapper.vm.$nextTick() + await wrapper.setData({ loading: false }) + }) + + it('renders header', async () => { + await wrapper.setData({ + header: { + DOI: 'DOI of the sample', + sample_label: 'Sample label', + process_label: 'Sample process label' + } + }) + const header = wrapper.findComponent('[data-test="header"]') + + expect.assertions(4) + expect(header.exists()).toBe(true) + expect(header.text()).toContain('DOI of the sample') + expect(header.text()).toContain('Sample label') + expect(header.text()).toContain('Sample process label') + }) + + it('renders materials components and attributes', async () => { + await wrapper.setData({ + materialComponents: [ + { + class: 'Material class', + role: 'Material role', + materialProperties: [ + { + type: 'Material property type', + value: 'Material property value', + units: 10 + } + ] + } + ] + }) + const materialComponents = wrapper.findComponent( + '[data-test="materialComponents"]' + ) + + expect.assertions(6) + expect(materialComponents.exists()).toBe(true) + expect(materialComponents.text()).toContain('Material class') + expect(materialComponents.text()).toContain('Material role') + expect(materialComponents.text()).toContain('Material property type') + expect(materialComponents.text()).toContain('Material property value') + expect(materialComponents.text()).toContain('10') + }) + + it('renders curated properties of nanocomposite sample', async () => { + await wrapper.setData({ + curatedProperties: [ + { + type: 'example type', + value: 10, + units: 'example units' + } + ] + }) + const curatedProperties = wrapper.findComponent( + '[data-test="curatedProperties"]' + ) + + expect.assertions(4) + expect(curatedProperties.exists()).toBe(true) + expect(curatedProperties.text()).toContain('example type') + expect(curatedProperties.text()).toContain(10) + expect(curatedProperties.text()).toContain('example units') + }) + + it('renders process label and processing steps', async () => { + await wrapper.setData({ + processLabel: 'example process label', + processingSteps: [ + { + parameterLabel: 'example parameter label', + description: 'example description' + } + ] + }) + const processLabel = wrapper.findComponent('[data-test="processLabel"]') + const processingSteps = wrapper.findComponent( + '[data-test="processingSteps"]' + ) + expect.assertions(4) + expect(processLabel.exists()).toBe(true) + expect(processingSteps.exists()).toBe(true) + + expect(processLabel.text()).toContain('example process label') + expect(processingSteps.text()).toContain('example parameter label') + }) + + it('renders sample images', async () => { + await wrapper.setData({ + sampleImages: [ + { + src: 'example src', + alt: 'example alt' + } + ] + }) + const sampleImages = wrapper.findComponent('[data-test="sampleImages"]') + + expect.assertions(2) + expect(sampleImages.exists()).toBe(true) + expect(sampleImages.html()).toContain( + 'example alt' + ) + }) + + it('renders other samples', async () => { + await wrapper.setData({ + otherSamples: ['sample-link-1', 'sample-link-2'] + }) + const otherSamples = wrapper.findComponent('[data-test="otherSamples"]') + + expect.assertions(3) + expect(otherSamples.exists()).toBe(true) + expect(otherSamples.text()).toContain('sample-link-1') + expect(otherSamples.text()).toContain('sample-link-2') }) }) From 34450fa0df858c5eaea6afe71ee56ad414a35b3f Mon Sep 17 00:00:00 2001 From: Kevin Zuniga Cuellar Date: Sun, 20 Feb 2022 22:17:51 -0500 Subject: [PATCH 151/306] #113: remove page style --- app/src/pages/explorer/sample/Sample.vue | 7 +------ app/src/pages/explorer/sample/sample.html | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/src/pages/explorer/sample/Sample.vue b/app/src/pages/explorer/sample/Sample.vue index 506c1e76..eb1017a9 100644 --- a/app/src/pages/explorer/sample/Sample.vue +++ b/app/src/pages/explorer/sample/Sample.vue @@ -1,9 +1,4 @@ - + diff --git a/app/src/pages/explorer/sample/sample.html b/app/src/pages/explorer/sample/sample.html index b9aa6562..394b053d 100644 --- a/app/src/pages/explorer/sample/sample.html +++ b/app/src/pages/explorer/sample/sample.html @@ -1,4 +1,4 @@ -
+
From a1addb2558276c90542d13f0016d170a15350267 Mon Sep 17 00:00:00 2001 From: Kevin Zuniga Cuellar Date: Sun, 20 Feb 2022 22:24:37 -0500 Subject: [PATCH 152/306] #113: fix empty results display --- app/src/pages/explorer/sample/sample.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/app/src/pages/explorer/sample/sample.js b/app/src/pages/explorer/sample/sample.js index 4d73d10a..270038c5 100644 --- a/app/src/pages/explorer/sample/sample.js +++ b/app/src/pages/explorer/sample/sample.js @@ -25,27 +25,31 @@ export default { return await querySparql(query(sampleId)) }, parseHeader (data) { - if (!data || data.length === 0) return null + if (!data) return null const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null const [sampleData] = parsedData return sampleData }, parseOtherSamples (data) { - if (!data || data.length === 0) return null + if (!data) return null const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null const links = parsedData.map(({ sample }) => sample.split('/').pop()) return links }, parseProcessLabel (data) { - if (!data || data.length === 0) return null + if (!data) return null const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null const [processLabelObject] = parsedData const { process_label: processLabel } = processLabelObject return processLabel }, parseMaterialData (data) { - if (!data || data.length === 0) return null + if (!data) return null const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null const seen = new Set() const filteredArr = parsedData .filter((item) => { @@ -82,8 +86,9 @@ export default { return filteredArr }, parseCuratedProperties (data) { - if (!data || data.length === 0) return null + if (!data) return null const parseData = parseSPARQL(data) + if (parseData.length === 0) return null if (!parseData.length) return null const curatedProperties = parseData.map((property) => { const { AttrType, value, Units: units } = property @@ -100,8 +105,9 @@ export default { return curatedProperties }, parseProcessingSteps (data) { - if (!data || data.length === 0) return null + if (!data) return null const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null const steps = parsedData.map( ({ param_label: parameterLabel, Descr: description }) => { return { parameterLabel, description } @@ -110,8 +116,10 @@ export default { return steps }, parseSampleImages (data) { - if (!data || data.length === 0) return null + console.log(data) + if (!data) return null const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null const images = parsedData.map((item) => { return { src: item.image, alt: item.sample } }) From ba64ce19e821d244993031eac4b9a820adb6921b Mon Sep 17 00:00:00 2001 From: Rory Schadler <48921090+roryschadler@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:38:34 -0500 Subject: [PATCH 153/306] #66 templated view article (#112) * #66 initial article commit * #66: Refactor article page, fetch article metadata Moved Article.vue, separated out into article.js to match file structure of other pages. Progressed on Semantic Scholar API logic. * #66: Refactor article.js * #66: Refactor Article.vue * #66: Add route for Article View Added route to explorer for the article view. Moved DOI from component prop to a watcher and computed property pair. * #66: Refactor article.js to move logic to services Moved article metadata retrieval logic to services. Unified all metadata under one object for simpler reference. * #66: First pass at article HTML view First attempt at displaying all article metadata. Also added pre-push linting fixes. * #66: Add loading state awareness * #66: Add article venue to retrieved fields * #66: Second pass at article view HTML Added basic loading indicator, refactored table to have better structure (I think) * #66: Basic CSS for article view * #66: Removed erroneous comment * #66: Fix scrolling bug Scrolling tables also scrolled their titles, but not their header rows. Isolated tables in their own div, maybe tables should be their own component... * #66: Unify dir structure, nest article page Move explorer/article/services to modules/explorer/article/services, clean up article now that it's nested properly (barring further change to nest completely under sample). Refactor extra function from fetchJSON into getArticleMetadata. * #66: initial Article.vue testing commit Includes mock for Semantic Scholar API calls and article.js whitespace linting fix. * #66: Refactored getArticleMetadata for easier mock Mocking getArticleMetadata easily required moving it into an enclosing object so that the manual mock could do the same, allowing it to access properties. The manual mock was written following along with [jest's manual mock](https://jestjs.io/docs/manual-mocks). The mock of the resulting getArticle also provides a stub of the SemanticScholar API response as of 2/2/22, for reference and testing. * #66: Write tests for Article.vue Wrote tests of DOI loading, reloading; article data loading; API failure. Added classes to article.html items to distinguish them and allow the tests to refer to them. Updated article.js to use the new articleMetadata.js and fixed bugs that appeared in testing. * #66: Fix linting errors * #66: Write tests for module articleMetadata.js Updated articleMetadata mock to include raw and cleaned mock data, and wrote tests of the fetch handler and response cleaning routines. Fixed issues in articleMetadata.js that came up in testing. * #66: Refactored articleMetadata.js to better track API errors Refactored .get function to remove repeated code and allow API calls to occur in parallel. Rewrote how internal fetch returns in order to pass errors (and success codes) in API call along to caller. Updated mock data to include mock version of success codes * #66: Updated tests to match Also added missing response codes to mock data, and fixed citation and reference call status not being passed through * #66: Updated Article.vue to display errors Article view now takes advantage of newly passed API errors to inform the user that an error has occurred. This could be expanded on * #66: Linting fixes * #66: Update test to use createWrapper Replaced localVue, shallowMount with createWrapper for consistency. Added test to ensure error message is displayed to user. * #66: Write comments, refactor error storage * #66: Write jsdoc-style function comments Documented functions, removed unused mock response function, and refactored testing slightly to remove repetition. * #66: Move article to its own route * #25: Remove console.logs, add reusable spinner --- app/src/assets/css/modules/_misc.scss | 90 +++++++ .../services/__mocks__/articleMetadata.js | 251 ++++++++++++++++++ .../article/services/articleMetadata.js | 132 +++++++++ app/src/pages/explorer/article/Article.vue | 2 + app/src/pages/explorer/article/article.html | 77 ++++++ app/src/pages/explorer/article/article.js | 91 +++++++ app/src/router/module/explorer.js | 8 + .../modules/explorer/articleMetadata.spec.js | 119 +++++++++ app/tests/unit/pages/explorer/article.spec.js | 69 +++++ 9 files changed, 839 insertions(+) create mode 100644 app/src/modules/explorer/article/services/__mocks__/articleMetadata.js create mode 100644 app/src/modules/explorer/article/services/articleMetadata.js create mode 100644 app/src/pages/explorer/article/Article.vue create mode 100644 app/src/pages/explorer/article/article.html create mode 100644 app/src/pages/explorer/article/article.js create mode 100644 app/tests/unit/modules/explorer/articleMetadata.spec.js create mode 100644 app/tests/unit/pages/explorer/article.spec.js diff --git a/app/src/assets/css/modules/_misc.scss b/app/src/assets/css/modules/_misc.scss index 28ebebd8..1d94916f 100644 --- a/app/src/assets/css/modules/_misc.scss +++ b/app/src/assets/css/modules/_misc.scss @@ -507,3 +507,93 @@ } } } + +.article { + &_title { + margin: 1rem 0; + padding-bottom: 0.2rem; + } + + &_subtitle { + margin: 1rem 0; + font-weight: bold; + font-size: 2.2rem; + } + + &_authors { + margin: 1rem 0; + font-style: italic; + font-size: 2.2rem; + } + + &_metadata { + margin: 1rem 0; + font-size: 1.5rem; + + &_strong { + font-weight: bold; + } + } + + &_abstract { + width: 90%; + font-size: 1.7rem; + line-height: 1.3; + margin: 1rem 0; + } + + &_citations,&_references { + margin: 2rem 0; + } + + &_table { + max-height: 50rem; + overflow: auto; + + & > table { + table-layout: fixed; + width: 100%; + border-collapse: collapse; + } + + & tr { + border: solid; + border-color: #555; + border-width: 1px 0; + + &:first-child { + border-top: none; + } + + &:last-child { + border-bottom: none; + } + } + + & th { + text-align: left; + font-size: 1.7rem; + position: sticky; + top: 0; + background: #eee; + &:nth-child(1){ + width: 2.5em; + } + &:nth-child(2){ + width: 20%; + } + &:nth-child(3){ + width: 75%; + } + } + + & td { + overflow: hidden; + max-width: 30%; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 1.5rem; + text-align: left; + } + } +} \ No newline at end of file diff --git a/app/src/modules/explorer/article/services/__mocks__/articleMetadata.js b/app/src/modules/explorer/article/services/__mocks__/articleMetadata.js new file mode 100644 index 00000000..6f5d387f --- /dev/null +++ b/app/src/modules/explorer/article/services/__mocks__/articleMetadata.js @@ -0,0 +1,251 @@ +/* globals jest */ + +// cleaned SemanticScholar API response, for comparison +export const cleanResponse = { + ok: true, + status: 200, + statusText: 'OK', + paperId: 'abc', + title: 'NanoMine schema: A shortened data representation for testing Article View', + abstract: 'Polymer nanocomposites consist of a polymer matrix and fillers like this is a testing matrix and filler material', + venue: 'APL Materials', + year: 2018, + citationCount: 2, + isOpenAccess: true, + authors: [ + { + authorId: 'abc1', + name: 'He Zhao' + }, + { + authorId: 'abc2', + name: 'Yixing Wang' + } + ], + authorNames: 'He Zhao, Yixing Wang', + citations: [ + { + ok: true, + status: 200, + statusText: 'OK', + paperId: 'def', + title: 'Bayesian Optimization for testing', + year: 2019, + authors: [ + { + authorId: 'def1', + name: 'Yichi Zhang' + }, + { + authorId: 'def2', + name: 'D. Apley' + } + ], + authorNames: 'Yichi Zhang, D. Apley' + }, + { + paperId: 'ghi', + title: 'Data-Centric Mixed-Variable Bayesian Optimization For Materials Design', + year: 2019, + authors: [ + { + authorId: 'ghi1', + name: 'A. Iyer' + }, + { + authorId: 'ghi2', + name: 'Yichi Zhang' + } + ], + authorNames: 'A. Iyer, Yichi Zhang' + } + ], + references: [ + { + ok: true, + status: 200, + statusText: 'OK', + paperId: 'jkl', + title: 'A translation approach to portable ontology specifications', + year: 1993, + authors: [ + { + authorId: 'jkl1', + name: 'T. Gruber' + } + ], + authorNames: 'T. Gruber' + }, + { + paperId: 'mno', + title: 'MatML: An XML for standardizing web-based materials property data', + year: 2000, + authors: [ + { + authorId: 'mno1', + name: 'E. Begley' + }, + { + authorId: 'mno2', + name: 'C. Sturrock' + } + ], + authorNames: 'E. Begley, C. Sturrock' + } + ] +} + +// raw response from SemanticScholar API, split into article, references, and citations as +// returned from the REST API. +export const rawResponse = { + article: { + paperId: 'abc', + title: 'NanoMine schema: A shortened data representation for testing Article View', + abstract: 'Polymer nanocomposites consist of a polymer matrix and fillers like this is a testing matrix and filler material', + venue: 'APL Materials', + year: 2018, + citationCount: 2, + isOpenAccess: true, + authors: [ + { + authorId: 'abc1', + name: 'He Zhao' + }, + { + authorId: 'abc2', + name: 'Yixing Wang' + } + ] + }, + references: { + offset: 0, + data: [ + { + citedPaper: { + paperId: 'jkl', + title: 'A translation approach to portable ontology specifications', + year: 1993, + authors: [ + { + authorId: 'jkl1', + name: 'T. Gruber' + } + ] + } + }, + { + citedPaper: { + paperId: 'mno', + title: 'MatML: An XML for standardizing web-based materials property data', + year: 2000, + authors: [ + { + authorId: 'mno1', + name: 'E. Begley' + }, + { + authorId: 'mno2', + name: 'C. Sturrock' + } + ] + } + }, + { + citedPaper: { + paperId: null, + title: '', + year: 2011, + authors: [] + } + }, + { + citedPaper: { + paperId: null, + title: 'for Polymer Property Predictor and Database', + year: null, + authors: [] + } + }, + { + citedPaper: { + paperId: null, + title: '', + year: null, + authors: [] + } + } + ] + }, + citations: { + offset: 0, + data: [ + { + citingPaper: { + paperId: 'def', + title: 'Bayesian Optimization for testing', + year: 2019, + authors: [ + { + authorId: 'def1', + name: 'Yichi Zhang' + }, + { + authorId: 'def2', + name: 'D. Apley' + } + ] + } + }, + { + citingPaper: { + paperId: 'ghi', + title: 'Data-Centric Mixed-Variable Bayesian Optimization For Materials Design', + year: 2019, + authors: [ + { + authorId: 'ghi1', + name: 'A. Iyer' + }, + { + authorId: 'ghi2', + name: 'Yichi Zhang' + } + ] + } + } + ] + } +} + +export default { + // control properties and their setters + testingData: true, + __setTestingData: function (value) { + this.testingData = !!value + }, + testingRejection: false, + __setTestingRejection: function (value) { + this.testingRejection = !!value + }, + __reset: function () { + this.testingData = true + this.testingRejection = false + }, + /** + * A mock of @/components/modules/explorer/article/services/articleMetadata.get(). + * + * Returns complete or empty data, or a rejected promise, depending on the desired + * testing scenario. + * @param {*} doi retained for compatibility with the original function + * @returns complete data, empty data, or a rejected Promise + */ + get: jest.fn(function ({ doi }) { + if (this.testingData) { + return Promise.resolve(cleanResponse) + } else if (this.testingRejection) { + return Promise.reject(new Error('Testing rejection of articleMetadata.get() Promise')) + } else { + return Promise.resolve() + } + }) +} diff --git a/app/src/modules/explorer/article/services/articleMetadata.js b/app/src/modules/explorer/article/services/articleMetadata.js new file mode 100644 index 00000000..026580f2 --- /dev/null +++ b/app/src/modules/explorer/article/services/articleMetadata.js @@ -0,0 +1,132 @@ +export default { + /** + * Retrieves article metadata for the given DOI, including: + * title, authors, publication year, publication venue, Open Access status, + * abstract, citation count; + * as well as the following for each citing paper and referenced paper: + * title, authors, publication year + * @param {string} doi DOI to request metadata for + * @returns article metadata, or error response if API call fails + */ + get: async function ({ doi }) { + // SemanticScholar API fields + const articleFields = ['title', 'authors', 'year', 'abstract', 'citationCount', 'isOpenAccess', 'venue'] + const citationFields = ['title', 'authors', 'year', 'paperId'] + const referencesFields = ['title', 'authors', 'year', 'paperId'] + + const responsePromises = [ + fetchSemanticScholarResponse(doi, '', articleFields), + fetchSemanticScholarResponse(doi, 'citations', citationFields), + fetchSemanticScholarResponse(doi, 'references', referencesFields) + ] + var [ + articleResponse, + articleCitationsResponse, + articleReferencesResponse + ] = (await Promise.allSettled(responsePromises)).map(value => value.value) + + // if article metadata is missing or errored, there is nothing else to return + if (!articleResponse || !articleResponse.ok) { + return articleResponse + } + + // clean up author names into easily displayed string + if (articleResponse.authors) { + articleResponse.authorNames = articleResponse.authors.map(author => author.name).join(', ') + } + + // for citations, references, pass original response with cleaned data, in case of errors + // bundle into article response for easy return + articleResponse.citations = { + ...articleCitationsResponse, + data: cleanPaperResponse(articleCitationsResponse, 'citingPaper') + } + articleResponse.references = { + ...articleReferencesResponse, + data: cleanPaperResponse(articleReferencesResponse, 'citedPaper') + } + + return articleResponse + } +} + +/** + * Sorts and cleans the raw array of citation/reference responses from SemanticScholar + * @param {*} rawData raw SemanticScholar API response + * @param {*} prop 'citingPaper' if cleaning citations, 'citedPaper' if cleaning references + * @returns A sorted, filtered, and cleaned array of citations or references + */ +function cleanPaperResponse (rawData, prop) { + if (!rawData || !rawData.ok) { // if data was not returned or had an error, skip cleaning + return rawData + } else { + // filter response items that are missing data, sort by year and title + const cleanedData = rawData.data.map(paper => paper[prop]).filter(articleFilter).sort(articleSort) + + // clean up author names into easily displayed string + for (const ref of cleanedData) { + if (ref.authors) { + ref.authorNames = ref.authors.map(author => author.name).join(', ') + } + } + return cleanedData + } +} + +/** Sort function for citations, references */ +function articleSort (a, b) { + if (a.year < b.year) { + return -1 + } else if (a.year > b.year) { + return 1 + } else { + return a.title.localeCompare(b.title) + } +} + +/** Filter function for citations, references */ +function articleFilter (paper) { + return paper.title && paper.authors && paper.year && paper.paperId +} + +/** + * Gets SemanticScholar API response for a given DOI, path, and set of query fields. + * @param {string} doi DOI string to query for + * @param {string} path 'citations' for querying citations, 'references' for querying references, or blank for articles + * @param {Array.} fields query fields to request from SemanticScholar + * @returns article response with JSON representation parsed, or error information + */ +async function fetchSemanticScholarResponse (doi, path, fields) { + const semanticScholarQueryBase = `${doi}/${path || ''}` + const requestURL = new URL(`https://api.semanticscholar.org/graph/v1/paper/DOI:${semanticScholarQueryBase}`) + requestURL.search = new URLSearchParams({ + fields: fields.join(','), + limit: 500 + }) + + try { + const rawResponse = await fetch(requestURL) + const JSONResponse = await rawResponse.json() + + // pass along important Response properties returned by fetch() too, it + // contains server response codes including errors + return { + ok: rawResponse.ok, + status: rawResponse.status, + statusText: rawResponse.statusText, + ...JSONResponse + } + } catch (error) { + if (error instanceof TypeError) { // fetch throws TypeErrors for network issues + // mock the important Response properties for ease of use + return { + ok: false, + error: error.message, + rawError: error, + rawData: {} + } + } else { + throw error + } + } +} diff --git a/app/src/pages/explorer/article/Article.vue b/app/src/pages/explorer/article/Article.vue new file mode 100644 index 00000000..84af536f --- /dev/null +++ b/app/src/pages/explorer/article/Article.vue @@ -0,0 +1,2 @@ + + diff --git a/app/src/pages/explorer/article/article.html b/app/src/pages/explorer/article/article.html new file mode 100644 index 00000000..136e0724 --- /dev/null +++ b/app/src/pages/explorer/article/article.html @@ -0,0 +1,77 @@ +
+
+

{{ article.title }}

+ + + +
+

Abstract

+

{{ article.abstract }}

+
+ + +
+
References
+
+ + + + + + + + + + + + + + + +
YearAuthor(s)Title
{{ refObject.year }}{{ refObject.authorNames }}{{ refObject.title }}
+
+
+
+
References failed to load. Please try again in a moment.
+
+
+
Cited By
+
+ + + + + + + + + + + + + + + +
YearAuthor(s)Title
{{ refObject.year }}{{ refObject.authorNames }}{{ refObject.title }}
+
+
+
+
Citations failed to load. Please try again in a moment.
+
+
+
+ +
+
+

Error retrieving this article.

+

Error: {{ error.article }}

+
+
\ No newline at end of file diff --git a/app/src/pages/explorer/article/article.js b/app/src/pages/explorer/article/article.js new file mode 100644 index 00000000..79134cce --- /dev/null +++ b/app/src/pages/explorer/article/article.js @@ -0,0 +1,91 @@ +import articleMetadata from '@/modules/explorer/article/services/articleMetadata' +import Spinner from '@/components/Spinner' + +export default { + name: 'Article', + components: { + 'loading-spinner': Spinner + }, + data () { + return { + toggleMenuVisibility: false, + article: {}, + loading: false, + error: {} + } + }, + computed: { + doi: function () { + if (this.$route) { + return this.$route.params.doi + } else { + return null + } + }, + doiLink: function () { + if (this.doi) { + return new URL(this.doi, 'https://www.doi.org') + } else { + return '' + } + } + }, + watch: { + doi: 'fetchData' + }, + created () { + this.fetchData() + }, + methods: { + toggleMenu () { + this.toggleMenuVisibility = !this.toggleMenuVisibility + }, + async fetchData () { + this.loading = true + this.error = {} + this.article = {} + + if (this.doi) { + try { + this.article = await articleMetadata.get({ doi: this.doi }) + this.loading = false + + // ensure all parts were provided, set error flags if not + this.error = { + article: this.getError('article'), + citations: this.getError('citations'), + references: this.getError('references') + } + } catch (error) { + // pass error message on to user + this.error = { + article: error.message, + citations: true, + references: true + } + this.loading = false + } + } + }, + /** + * Checks if articleMetadata.get() returned any error. + * @param {string} prop Part of article object to check + * @returns As much information as is available for the error, if any. + */ + getError (prop) { + let base + if (prop === 'article') { + base = this.article + } else { + base = this.article[prop] + } + if (!base) { // if metadata wasn't returned, error is unclear + return true + } else if (!base.ok) { // fetch responded with error, or API did + return base.error || `${base.status} ${base.statusText}` + } else { // no error detected + return false + } + } + } +} diff --git a/app/src/router/module/explorer.js b/app/src/router/module/explorer.js index 6564e97a..a072a860 100644 --- a/app/src/router/module/explorer.js +++ b/app/src/router/module/explorer.js @@ -6,6 +6,14 @@ const explorerRoutes = [ component: () => import('@/pages/explorer/Home.vue'), meta: { requiresAuth: false } }, + { + // DOIs usually have more than one segment, i.e. 10.1063/1.5046839 + // extended path regex needed to match those multiple segments + path: 'article/:doi+', + name: 'Article', + component: () => import('@/pages/explorer/article/Article.vue'), + meta: { requiresAuth: false } + }, { path: 'visualization', name: 'ExplorerVisualization', diff --git a/app/tests/unit/modules/explorer/articleMetadata.spec.js b/app/tests/unit/modules/explorer/articleMetadata.spec.js new file mode 100644 index 00000000..67fc3a25 --- /dev/null +++ b/app/tests/unit/modules/explorer/articleMetadata.spec.js @@ -0,0 +1,119 @@ +import articleMetadata from '@/modules/explorer/article/services/articleMetadata' +import { rawResponse, cleanResponse } from '@/modules/explorer/article/services/__mocks__/articleMetadata' + +global.fetch = jest.fn() + +global.console = { + log: jest.fn(), // console.log are ignored in tests + + // Keep native behavior for other methods + error: console.error, + warn: console.warn, + info: console.info, + debug: console.debug +} + +const doi = { doi: '10.1063/1.5046839' } + +describe('articleMetadata.js', () => { + beforeEach(() => { + fetch.mockClear() + }) + + it('translates Semantic Scholar data correctly', async () => { + global.fetch = response('good', 'all') + const article = await articleMetadata.get(doi) + expect(article.title).toBe(cleanResponse.title) + expect(article.references.data[0].paperId).toBe(cleanResponse.references[0].paperId) + }) + + it('handles a bad fetch response to the article request', async () => { + global.fetch = response('bad', 'article') + const article = await articleMetadata.get(doi) + expect(article.error).toMatch(/Testing bad response/) + }) + + it('handles a bad fetch response to the references request', async () => { + global.fetch = response('bad', 'references') + const article = await articleMetadata.get(doi) + expect(article.references.error).toMatch(/Testing bad response/) + expect(article.title).toBe(cleanResponse.title) + }) + + it('handles a bad fetch response to the citations request', async () => { + global.fetch = response('bad', 'citations') + const article = await articleMetadata.get(doi) + expect(article.citations.error).toMatch(/Testing bad response/) + expect(article.title).toBe(cleanResponse.title) + }) + + it('handles a rejected fetch response to the article request', async () => { + global.fetch = response('reject', 'article') + const article = await articleMetadata.get(doi) + expect(article.error).toMatch(/Testing rejection/) + }) + + it('handles a rejected fetch response to the references request', async () => { + global.fetch = response('reject', 'references') + const article = await articleMetadata.get(doi) + expect(article.references.error).toMatch(/Testing rejection/) + expect(article.title).toBe(cleanResponse.title) + }) + + it('handles a rejected fetch response to the citations request', async () => { + global.fetch = response('reject', 'citations') + const article = await articleMetadata.get(doi) + expect(article.citations.error).toMatch(/Testing rejection/) + expect(article.title).toBe(cleanResponse.title) + }) +}) + +/** + * Returns a jest mock function with the proper functionality for the test, + * either returning complete data, a mocked 404 response, or a rejected + * promise. + * + * responseType determines whether the return value of the mock is a 200 + * response with data, a 404 response without, or a rejected Promise. + * testingSection determines the section that receives the 404 or rejected + * Promise, for isolated testing. Has no effect if responseType is 'good'. + * @param {string} responseType either 'good', 'bad', or 'reject + * @param {*} testingSection either 'article', 'citations', or 'references' + * @returns a jest mock with the requested return functionality + */ +function response (responseType, testingSection) { + return jest.fn((requestURL) => { + // check which section is being requested, compare to testingSection + const URLString = requestURL.toString() + let requestedSection + if (URLString.match(/citations/)) { + requestedSection = 'citations' + } else if (URLString.match(/references/)) { + requestedSection = 'references' + } else { + requestedSection = 'article' + } + + // only return non-good response if testingSection, requested section match + if (responseType !== 'good' && testingSection === requestedSection) { + if (responseType === 'bad') { + return Promise.resolve({ + ok: false, + status: 404, + statusText: 'Testing Not Found', + json: () => Promise.resolve({ error: 'Testing bad response' }) + }) + } else if (responseType === 'reject') { + return Promise.reject(new TypeError('Testing rejection of fetch(article) Promise')) + } + } else { + // responseType is good, or we aren't testing this section + return Promise.resolve({ + ok: true, + status: 200, + statusText: 'OK', + json: () => Promise.resolve(rawResponse[requestedSection]) + }) + } + }) +} diff --git a/app/tests/unit/pages/explorer/article.spec.js b/app/tests/unit/pages/explorer/article.spec.js new file mode 100644 index 00000000..5cb3b542 --- /dev/null +++ b/app/tests/unit/pages/explorer/article.spec.js @@ -0,0 +1,69 @@ +import createWrapper from '../../../jest/script/wrapper' + +import Article from '@/pages/explorer/article/Article.vue' +import articleMetadata from '@/modules/explorer/article/services/articleMetadata' +jest.mock('@/modules/explorer/article/services/articleMetadata') + +var wrapper = null + +afterEach(() => { + articleMetadata.__reset() + articleMetadata.get.mockClear() +}) + +describe('Article.vue', () => { + const baseDOI = '10.1063/1.5046839' + beforeAll(() => { + wrapper = mountArticle(baseDOI) + }) + + it('loads DOI', () => { + const doiWrapper = wrapper.find('.article_doi') + expect(doiWrapper.text()).toMatch(new RegExp(baseDOI)) + }) + + it('displays provided data', () => { + expect(wrapper.vm.loading).toBeFalsy() + const titleWrapper = wrapper.find('.article_title') + expect(titleWrapper.exists()).toBeTruthy() + expect(titleWrapper.text()).toMatch(/NanoMine schema/) + }) + + it('updates when passed a new DOI', async () => { + const newDOI = '10.1002/polb.20925' + wrapper.vm.$router.push(doiLink(newDOI)) + expect(wrapper.vm.doi).toBe(newDOI) + + await wrapper.vm.$nextTick() + expect(articleMetadata.get.mock.calls.length).toBe(1) + }) +}) + +describe('Article.vue', () => { + it('handles data promise rejection', async () => { + articleMetadata.__setTestingData(false) + articleMetadata.__setTestingRejection(true) + wrapper = mountArticle() + + // one tick to retrieve data, one tick to update view + await wrapper.vm.$nextTick() + await wrapper.vm.$nextTick() + + expect(wrapper.vm.error).toBeTruthy() + expect(wrapper.vm.loading).toBeFalsy() + const errorTitle = wrapper.find('.article_title p') + expect(errorTitle.exists()).toBeTruthy() + expect(errorTitle.text()).toMatch(/Testing rejection/) + }) +}) + +function mountArticle (doi) { + const wrapper = createWrapper(Article, { + props: {}, + slots: {} + }) + wrapper.vm.$router.push(doiLink(doi || 'fake/doi')) + return wrapper +} + +const doiLink = doi => `/explorer/article/${doi}` From 7bbe09723248f9743f19e5f5116deca685bf4811 Mon Sep 17 00:00:00 2001 From: Kevin Zuniga Cuellar Date: Tue, 22 Feb 2022 13:00:24 -0500 Subject: [PATCH 154/306] #113: remove console.logs and add index key --- app/src/pages/explorer/sample/sample.html | 17 +- app/src/pages/explorer/sample/sample.js | 203 +++++++++++----------- 2 files changed, 112 insertions(+), 108 deletions(-) diff --git a/app/src/pages/explorer/sample/sample.html b/app/src/pages/explorer/sample/sample.html index 394b053d..7f201568 100644 --- a/app/src/pages/explorer/sample/sample.html +++ b/app/src/pages/explorer/sample/sample.html @@ -9,10 +9,10 @@

{{ this.$route.params.label }}

Material Components and Attributes

-
    +
    • Class: {{ material.class }}
    • Role: {{ material.role }}
    • -
    • +
    • {{ property.type }}: {{ property.value }} {{ property.units }} @@ -21,13 +21,13 @@

      Material Components and Attributes

Sample Images

- +

Curated Properties of Nanocomposite Sample

Scalar attributes:
    -
  • +
  • {{ property.type }}: {{ property.value }} {{ property.units }} @@ -39,7 +39,7 @@

    Curated Processing Steps and Parameters

    Class: {{ processLabel }}
    Processing Steps:
      -
    • +
    • {{ step.parameterLabel }} {{ step.description }}
    • @@ -48,7 +48,12 @@

      Curated Processing Steps and Parameters

      Other Samples from this Research Article

      - + {{ link }}
      diff --git a/app/src/pages/explorer/sample/sample.js b/app/src/pages/explorer/sample/sample.js index 270038c5..684e6584 100644 --- a/app/src/pages/explorer/sample/sample.js +++ b/app/src/pages/explorer/sample/sample.js @@ -1,13 +1,13 @@ -import { querySparql, parseSPARQL } from '@/modules/sparql' -import sampleQueries from '@/modules/queries/sampleQueries' -import Spinner from '@/components/Spinner' +import { querySparql, parseSPARQL } from "@/modules/sparql"; +import sampleQueries from "@/modules/queries/sampleQueries"; +import Spinner from "@/components/Spinner"; export default { - name: 'SampleView', + name: "SampleView", components: { - Spinner + Spinner, }, - data () { + data() { return { header: null, materialComponents: null, @@ -16,117 +16,116 @@ export default { processingSteps: null, sampleImages: null, otherSamples: null, - loading: false - } + loading: false, + }; }, methods: { - async fetchData (query) { - const sampleId = this.$route.params.label - return await querySparql(query(sampleId)) + async fetchData(query) { + const sampleId = this.$route.params.label; + return await querySparql(query(sampleId)); }, - parseHeader (data) { - if (!data) return null - const parsedData = parseSPARQL(data) - if (parsedData.length === 0) return null - const [sampleData] = parsedData - return sampleData + parseHeader(data) { + if (!data) return null; + const parsedData = parseSPARQL(data); + if (parsedData.length === 0) return null; + const [sampleData] = parsedData; + return sampleData; }, - parseOtherSamples (data) { - if (!data) return null - const parsedData = parseSPARQL(data) - if (parsedData.length === 0) return null - const links = parsedData.map(({ sample }) => sample.split('/').pop()) - return links + parseOtherSamples(data) { + if (!data) return null; + const parsedData = parseSPARQL(data); + if (parsedData.length === 0) return null; + const links = parsedData.map(({ sample }) => sample.split("/").pop()); + return links; }, - parseProcessLabel (data) { - if (!data) return null - const parsedData = parseSPARQL(data) - if (parsedData.length === 0) return null - const [processLabelObject] = parsedData - const { process_label: processLabel } = processLabelObject - return processLabel + parseProcessLabel(data) { + if (!data) return null; + const parsedData = parseSPARQL(data); + if (parsedData.length === 0) return null; + const [processLabelObject] = parsedData; + const { process_label: processLabel } = processLabelObject; + return processLabel; }, - parseMaterialData (data) { - if (!data) return null - const parsedData = parseSPARQL(data) - if (parsedData.length === 0) return null - const seen = new Set() + parseMaterialData(data) { + if (!data) return null; + const parsedData = parseSPARQL(data); + if (parsedData.length === 0) return null; + const seen = new Set(); const filteredArr = parsedData .filter((item) => { - const duplicate = seen.has(item.std_name) - seen.add(item.std_name) - return !duplicate + const duplicate = seen.has(item.std_name); + seen.add(item.std_name); + return !duplicate; }) .map((item) => { return { class: item.std_name, - role: item.role - } - }) + role: item.role, + }; + }); filteredArr.forEach((element) => { const materialProperties = parsedData .filter((item) => item.std_name === element.class) .map((item) => { - const { attrUnits, attrValue: value, attrType } = item - const units = attrUnits || '' + const { attrUnits, attrValue: value, attrType } = item; + const units = attrUnits || ""; const type = attrType - .split('/') + .split("/") .pop() .match(/[A-Z][a-z]+|[0-9]+/g) - .join(' ') + .join(" "); return { type, units, - value - } - }) - element.materialProperties = materialProperties - }) - return filteredArr + value, + }; + }); + element.materialProperties = materialProperties; + }); + return filteredArr; }, - parseCuratedProperties (data) { - if (!data) return null - const parseData = parseSPARQL(data) - if (parseData.length === 0) return null - if (!parseData.length) return null + parseCuratedProperties(data) { + if (!data) return null; + const parseData = parseSPARQL(data); + if (parseData.length === 0) return null; + if (!parseData.length) return null; const curatedProperties = parseData.map((property) => { - const { AttrType, value, Units: units } = property - const type = AttrType.split('/') + const { AttrType, value, Units: units } = property; + const type = AttrType.split("/") .pop() .match(/[A-Z][a-z]+|[0-9]+/g) - .join(' ') + .join(" "); return { type, units, - value - } - }) - return curatedProperties + value, + }; + }); + return curatedProperties; }, - parseProcessingSteps (data) { - if (!data) return null - const parsedData = parseSPARQL(data) - if (parsedData.length === 0) return null + parseProcessingSteps(data) { + if (!data) return null; + const parsedData = parseSPARQL(data); + if (parsedData.length === 0) return null; const steps = parsedData.map( ({ param_label: parameterLabel, Descr: description }) => { - return { parameterLabel, description } + return { parameterLabel, description }; } - ) - return steps + ); + return steps; }, - parseSampleImages (data) { - console.log(data) - if (!data) return null - const parsedData = parseSPARQL(data) - if (parsedData.length === 0) return null + parseSampleImages(data) { + if (!data) return null; + const parsedData = parseSPARQL(data); + if (parsedData.length === 0) return null; const images = parsedData.map((item) => { - return { src: item.image, alt: item.sample } - }) - return images + return { src: item.image, alt: item.sample }; + }); + return images; }, - async fetchSamplePageData () { - this.loading = true + async fetchSamplePageData() { + this.loading = true; await Promise.allSettled([ this.fetchData(sampleQueries.materialComponents), this.fetchData(sampleQueries.curatedProperties), @@ -134,14 +133,14 @@ export default { this.fetchData(sampleQueries.processingSteps), this.fetchData(sampleQueries.sampleImages), this.fetchData(sampleQueries.otherSamples), - this.fetchData(sampleQueries.header) + this.fetchData(sampleQueries.header), ]) .then((res) => { const data = res.map((promise) => { - if (promise.status === 'fulfilled') return promise.value - console.error(promise.reason) - return null - }) + if (promise.status === "fulfilled") return promise.value; + console.error(promise.reason); + return null; + }); const [ materialComponents, curatedProperties, @@ -149,26 +148,26 @@ export default { processingSteps, sampleImages, otherSamples, - header - ] = data - this.materialComponents = this.parseMaterialData(materialComponents) + header, + ] = data; + this.materialComponents = this.parseMaterialData(materialComponents); this.curatedProperties = - this.parseCuratedProperties(curatedProperties) - this.processLabel = this.parseProcessLabel(processLabel) - this.processingSteps = this.parseProcessingSteps(processingSteps) - this.sampleImages = this.parseSampleImages(sampleImages) - this.otherSamples = this.parseOtherSamples(otherSamples) - this.header = this.parseHeader(header) - this.loading = false + this.parseCuratedProperties(curatedProperties); + this.processLabel = this.parseProcessLabel(processLabel); + this.processingSteps = this.parseProcessingSteps(processingSteps); + this.sampleImages = this.parseSampleImages(sampleImages); + this.otherSamples = this.parseOtherSamples(otherSamples); + this.header = this.parseHeader(header); + this.loading = false; }) - .catch((e) => console.error(e)) - } + .catch((e) => console.error(e)); + }, }, watch: { - $route: 'fetchSamplePageData' + $route: "fetchSamplePageData", + }, + created() { + this.fetchSamplePageData(); }, - created () { - this.fetchSamplePageData() - } -} +}; From e5eca029e288c1efd2b132e7b4a656516ce1618e Mon Sep 17 00:00:00 2001 From: Kevin Zuniga Cuellar Date: Tue, 22 Feb 2022 13:00:57 -0500 Subject: [PATCH 155/306] #113: fix linting errors --- app/src/pages/explorer/sample/sample.js | 202 ++++++++++++------------ 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/app/src/pages/explorer/sample/sample.js b/app/src/pages/explorer/sample/sample.js index 684e6584..6f7d6294 100644 --- a/app/src/pages/explorer/sample/sample.js +++ b/app/src/pages/explorer/sample/sample.js @@ -1,13 +1,13 @@ -import { querySparql, parseSPARQL } from "@/modules/sparql"; -import sampleQueries from "@/modules/queries/sampleQueries"; -import Spinner from "@/components/Spinner"; +import { querySparql, parseSPARQL } from '@/modules/sparql' +import sampleQueries from '@/modules/queries/sampleQueries' +import Spinner from '@/components/Spinner' export default { - name: "SampleView", + name: 'SampleView', components: { - Spinner, + Spinner }, - data() { + data () { return { header: null, materialComponents: null, @@ -16,116 +16,116 @@ export default { processingSteps: null, sampleImages: null, otherSamples: null, - loading: false, - }; + loading: false + } }, methods: { - async fetchData(query) { - const sampleId = this.$route.params.label; - return await querySparql(query(sampleId)); + async fetchData (query) { + const sampleId = this.$route.params.label + return await querySparql(query(sampleId)) }, - parseHeader(data) { - if (!data) return null; - const parsedData = parseSPARQL(data); - if (parsedData.length === 0) return null; - const [sampleData] = parsedData; - return sampleData; + parseHeader (data) { + if (!data) return null + const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null + const [sampleData] = parsedData + return sampleData }, - parseOtherSamples(data) { - if (!data) return null; - const parsedData = parseSPARQL(data); - if (parsedData.length === 0) return null; - const links = parsedData.map(({ sample }) => sample.split("/").pop()); - return links; + parseOtherSamples (data) { + if (!data) return null + const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null + const links = parsedData.map(({ sample }) => sample.split('/').pop()) + return links }, - parseProcessLabel(data) { - if (!data) return null; - const parsedData = parseSPARQL(data); - if (parsedData.length === 0) return null; - const [processLabelObject] = parsedData; - const { process_label: processLabel } = processLabelObject; - return processLabel; + parseProcessLabel (data) { + if (!data) return null + const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null + const [processLabelObject] = parsedData + const { process_label: processLabel } = processLabelObject + return processLabel }, - parseMaterialData(data) { - if (!data) return null; - const parsedData = parseSPARQL(data); - if (parsedData.length === 0) return null; - const seen = new Set(); + parseMaterialData (data) { + if (!data) return null + const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null + const seen = new Set() const filteredArr = parsedData .filter((item) => { - const duplicate = seen.has(item.std_name); - seen.add(item.std_name); - return !duplicate; + const duplicate = seen.has(item.std_name) + seen.add(item.std_name) + return !duplicate }) .map((item) => { return { class: item.std_name, - role: item.role, - }; - }); + role: item.role + } + }) filteredArr.forEach((element) => { const materialProperties = parsedData .filter((item) => item.std_name === element.class) .map((item) => { - const { attrUnits, attrValue: value, attrType } = item; - const units = attrUnits || ""; + const { attrUnits, attrValue: value, attrType } = item + const units = attrUnits || '' const type = attrType - .split("/") + .split('/') .pop() .match(/[A-Z][a-z]+|[0-9]+/g) - .join(" "); + .join(' ') return { type, units, - value, - }; - }); - element.materialProperties = materialProperties; - }); - return filteredArr; + value + } + }) + element.materialProperties = materialProperties + }) + return filteredArr }, - parseCuratedProperties(data) { - if (!data) return null; - const parseData = parseSPARQL(data); - if (parseData.length === 0) return null; - if (!parseData.length) return null; + parseCuratedProperties (data) { + if (!data) return null + const parseData = parseSPARQL(data) + if (parseData.length === 0) return null + if (!parseData.length) return null const curatedProperties = parseData.map((property) => { - const { AttrType, value, Units: units } = property; - const type = AttrType.split("/") + const { AttrType, value, Units: units } = property + const type = AttrType.split('/') .pop() .match(/[A-Z][a-z]+|[0-9]+/g) - .join(" "); + .join(' ') return { type, units, - value, - }; - }); - return curatedProperties; + value + } + }) + return curatedProperties }, - parseProcessingSteps(data) { - if (!data) return null; - const parsedData = parseSPARQL(data); - if (parsedData.length === 0) return null; + parseProcessingSteps (data) { + if (!data) return null + const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null const steps = parsedData.map( ({ param_label: parameterLabel, Descr: description }) => { - return { parameterLabel, description }; + return { parameterLabel, description } } - ); - return steps; + ) + return steps }, - parseSampleImages(data) { - if (!data) return null; - const parsedData = parseSPARQL(data); - if (parsedData.length === 0) return null; + parseSampleImages (data) { + if (!data) return null + const parsedData = parseSPARQL(data) + if (parsedData.length === 0) return null const images = parsedData.map((item) => { - return { src: item.image, alt: item.sample }; - }); - return images; + return { src: item.image, alt: item.sample } + }) + return images }, - async fetchSamplePageData() { - this.loading = true; + async fetchSamplePageData () { + this.loading = true await Promise.allSettled([ this.fetchData(sampleQueries.materialComponents), this.fetchData(sampleQueries.curatedProperties), @@ -133,14 +133,14 @@ export default { this.fetchData(sampleQueries.processingSteps), this.fetchData(sampleQueries.sampleImages), this.fetchData(sampleQueries.otherSamples), - this.fetchData(sampleQueries.header), + this.fetchData(sampleQueries.header) ]) .then((res) => { const data = res.map((promise) => { - if (promise.status === "fulfilled") return promise.value; - console.error(promise.reason); - return null; - }); + if (promise.status === 'fulfilled') return promise.value + console.error(promise.reason) + return null + }) const [ materialComponents, curatedProperties, @@ -148,26 +148,26 @@ export default { processingSteps, sampleImages, otherSamples, - header, - ] = data; - this.materialComponents = this.parseMaterialData(materialComponents); + header + ] = data + this.materialComponents = this.parseMaterialData(materialComponents) this.curatedProperties = - this.parseCuratedProperties(curatedProperties); - this.processLabel = this.parseProcessLabel(processLabel); - this.processingSteps = this.parseProcessingSteps(processingSteps); - this.sampleImages = this.parseSampleImages(sampleImages); - this.otherSamples = this.parseOtherSamples(otherSamples); - this.header = this.parseHeader(header); - this.loading = false; + this.parseCuratedProperties(curatedProperties) + this.processLabel = this.parseProcessLabel(processLabel) + this.processingSteps = this.parseProcessingSteps(processingSteps) + this.sampleImages = this.parseSampleImages(sampleImages) + this.otherSamples = this.parseOtherSamples(otherSamples) + this.header = this.parseHeader(header) + this.loading = false }) - .catch((e) => console.error(e)); - }, + .catch((e) => console.error(e)) + } }, watch: { - $route: "fetchSamplePageData", - }, - created() { - this.fetchSamplePageData(); + $route: 'fetchSamplePageData' }, -}; + created () { + this.fetchSamplePageData() + } +} From c8fec5a3d50bdd3747b749ccb8af46ccddb7e63c Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Thu, 24 Feb 2022 16:47:49 -0800 Subject: [PATCH 156/306] #123: Consolidate exports in sparql.js --- app/src/modules/sparql.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/modules/sparql.js b/app/src/modules/sparql.js index 4a8f45aa..3340bf3a 100644 --- a/app/src/modules/sparql.js +++ b/app/src/modules/sparql.js @@ -17,9 +17,7 @@ async function querySparql (query, endpoint = SPARQL_ENDPOINT) { .catch((err) => console.log(err)) } -export { querySparql } - -export function parseSPARQL (response) { +function parseSPARQL (response) { const queryResults = [] for (let i = 0; i < response.results.bindings.length; i++) { const newObject = {} @@ -38,3 +36,5 @@ export function parseSPARQL (response) { return queryResults } + +export { querySparql, parseSPARQL } From 27bb3b368f04266023f093c686995aaf32531afb Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Thu, 24 Feb 2022 16:53:55 -0800 Subject: [PATCH 157/306] #123: Modify sparql capitalization to match existing pattern --- app/src/modules/sparql.js | 4 ++-- app/src/pages/explorer/sample/sample.js | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/modules/sparql.js b/app/src/modules/sparql.js index 3340bf3a..6bd8df54 100644 --- a/app/src/modules/sparql.js +++ b/app/src/modules/sparql.js @@ -17,7 +17,7 @@ async function querySparql (query, endpoint = SPARQL_ENDPOINT) { .catch((err) => console.log(err)) } -function parseSPARQL (response) { +function parseSparql (response) { const queryResults = [] for (let i = 0; i < response.results.bindings.length; i++) { const newObject = {} @@ -37,4 +37,4 @@ function parseSPARQL (response) { return queryResults } -export { querySparql, parseSPARQL } +export { querySparql, parseSparql } diff --git a/app/src/pages/explorer/sample/sample.js b/app/src/pages/explorer/sample/sample.js index 6f7d6294..a8b069fa 100644 --- a/app/src/pages/explorer/sample/sample.js +++ b/app/src/pages/explorer/sample/sample.js @@ -1,4 +1,4 @@ -import { querySparql, parseSPARQL } from '@/modules/sparql' +import { querySparql, parseSparql } from '@/modules/sparql' import sampleQueries from '@/modules/queries/sampleQueries' import Spinner from '@/components/Spinner' @@ -26,21 +26,21 @@ export default { }, parseHeader (data) { if (!data) return null - const parsedData = parseSPARQL(data) + const parsedData = parseSparql(data) if (parsedData.length === 0) return null const [sampleData] = parsedData return sampleData }, parseOtherSamples (data) { if (!data) return null - const parsedData = parseSPARQL(data) + const parsedData = parseSparql(data) if (parsedData.length === 0) return null const links = parsedData.map(({ sample }) => sample.split('/').pop()) return links }, parseProcessLabel (data) { if (!data) return null - const parsedData = parseSPARQL(data) + const parsedData = parseSparql(data) if (parsedData.length === 0) return null const [processLabelObject] = parsedData const { process_label: processLabel } = processLabelObject @@ -48,7 +48,7 @@ export default { }, parseMaterialData (data) { if (!data) return null - const parsedData = parseSPARQL(data) + const parsedData = parseSparql(data) if (parsedData.length === 0) return null const seen = new Set() const filteredArr = parsedData @@ -87,7 +87,7 @@ export default { }, parseCuratedProperties (data) { if (!data) return null - const parseData = parseSPARQL(data) + const parseData = parseSparql(data) if (parseData.length === 0) return null if (!parseData.length) return null const curatedProperties = parseData.map((property) => { @@ -106,7 +106,7 @@ export default { }, parseProcessingSteps (data) { if (!data) return null - const parsedData = parseSPARQL(data) + const parsedData = parseSparql(data) if (parsedData.length === 0) return null const steps = parsedData.map( ({ param_label: parameterLabel, Descr: description }) => { @@ -117,7 +117,7 @@ export default { }, parseSampleImages (data) { if (!data) return null - const parsedData = parseSPARQL(data) + const parsedData = parseSparql(data) if (parsedData.length === 0) return null const images = parsedData.map((item) => { return { src: item.image, alt: item.sample } From 97f9f65a1ff186ab80c6a4390ae02630cc8fc543 Mon Sep 17 00:00:00 2001 From: Rory Schadler <48921090+roryschadler@users.noreply.github.com> Date: Thu, 24 Feb 2022 20:10:09 -0500 Subject: [PATCH 158/306] #28: Link MM/teams to teams page (#122) * #28: Link MM/teams to teams page * #28: Update reference to about, how, news --- app/src/components/Drawer.vue | 6 +++--- app/src/pages/metamine/Base.vue | 2 +- app/src/router/module/metamine.js | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/components/Drawer.vue b/app/src/components/Drawer.vue index 9826571e..8bb74377 100644 --- a/app/src/components/Drawer.vue +++ b/app/src/components/Drawer.vue @@ -21,13 +21,13 @@ groups About - + About Us - + How To - + Research + News diff --git a/app/src/pages/metamine/Base.vue b/app/src/pages/metamine/Base.vue index 39667333..33d458cf 100644 --- a/app/src/pages/metamine/Base.vue +++ b/app/src/pages/metamine/Base.vue @@ -10,7 +10,7 @@
      - ABOUT + ABOUT VISUALIZE TOOLS CONTACT diff --git a/app/src/router/module/metamine.js b/app/src/router/module/metamine.js index 30023511..31448edd 100644 --- a/app/src/router/module/metamine.js +++ b/app/src/router/module/metamine.js @@ -4,6 +4,12 @@ const metamineRoutes = [ name: 'HomeMM', component: () => import(/* webpackChunkName: "homemm" */ '@/pages/metamine/Home.vue'), meta: { requiresAuth: false } + }, + { + path: 'teams', + name: 'Teams', + component: () => import(/* webpackChunkName: "about" */ '@/pages/nanomine/teams/Teams.vue'), + meta: { requiresAuth: false } } ] From 8933fe7c640dc25527dc200fd379b6f91937b273 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Thu, 24 Feb 2022 17:17:50 -0800 Subject: [PATCH 159/306] #123: Merge parseSparql and transformSparqlData into a single function --- app/src/modules/sparql.js | 25 +++++++++++++------------ app/src/modules/vega-chart.js | 24 ++---------------------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/app/src/modules/sparql.js b/app/src/modules/sparql.js index 6bd8df54..2aacd0b3 100644 --- a/app/src/modules/sparql.js +++ b/app/src/modules/sparql.js @@ -1,3 +1,6 @@ +import { literal, namedNode } from '@rdfjs/data-model' +import { fromRdf } from 'rdf-literal' + const SPARQL_ENDPOINT = 'https://materialsmine.org/wi/sparql' async function querySparql (query, endpoint = SPARQL_ENDPOINT) { @@ -19,21 +22,19 @@ async function querySparql (query, endpoint = SPARQL_ENDPOINT) { function parseSparql (response) { const queryResults = [] - for (let i = 0; i < response.results.bindings.length; i++) { - const newObject = {} - const row = response.results.bindings[i] - for (const variable of response.head.vars) { - if (row !== undefined && row[variable] !== undefined && row[variable]) { - if (!isNaN(row[variable].value)) { - newObject[variable] = +row[variable].value - } else { - newObject[variable] = row[variable].value + if (response) { + for (const row of response.results.bindings) { + const rowData = {} + queryResults.push(rowData) + Object.entries(row).forEach(([field, result, t]) => { + let value = result.value + if (result.type === 'literal' && result.datatype) { + value = fromRdf(literal(value, namedNode(result.datatype))) } - queryResults[i] = newObject - } + rowData[field] = value + }) } } - return queryResults } diff --git a/app/src/modules/vega-chart.js b/app/src/modules/vega-chart.js index 40bec29a..cd40d460 100644 --- a/app/src/modules/vega-chart.js +++ b/app/src/modules/vega-chart.js @@ -1,6 +1,4 @@ -import { literal, namedNode } from '@rdfjs/data-model' -import { fromRdf } from 'rdf-literal' -import { querySparql } from '@/modules/sparql' +import { querySparql, parseSparql } from '@/modules/sparql' const defaultQuery = ` PREFIX rdfs: @@ -86,30 +84,12 @@ async function readChartSparqlRow (chartResult) { return chart } -function transformSparqlData (sparqlResults) { - const data = [] - if (sparqlResults) { - for (const row of sparqlResults.results.bindings) { - const resultData = {} - data.push(resultData) - Object.entries(row).forEach(([field, result, t]) => { - let value = result.value - if (result.type === 'literal' && result.datatype) { - value = fromRdf(literal(value, namedNode(result.datatype))) - } - resultData[field] = value - }) - } - } - return data -} - function buildSparqlSpec (baseSpec, sparqlResults) { if (!baseSpec) { return null } const spec = Object.assign({}, baseSpec) - spec.data = { values: transformSparqlData(sparqlResults) } + spec.data = { values: parseSparql(sparqlResults) } return spec } From 2b07137d91ddd58af7ce1eda5b326775d930c5c0 Mon Sep 17 00:00:00 2001 From: Sam Stouffer Date: Thu, 10 Feb 2022 17:43:27 -0500 Subject: [PATCH 160/306] #61: Add gallery page --- app/src/assets/css/base/_grid.scss | 3 +- app/src/assets/css/modules/_utility.scss | 62 ++++++ app/src/assets/img/rdf_flyer.svg | 18 ++ app/src/components/explorer/Pagination.vue | 112 +++++++++++ app/src/components/spinner.vue | 90 +++++++++ app/src/pages/explorer/Gallery.vue | 183 ++++++++++++++++++ app/src/router/module/explorer.js | 1 + .../store/modules/explorer/gallery/actions.js | 23 +++ .../store/modules/explorer/gallery/getters.js | 17 ++ .../store/modules/explorer/gallery/index.js | 18 ++ .../modules/explorer/gallery/mutations.js | 11 ++ app/src/store/modules/explorer/index.js | 5 + app/tests/jest/script/wrapper.js | 7 +- .../components/explorer/Pagination.spec.js | 71 +++++++ app/tests/unit/pages/explorer/Gallery.spec.js | 45 +++++ 15 files changed, 663 insertions(+), 3 deletions(-) create mode 100644 app/src/assets/img/rdf_flyer.svg create mode 100644 app/src/components/explorer/Pagination.vue create mode 100644 app/src/components/spinner.vue create mode 100644 app/src/pages/explorer/Gallery.vue create mode 100644 app/src/store/modules/explorer/gallery/actions.js create mode 100644 app/src/store/modules/explorer/gallery/getters.js create mode 100644 app/src/store/modules/explorer/gallery/index.js create mode 100644 app/src/store/modules/explorer/gallery/mutations.js create mode 100644 app/tests/unit/components/explorer/Pagination.spec.js create mode 100644 app/tests/unit/pages/explorer/Gallery.spec.js diff --git a/app/src/assets/css/base/_grid.scss b/app/src/assets/css/base/_grid.scss index b3fab7d1..fcb1e8c4 100644 --- a/app/src/assets/css/base/_grid.scss +++ b/app/src/assets/css/base/_grid.scss @@ -1,3 +1,4 @@ +@import "@/assets/css/abstract/_mixins"; .grid { display: grid; @@ -51,4 +52,4 @@ grid-template-columns: 2fr 1fr; } } -} \ No newline at end of file +} diff --git a/app/src/assets/css/modules/_utility.scss b/app/src/assets/css/modules/_utility.scss index f74ec9f6..cc31f0b2 100644 --- a/app/src/assets/css/modules/_utility.scss +++ b/app/src/assets/css/modules/_utility.scss @@ -1,3 +1,4 @@ +@import '@/assets/css/abstract/_variables.scss'; .wrapper { padding-left: 1.1875rem; padding-right: 1.1875rem; @@ -166,7 +167,68 @@ height: 12rem; } } + &_gridicon { + position: absolute; + right: .3rem; + z-index: 10000000; + & > div { + display: inline-block; + + & > i { + font-size: 1rem !important; + cursor: pointer; + } + } + & > div:hover{ + background-color: $primary-light; + & > i { + color: $primary !important; + } + } + + &-single{ + position: absolute; + right: .05rem; + z-index: 10000000; + top: .05rem; + @include respond(tab-land){ + top: .2rem; + right: .3rem; + } + + & > div { + display: inline-block; + } + } + } + &_show_hide { + & > span.md-body-1 { + display: none !important; + visibility: hidden !important; + transition: all 3s ease-in-out; + } + + &:hover { + & > span.md-body-1 { + display: block !important; + visibility: visible !important; + } + } + } + &_content__result { + font-size: .8rem; + color: lightslategray; + margin: 0 0 .5rem 0; + padding: .6rem; + } + &_color { + color: $primary !important + } + &_gridbg { + background-color: rgba($primary-black, 0.7) !important; + border: 1px solid $primary !important; + } } .dialog-box { diff --git a/app/src/assets/img/rdf_flyer.svg b/app/src/assets/img/rdf_flyer.svg new file mode 100644 index 00000000..0a674695 --- /dev/null +++ b/app/src/assets/img/rdf_flyer.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/components/explorer/Pagination.vue b/app/src/components/explorer/Pagination.vue new file mode 100644 index 00000000..886361e3 --- /dev/null +++ b/app/src/components/explorer/Pagination.vue @@ -0,0 +1,112 @@ + + + diff --git a/app/src/components/spinner.vue b/app/src/components/spinner.vue new file mode 100644 index 00000000..f4dde245 --- /dev/null +++ b/app/src/components/spinner.vue @@ -0,0 +1,90 @@ + + + diff --git a/app/src/pages/explorer/Gallery.vue b/app/src/pages/explorer/Gallery.vue new file mode 100644 index 00000000..b9292c15 --- /dev/null +++ b/app/src/pages/explorer/Gallery.vue @@ -0,0 +1,183 @@ + + + diff --git a/app/src/router/module/explorer.js b/app/src/router/module/explorer.js index 522dd3fe..321e0462 100644 --- a/app/src/router/module/explorer.js +++ b/app/src/router/module/explorer.js @@ -31,6 +31,7 @@ const explorerRoutes = [ { path: '', name: 'ChartGallery', + component: () => import('@/pages/explorer/Gallery.vue'), meta: { requiresAuth: false } }, { diff --git a/app/src/store/modules/explorer/gallery/actions.js b/app/src/store/modules/explorer/gallery/actions.js new file mode 100644 index 00000000..2cd1c79c --- /dev/null +++ b/app/src/store/modules/explorer/gallery/actions.js @@ -0,0 +1,23 @@ +const placeholderDesc = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' +export default { + async loadItems ({commit, getters}, {page=1} = {}) { + // Loads dummy items for now + if (page < 1 || page > 1 && page > getters.totalPages) { + throw `Invalid Page Number: ${page}. Must be number from 1 to ${getters.totalPages}` + } + const startIndex = (page - 1) * getters.pageSize + const total = 333 + const items = [...Array(getters.pageSize).keys()] + .map(i => i + startIndex + 1) + .filter(i => i <= total) + .map(i => ({ + id: `gallery_item_${i}`, + label: `Gallery Item #${i}: ${placeholderDesc.slice(0, Math.random()*50)}`, + description: placeholderDesc.slice(0, Math.random()*placeholderDesc.length) + })) + + commit('setPage', page) + commit('setTotal', total) + commit('setItems', items) + } +} diff --git a/app/src/store/modules/explorer/gallery/getters.js b/app/src/store/modules/explorer/gallery/getters.js new file mode 100644 index 00000000..7628d57b --- /dev/null +++ b/app/src/store/modules/explorer/gallery/getters.js @@ -0,0 +1,17 @@ +export default { + items (state) { + return state.items + }, + pageSize (state) { + return state.pageSize + }, + page (state) { + return state.page + }, + total (state) { + return state.total + }, + totalPages (state, getters) { + return Math.ceil(getters.total / getters.pageSize) + } +} diff --git a/app/src/store/modules/explorer/gallery/index.js b/app/src/store/modules/explorer/gallery/index.js new file mode 100644 index 00000000..0904ca62 --- /dev/null +++ b/app/src/store/modules/explorer/gallery/index.js @@ -0,0 +1,18 @@ +import mutations from './mutations.js' +import actions from './actions.js' +import getters from './getters.js' + +export default { + namespaced: true, + state () { + return { + items: null, + pageSize: 50, + page: 1, + total: null + } + }, + mutations, + actions, + getters +} diff --git a/app/src/store/modules/explorer/gallery/mutations.js b/app/src/store/modules/explorer/gallery/mutations.js new file mode 100644 index 00000000..1c9067e8 --- /dev/null +++ b/app/src/store/modules/explorer/gallery/mutations.js @@ -0,0 +1,11 @@ +export default { + setItems (state, items) { + state.items = items + }, + setPage (state, page) { + state.page = page + }, + setTotal (state, total) { + state.total = total + } +} diff --git a/app/src/store/modules/explorer/index.js b/app/src/store/modules/explorer/index.js index 6c5f65af..dff2c59e 100644 --- a/app/src/store/modules/explorer/index.js +++ b/app/src/store/modules/explorer/index.js @@ -2,8 +2,13 @@ import mutations from './mutations.js' import actions from './actions.js' import getters from './getters.js' +import gallery from './gallery' + export default { namespaced: true, + modules: { + gallery, + }, state () { return { toggleMenuVisibility: false, diff --git a/app/tests/jest/script/wrapper.js b/app/tests/jest/script/wrapper.js index c351e2a4..3162f927 100644 --- a/app/tests/jest/script/wrapper.js +++ b/app/tests/jest/script/wrapper.js @@ -2,7 +2,7 @@ import _ from 'lodash' import VueMaterial from 'vue-material' import store from '@/store' import router from '@/router' -import { mount, createLocalVue, shallowMount } from '@vue/test-utils' +import { mount, createLocalVue, shallowMount, RouterLinkStub } from '@vue/test-utils' /** Add external plugins as needed */ const localVue = createLocalVue() @@ -25,7 +25,10 @@ function createWrapper (component, overrides, useMount = true) { router, store, propsData: _.merge({}, overrides.props), - slots: _.merge({}, overrides.slots) + slots: _.merge({}, overrides.slots), + stubs: { + RouterLink: RouterLinkStub + } } return mountType(component, defaultMountOptions) } diff --git a/app/tests/unit/components/explorer/Pagination.spec.js b/app/tests/unit/components/explorer/Pagination.spec.js new file mode 100644 index 00000000..f66f4c9f --- /dev/null +++ b/app/tests/unit/components/explorer/Pagination.spec.js @@ -0,0 +1,71 @@ +import createWrapper from '../../../jest/script/wrapper' +import { enableAutoDestroy, RouterLinkStub } from '@vue/test-utils' +import Pagination from '@/components/explorer/Pagination.vue' + +describe('Pagination.vue', () => { + + const defaultProps = { + cpage: 1, + tpages: 4, + } + + let wrapper + beforeEach(() => { + if (wrapper) { + wrapper.destroy() + } + wrapper = createWrapper(Pagination, {props:defaultProps}, true) + }) + + enableAutoDestroy(afterEach) + + it("disables home and prev on page 1", () => { + expect(wrapper.find('.pagination-button-home').attributes("disabled")).toBe("disabled") + expect(wrapper.find('.pagination-button-prev').attributes("disabled")).toBe("disabled") + }) + + it("disables next and end on last page", async () => { + await wrapper.setProps({cpage: defaultProps.tpages}) + expect(wrapper.find('.pagination-button-next').attributes("disabled")).toBe("disabled") + expect(wrapper.find('.pagination-button-end').attributes("disabled")).toBe("disabled") + }) + + it("goes to page one when home is clicked", async () => { + await wrapper.setProps({cpage: 2}) + const button = wrapper.find('.pagination-button-home') + expect(button.attributes("disabled")).toBeUndefined() + await button.trigger('click') + const pageEvent = wrapper.emitted('go-to-page') + expect(pageEvent.length).toBe(1) + expect(pageEvent[0][0]).toBe(1) + }) + + it("goes to the prev page when prev is clicked", async () => { + const page = 3 + await wrapper.setProps({cpage: page}) + const button = wrapper.find('.pagination-button-prev') + expect(button.attributes("disabled")).toBeUndefined() + await button.trigger('click') + const pageEvent = wrapper.emitted('go-to-page') + expect(pageEvent.length).toBe(1) + expect(pageEvent[0][0]).toBe(page - 1) + }) + + it("goes to the next page when next is clicked", async () => { + const button = wrapper.find('.pagination-button-next') + expect(button.attributes("disabled")).toBeUndefined() + await button.trigger('click') + const pageEvent = wrapper.emitted('go-to-page') + expect(pageEvent.length).toBe(1) + expect(pageEvent[0][0]).toBe(2) + }) + + it("goes to the last page when end is clicked", async () => { + const button = wrapper.find('.pagination-button-end') + expect(button.attributes("disabled")).toBeUndefined() + await button.trigger('click') + const pageEvent = wrapper.emitted('go-to-page') + expect(pageEvent.length).toBe(1) + expect(pageEvent[0][0]).toBe(defaultProps.tpages) + }) +}) diff --git a/app/tests/unit/pages/explorer/Gallery.spec.js b/app/tests/unit/pages/explorer/Gallery.spec.js new file mode 100644 index 00000000..fcc46309 --- /dev/null +++ b/app/tests/unit/pages/explorer/Gallery.spec.js @@ -0,0 +1,45 @@ +import createWrapper from '../../../jest/script/wrapper' +import { enableAutoDestroy, RouterLinkStub } from '@vue/test-utils' +import ExplorerGallery from '@/pages/explorer/Gallery.vue' + +describe('ExplorerHome.vue', () => { + const itemsPerPage = 50 + let wrapper + beforeEach(() => { + wrapper = createWrapper(ExplorerGallery, {}, true) + }) + + enableAutoDestroy(afterEach) + + it(`loads ${itemsPerPage} items`, () => { + expect.assertions(1) + expect(wrapper.findAll('.gallery-item').length).toBe(itemsPerPage) + }) + + it("shows number of results", () => { + expect.assertions(1) + expect(wrapper.find(".u_content__result").text()).toMatch(/^About [1-9]\d* results/) + }) + + it("provides links for each result", () => { + const items = wrapper.vm.items + expect.assertions(items.length) + console.log(items.length) + for (let item of items) { + expect( + wrapper.findAllComponents(RouterLinkStub) + .filter(w => w.props().to === `/explorer/chart/view/${item.id}`) + .at(0) + .exists() + ).toBe(true) + } + }) + + it("paginates gallery items", async () => { + const initialItemId = wrapper.vm.items[0].id + await wrapper.find('.pagination-button-next') + .trigger('click') + const newItemId = wrapper.vm.items[0].id + expect(newItemId).not.toEqual(initialItemId) + }) +}) From 73f048dba1f6994be1b0ec636abe12b27b6a8c4c Mon Sep 17 00:00:00 2001 From: Sam Stouffer Date: Thu, 17 Feb 2022 15:17:57 -0500 Subject: [PATCH 161/306] remove duplicate spinner component --- app/src/components/spinner.vue | 90 ------------------------------ app/src/pages/explorer/Gallery.vue | 2 +- 2 files changed, 1 insertion(+), 91 deletions(-) delete mode 100644 app/src/components/spinner.vue diff --git a/app/src/components/spinner.vue b/app/src/components/spinner.vue deleted file mode 100644 index f4dde245..00000000 --- a/app/src/components/spinner.vue +++ /dev/null @@ -1,90 +0,0 @@ - - - diff --git a/app/src/pages/explorer/Gallery.vue b/app/src/pages/explorer/Gallery.vue index b9292c15..69e56dda 100644 --- a/app/src/pages/explorer/Gallery.vue +++ b/app/src/pages/explorer/Gallery.vue @@ -82,7 +82,7 @@
      - From 774e66418567eed3564738b7b2cd0541f5fbf4fd Mon Sep 17 00:00:00 2001 From: Sam Stouffer Date: Thu, 17 Feb 2022 15:42:25 -0500 Subject: [PATCH 163/306] fix lint errors --- app/src/components/explorer/Pagination.vue | 4 +- app/src/pages/explorer/Gallery.vue | 9 ++-- .../store/modules/explorer/gallery/actions.js | 10 ++--- app/src/store/modules/explorer/index.js | 2 +- .../components/explorer/Pagination.spec.js | 41 +++++++++---------- app/tests/unit/pages/explorer/Gallery.spec.js | 10 ++--- 6 files changed, 37 insertions(+), 39 deletions(-) diff --git a/app/src/components/explorer/Pagination.vue b/app/src/components/explorer/Pagination.vue index 0382086b..8433f34b 100644 --- a/app/src/components/explorer/Pagination.vue +++ b/app/src/components/explorer/Pagination.vue @@ -30,11 +30,11 @@ export default { name: 'pagination', props: { cpage: Number, - tpages: Number, + tpages: Number }, methods: { goToPage (page) { - if (page != this.cpage) { + if (page !== this.cpage) { this.$emit('go-to-page', page) } }, diff --git a/app/src/pages/explorer/Gallery.vue b/app/src/pages/explorer/Gallery.vue index 69e56dda..11a8b4f4 100644 --- a/app/src/pages/explorer/Gallery.vue +++ b/app/src/pages/explorer/Gallery.vue @@ -117,11 +117,10 @@ export default { methods: { ...mapActions('explorer/gallery', ['loadItems']), reduceDescription (args) { - let arr, arrSplice, res - arr = args.split(' ') + const arr = args.split(' ') arr.splice(15) - arrSplice = arr.reduce((a, b) => `${a} ${b}`, '') - res = arrSplice.normalize('NFD').replace(/[\u0300-\u036f]/g, '') + const arrSplice = arr.reduce((a, b) => `${a} ${b}`, '') + const res = arrSplice.normalize('NFD').replace(/[\u0300-\u036f]/g, '') return `${res}...` }, deleteChart (chart) { @@ -135,7 +134,7 @@ export default { }, async mounted () { await this.loadItems() - }, + } } diff --git a/app/src/components/nanomine/PageHeader.vue b/app/src/components/nanomine/PageHeader.vue index c799f15e..b8fb3f7d 100644 --- a/app/src/components/nanomine/PageHeader.vue +++ b/app/src/components/nanomine/PageHeader.vue @@ -80,10 +80,10 @@ diff --git a/app/src/components/nanomine/ReferenceContainer.vue b/app/src/components/nanomine/ReferenceContainer.vue new file mode 100644 index 00000000..5b1222f3 --- /dev/null +++ b/app/src/components/nanomine/ReferenceContainer.vue @@ -0,0 +1,53 @@ + + + + diff --git a/app/src/components/nanomine/SmilesCanvas.vue b/app/src/components/nanomine/SmilesCanvas.vue new file mode 100644 index 00000000..2a22e4c1 --- /dev/null +++ b/app/src/components/nanomine/SmilesCanvas.vue @@ -0,0 +1,163 @@ + +/* + Uses code from: https://github.com/reymond-group/smilesDrawer + TODO: overrides for theme and computeOnly do not seem to be working and removed from sample +*/ + diff --git a/app/src/components/nanomine/ToolCard.vue b/app/src/components/nanomine/ToolCard.vue new file mode 100644 index 00000000..adade234 --- /dev/null +++ b/app/src/components/nanomine/ToolCard.vue @@ -0,0 +1,58 @@ + + + diff --git a/app/src/modules/JobMgr.js b/app/src/modules/JobMgr.js new file mode 100644 index 00000000..6fb37304 --- /dev/null +++ b/app/src/modules/JobMgr.js @@ -0,0 +1,141 @@ +/* +See usage notes below code +*/ + +export function JobMgr () { + this.jobType = null + this.jobId = null + this.err = null + this.jobInputFiles = [] + this.jobParameters = null + this.createJobPath = '/nmr/jobcreate' + this.postJobFilePath = '/nmr/jobpostfile' + this.submitJobPath = '/nmr/jobsubmit' +} +JobMgr.prototype = { + getJobId: function () { + return this.jobId + }, + handleErr: function (err, failureFunction) { + if (err.response) { + if (err.config && err.config.data) { + const data = JSON.parse(err.config.data) + if (data.jobFileInfo) { + this.jobInputFiles[data.jobFileInfo.idx].statusCode = err.response.status + this.jobInputFiles[data.jobFileInfo.idx].statusText = err.response.statusText + } + } + return failureFunction(err.response.status, err.response.statusText) + } else if (err.request) { + return failureFunction(500, err) + } else { + return failureFunction(500, err) + } + }, + submitJob: function (successFunction, failureFunction) { + // this.jobId = SET by remote call + if (this.jobType === null) { + setTimeout(failureFunction(400, 'Job type required'), 0) // don't do this on main path -- it's supposed to be async + } else { + // create job to get jobId and initialize job directory + const fileSends = [] + let jobUser = '' // default for now, server will set real value unless runAsUser is set by an admin (checked on server side) + const runAs = this.$store.getters.runAsUser + if (runAs && runAs.length > 0) { + jobUser = runAs + } + if (this.jobParameters) { + this.jobParameters.user = jobUser + } else { + this.jobParameters = { user: jobUser } + } + try { + fetch(this.createJobPath, { + method: 'POST', + jobParameters: this.jobParameters, + jobType: this.jobType + }) + .then(function (res) { + this.jobId = res.data.data.jobId + this.jobInputFiles.forEach(function (v) { + // send each file in a separate request and wait for all to complete successfully before submitting job + fileSends.push(fetch(this.postJobFilePath, { + method: 'POST', + jobId: this.jobId, + jobType: this.jobType, + jobFileInfo: v + })) + }) + Promise.all(fileSends) + .then((p) => { + // wait for all files to be sent then submit job + p.forEach(function (v) { + // set status and status text this.jobInputFiles[idx].statusCode=p. + const reqData = JSON.parse(v.config.data) + const index = reqData.jobFileInfo.idx + this.jobInputFiles[index].statusCode = v.status + this.jobInputFiles[index].statusText = v.statusText + }) + fetch(this.submitJobPath, { + method: 'POST', + jobId: this.jobId, + jobType: this.jobType + }) + .then(function (res) { + return successFunction(this.jobId) + }) + .catch(function (err) { + this.handleErr(err, failureFunction) + }) + }) + .catch(function (err) { + this.handleErr(err, failureFunction) + }) + }) + .catch(function (err) { + this.handleErr(err, failureFunction) + }) + } catch (err) { + this.handleErr(err, failureFunction) + } + } + }, + setJobType: function (jobType) { + this.jobType = jobType + }, + getJobType: function () { + return this.jobType + }, + getFileCount: function () { + return this.jobInputFiles.length + }, + getFileInfo: function (idx) { + let rv = null + if (idx >= 0 && idx < this.jobInputFiles.length) { + rv = this.jobInputFiles[idx] + } + return rv + }, + addInputFile: function (fileName, dataUri) { + const idx = this.jobInputFiles.length + this.jobInputFiles.push({ idx: idx, fileName: fileName, dataUri: dataUri, statusCode: null, statusText: null }) + }, + setJobParameters: function (paramsObject) { + this.jobParameters = paramsObject + } +} + +/* Using this class +import {JobMgr} from '@/modules/JobMgr.js' +const jm new JobMgr() +jm.addInputFile(fileName[0], dataUrl[0]) +jm.addInputFile(fileName[N], dataUrl[N]) +jm.setJobParameters({ testField: val1, myField2: val2 }) +jm.setJobType(jobType) +jm.submitJob(function success (jobid) {}, function failure (err) { + for (let i = 0; i < jm.getFileCount(); ++i) { + const fileInfo = jm.getFileInfo(i) + } +}) + +*/ diff --git a/app/src/pages/nanomine/csvPlotter/CsvPlotter.vue b/app/src/pages/nanomine/csvPlotter/CsvPlotter.vue new file mode 100644 index 00000000..c243fea2 --- /dev/null +++ b/app/src/pages/nanomine/csvPlotter/CsvPlotter.vue @@ -0,0 +1,8 @@ + + + diff --git a/app/src/pages/nanomine/csvPlotter/csvPlotter.html b/app/src/pages/nanomine/csvPlotter/csvPlotter.html new file mode 100644 index 00000000..3c55babf --- /dev/null +++ b/app/src/pages/nanomine/csvPlotter/csvPlotter.html @@ -0,0 +1,48 @@ +
      +
      +
      +

      Curation Plot

      +
      + +
      + + +
      + {{csvName}} + + delete + +
      +
      +
      + + + + +
      +
      diff --git a/app/src/pages/nanomine/csvPlotter/csvPlotter.js b/app/src/pages/nanomine/csvPlotter/csvPlotter.js new file mode 100644 index 00000000..59005a2b --- /dev/null +++ b/app/src/pages/nanomine/csvPlotter/csvPlotter.js @@ -0,0 +1,145 @@ +import {} from 'vuex' +// import { max } from 'd3' +import LineChart from '@/components/nanomine/LineChart' +// import { Auth } from '@/modules/Auth.js' +export default { + name: 'CurationPlot', + data () { + // let margin = { + // top: 10, + // right: 30, + // bottom: 30, + // left: 60 + // }; + // let width = 460 - margin.left - margin.right; + // let height = 400 - margin.top - margin.bottom; + return { + title: 'Curation Plot', + dialog: false, + boxColor: '#e3e3e3', + csv: null, + csvName: '', + csvText: '', + data: [], + dataset: {}, + xlabel: '', + ylabel: '' + // // set the dimensions and margins of the graph + // margin: margin, + // width: width, + // height: height + } + }, + components: { + 'nm-linechart': LineChart + }, + methods: { + reset () { + this.boxColor = '#e3e3e3' + this.csv = null + this.csvName = '' + this.csvText = '' + this.data = [] + this.dataset = this.dataset = { + data: [], + xlabel: '', + ylabel: '' + } + this.xlabel = '' + this.ylabel = '' + document.getElementById('assetsFieldHandle').value = '' + }, + onChange () { + this.csv = this.$refs.myUpload.files[0] + console.log(this.csv) + this.csvName = this.csv.name + console.log(this.csvName) + const fr = new FileReader() + // fr.readAsDataURL(this.csv); + fr.readAsText(this.csv) + fr.addEventListener('load', () => { + this.csvText = fr.result + this.csv2xy(this.csvText) + }) + }, + remove () { + this.reset() + }, + dragover (event) { + event.preventDefault() + this.boxColor = '#c4c4c4' + // Add some visual fluff to show the user can drop its files + // if (!event.currentTarget.classList.contains('bg-green-300')) { + // event.currentTarget.classList.remove('bg-gray-100'); + // event.currentTarget.classList.add('bg-green-300'); + // } + }, + dragleave (event) { + this.boxColor = '#e3e3e3' + // Clean up + // event.currentTarget.classList.add('bg-gray-100'); + // event.currentTarget.classList.remove('bg-green-300'); + }, + drop (event) { + event.preventDefault() + this.boxColor = '#97fc83' + this.$refs.myUpload.files = event.dataTransfer.files + this.onChange() // Trigger the onChange event manually + // Clean up + // event.currentTarget.classList.add('bg-gray-100'); + // event.currentTarget.classList.remove('bg-green-300'); + }, + csv2xy (csvText) { + // var result = {} + var rows = csvText.split(/\r\n|\r|\n/) + const length = rows.length - 1 + var data = [] + var xlabel = '' + var ylabel = ''; + [xlabel, ylabel] = rows[0].split(',') + for (var i = 1; i < length; ++i) { + var rowV = rows[i].split(',') + data.push({ + x: +rowV[0], + y: +rowV[1] + }) + } + this.xlabel = xlabel + this.ylabel = ylabel + this.data = data + } + }, + // computed: { + // /** + // * dataset: Will organize data according to the filter rules + // */ + // dataset() { + // // Default + // return this.transformData(data); + // } + // // }, + // // created() { + // // this.maxValue = max(data, d => d.high).toFixed(2); + // }, + watch: { + data (newData) { + if (newData.length > 0) { + console.log('xlabel: ' + this.xlabel) + console.log('ylabel: ' + this.ylabel) + console.log(newData[0].x) + console.log(newData[0].y) + console.log(newData) + // console.log("data: " + this.data); + console.log('watch run') + this.dataset = { + data: newData, + xlabel: this.xlabel, + ylabel: this.ylabel + } + } + } + }, + created () { + this.$store.commit('setAppHeaderInfo', { icon: 'workspaces', name: 'Curation Plot' }) + } +} diff --git a/app/src/pages/nanomine/toolSets/BinarizationTools.vue b/app/src/pages/nanomine/toolSets/BinarizationTools.vue new file mode 100644 index 00000000..016fc8b3 --- /dev/null +++ b/app/src/pages/nanomine/toolSets/BinarizationTools.vue @@ -0,0 +1,37 @@ + + diff --git a/app/src/pages/nanomine/toolSets/CharacterizationTools.vue b/app/src/pages/nanomine/toolSets/CharacterizationTools.vue new file mode 100644 index 00000000..f61dbf86 --- /dev/null +++ b/app/src/pages/nanomine/toolSets/CharacterizationTools.vue @@ -0,0 +1,41 @@ + + diff --git a/app/src/pages/nanomine/toolSets/MCRTools.vue b/app/src/pages/nanomine/toolSets/MCRTools.vue new file mode 100644 index 00000000..25dca7ce --- /dev/null +++ b/app/src/pages/nanomine/toolSets/MCRTools.vue @@ -0,0 +1,45 @@ + + diff --git a/app/src/pages/nanomine/toolSets/ModuleTools.vue b/app/src/pages/nanomine/toolSets/ModuleTools.vue new file mode 100644 index 00000000..455ca016 --- /dev/null +++ b/app/src/pages/nanomine/toolSets/ModuleTools.vue @@ -0,0 +1,36 @@ + + diff --git a/app/src/pages/nanomine/toolSets/ReconstructionTools.vue b/app/src/pages/nanomine/toolSets/ReconstructionTools.vue new file mode 100644 index 00000000..d862a399 --- /dev/null +++ b/app/src/pages/nanomine/toolSets/ReconstructionTools.vue @@ -0,0 +1,42 @@ + + diff --git a/app/src/pages/nanomine/toolSets/SimulationTools.vue b/app/src/pages/nanomine/toolSets/SimulationTools.vue new file mode 100644 index 00000000..4887eb89 --- /dev/null +++ b/app/src/pages/nanomine/toolSets/SimulationTools.vue @@ -0,0 +1,34 @@ + + diff --git a/app/src/pages/nanomine/toolSets/ToolSetBase.vue b/app/src/pages/nanomine/toolSets/ToolSetBase.vue new file mode 100644 index 00000000..98240aef --- /dev/null +++ b/app/src/pages/nanomine/toolSets/ToolSetBase.vue @@ -0,0 +1,3 @@ + diff --git a/app/src/pages/nanomine/toolSets/ToolSetTemplate.vue b/app/src/pages/nanomine/toolSets/ToolSetTemplate.vue new file mode 100644 index 00000000..0de93d40 --- /dev/null +++ b/app/src/pages/nanomine/toolSets/ToolSetTemplate.vue @@ -0,0 +1,71 @@ + + diff --git a/app/src/pages/nanomine/toolSets/index.js b/app/src/pages/nanomine/toolSets/index.js new file mode 100644 index 00000000..c0c157d9 --- /dev/null +++ b/app/src/pages/nanomine/toolSets/index.js @@ -0,0 +1,15 @@ +import BinarizationTools from './BinarizationTools' +import CharacterizationTools from './CharacterizationTools' +import ReconstructionTools from './ReconstructionTools' +import MCRTools from './MCRTools' +import ModuleTools from './ModuleTools' +import SimulationTools from './SimulationTools' + +export default { + BinarizationTools, + CharacterizationTools, + ReconstructionTools, + MCRTools, + ModuleTools, + SimulationTools +} diff --git a/app/src/pages/nanomine/tools/CorrelationCharacterize.vue b/app/src/pages/nanomine/tools/CorrelationCharacterize.vue new file mode 100644 index 00000000..0397c6d4 --- /dev/null +++ b/app/src/pages/nanomine/tools/CorrelationCharacterize.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/src/pages/nanomine/tools/CorrelationReconstruct.vue b/app/src/pages/nanomine/tools/CorrelationReconstruct.vue new file mode 100644 index 00000000..46a10f12 --- /dev/null +++ b/app/src/pages/nanomine/tools/CorrelationReconstruct.vue @@ -0,0 +1,96 @@ + + + diff --git a/app/src/pages/nanomine/tools/DescriptorCharacterize.vue b/app/src/pages/nanomine/tools/DescriptorCharacterize.vue new file mode 100644 index 00000000..a0fa82af --- /dev/null +++ b/app/src/pages/nanomine/tools/DescriptorCharacterize.vue @@ -0,0 +1,75 @@ + + + diff --git a/app/src/pages/nanomine/tools/DescriptorReconstruct.vue b/app/src/pages/nanomine/tools/DescriptorReconstruct.vue new file mode 100644 index 00000000..0d2fba8c --- /dev/null +++ b/app/src/pages/nanomine/tools/DescriptorReconstruct.vue @@ -0,0 +1,84 @@ + + + diff --git a/app/src/pages/nanomine/tools/IntelligentCharacterize.vue b/app/src/pages/nanomine/tools/IntelligentCharacterize.vue new file mode 100644 index 00000000..31f166a0 --- /dev/null +++ b/app/src/pages/nanomine/tools/IntelligentCharacterize.vue @@ -0,0 +1,83 @@ + + + diff --git a/app/src/pages/nanomine/tools/NiblackBinarization.vue b/app/src/pages/nanomine/tools/NiblackBinarization.vue new file mode 100644 index 00000000..55d33bf0 --- /dev/null +++ b/app/src/pages/nanomine/tools/NiblackBinarization.vue @@ -0,0 +1,87 @@ + + + diff --git a/app/src/pages/nanomine/tools/OtsuBinarization.vue b/app/src/pages/nanomine/tools/OtsuBinarization.vue new file mode 100644 index 00000000..f1678cf2 --- /dev/null +++ b/app/src/pages/nanomine/tools/OtsuBinarization.vue @@ -0,0 +1,79 @@ + + + + +import getters from './getters' +export default { + namespaced: true, + state () { + return + }, + getters +} diff --git a/app/src/pages/nanomine/tools/Polymerizer.vue b/app/src/pages/nanomine/tools/Polymerizer.vue new file mode 100644 index 00000000..77e2403f --- /dev/null +++ b/app/src/pages/nanomine/tools/Polymerizer.vue @@ -0,0 +1,36 @@ + + + diff --git a/app/src/pages/nanomine/tools/SDFCharacterize.vue b/app/src/pages/nanomine/tools/SDFCharacterize.vue new file mode 100644 index 00000000..a38609f7 --- /dev/null +++ b/app/src/pages/nanomine/tools/SDFCharacterize.vue @@ -0,0 +1,75 @@ + + + diff --git a/app/src/pages/nanomine/tools/SDFReconstruct.vue b/app/src/pages/nanomine/tools/SDFReconstruct.vue new file mode 100644 index 00000000..454b2e1e --- /dev/null +++ b/app/src/pages/nanomine/tools/SDFReconstruct.vue @@ -0,0 +1,90 @@ + + + diff --git a/app/src/pages/nanomine/tools/ToolBase.vue b/app/src/pages/nanomine/tools/ToolBase.vue new file mode 100644 index 00000000..98240aef --- /dev/null +++ b/app/src/pages/nanomine/tools/ToolBase.vue @@ -0,0 +1,3 @@ + diff --git a/app/src/pages/nanomine/tools/ToolTemplate.vue b/app/src/pages/nanomine/tools/ToolTemplate.vue new file mode 100644 index 00000000..36112057 --- /dev/null +++ b/app/src/pages/nanomine/tools/ToolTemplate.vue @@ -0,0 +1,42 @@ + + + diff --git a/app/src/pages/nanomine/tools/TransferLearning.vue b/app/src/pages/nanomine/tools/TransferLearning.vue new file mode 100644 index 00000000..ba6130be --- /dev/null +++ b/app/src/pages/nanomine/tools/TransferLearning.vue @@ -0,0 +1,41 @@ + + + diff --git a/app/src/pages/nanomine/tools/chemProps/ChemProps.vue b/app/src/pages/nanomine/tools/chemProps/ChemProps.vue index 821de578..4165d279 100644 --- a/app/src/pages/nanomine/tools/chemProps/ChemProps.vue +++ b/app/src/pages/nanomine/tools/chemProps/ChemProps.vue @@ -1,2 +1,8 @@ + + diff --git a/app/src/pages/nanomine/tools/chemProps/chemProps.html b/app/src/pages/nanomine/tools/chemProps/chemProps.html index 94f52f7f..06751e5c 100644 --- a/app/src/pages/nanomine/tools/chemProps/chemProps.html +++ b/app/src/pages/nanomine/tools/chemProps/chemProps.html @@ -1,5 +1,91 @@ -
      -
      -

      ChemProps

      + +
      +
      + + + + + +
      +

      ChemProps - A growing polymer name and filler name standardization database

      +
      +
      +

      Description

      +

      + ChemProps is a growing polymer name and filler name standardization database. Polymer names and filler names can have many alias, + impeding the queries to collect all relevant data by a chemical name as the keyword. Chemprops is a useful resource to address + this problem. It standardizes the chemical names that belong to the same database such that queries can retrieve all data that + is related to a certain chemical name regardless of how they were originally reported. You can find more details in our paper + "ChemProps: A RESTful API enabled database for composite polymer name standardization". +

      +
      +
      +

      + This webapp is designed for one-time search. For batch jobs, please use the ChemProps API. A token is required to use the API. + You must be logged in to request the ChemProps API token. +

      +
      + Request API Token +
      +

      Instructions

      +
      +
      +
        +
      1. Select the collection.
      2. +
        + Polymer + Filler +
        +
      3. Input the searching terms. For the quick search, you can search by either chemical name, abbreviation, trade name, or SMILES. For the advanced search, you must input a chemical name.
      4. +
      5. Input the searching terms. Note that you must input a chemical name.
      6. +
        + + + + + + + + + + + + + + + + + +
        + Search +
      +
      +
      +
      +

      Standardized chemical name and density information:

      +
      +
      + + + + + + + + + + + + +

      Structure + +

      +

      Formula: {{molecularFormula}} +

      +
      +
      -
      \ No newline at end of file +
      + \ No newline at end of file diff --git a/app/src/pages/nanomine/tools/chemProps/chemProps.js b/app/src/pages/nanomine/tools/chemProps/chemProps.js index a44aa49f..9ec52837 100644 --- a/app/src/pages/nanomine/tools/chemProps/chemProps.js +++ b/app/src/pages/nanomine/tools/chemProps/chemProps.js @@ -1,6 +1,254 @@ +import { mapGetters, mapMutations } from 'vuex' +// import { Auth } from '@/modules/Auth.js' +import SmilesCanvas from '@/components/nanomine/SmilesCanvas' +import ToolTemplate from '../ToolTemplate' +import Dialog from '@/components/Dialog' +const SERVER = `${window.location.origin}/nmr/api` +// const SERVER = `http://localhost:8000/nmr/api` +const URL = SERVER + export default { name: 'ChemProps', + components: { + SmilesCanvas, + ToolTemplate, + dialogbox: Dialog + }, + props: { + card: { + type: Boolean, + required: false, + default: false + } + }, + data () { + return { + title: 'ChemProps', + dialog: { + title: '' + }, + pfRadios: 'pol', + quicksearchkeyword: '', + chemicalname: '', + abbreviation: '', + SMILES: '', + tradename: '', + stdname: '', + density: '', + uSMILES: '', + loginRequired: false, + loginRequiredMsg: '', + successDlg: false, + theme: 'dark', + smilesError: false, + smilesMessage: '', + inputStr: '', + molecularFormula: '', + chempropsToken: null, + // https://github.com/reymond-group/smilesDrawer#options + smilesOptions: { + Padding: 0.0, + atomVisualization: 'default', // 'balls', + explicitHydrogens: true, + terminalCarbons: true, + debug: false + }, + tool: { + references: [ + '10.1186/s13321-021-00502-6', + '10.1021/acs.jcim.7b00425' + ] + } + } + }, + watch: { + stdname (newData, oldData) { + if (newData) { + this.scrollToResult() + } + } + }, + beforeMount: function () { + // this.auth = new Auth() + }, + async mounted () { + let result = await fetch(`${URL}/parser`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }) + if (result && result.status === 201) { + result = await result.json() + if (result.token) this.chempropsToken = result.token + } + }, + methods: { + ...mapMutations({ + toggleDialogBox: 'setDialogBox' + }), + scrollToResult () { + const elem = document.getElementById('chemprops-displayed-result') + if (elem) { + setTimeout(function () { + elem.scrollIntoView() + }, 800) + } + }, + setLoading: function () { + this.$store.commit('isLoading') + }, + resetLoading: function () { + this.$store.commit('notLoading') + }, + resetOutput: function () { + this.stdname = '' + this.density = '' + if (this.dialogBoxActive) { + this.toggleDialogBox() + } + }, + successDlgClicked: function () { + // this.$router.go(-1) // go back to previous page + this.successDlg = false + }, + search: function () { + this.resetOutput() + if (!this.chempropsToken) { + this.renderDialog( + 'Search Error', + 'System error, contact our system administrator' + ) + return + } + if (this.pfRadios === 'pol' && this.quicksearchkeyword.trim() !== '') { + if (this.quicksearchkeyword === '') { + this.renderDialog( + 'Input Error', + 'Please input the quick search keyword.' + ) + return + } + this.chemicalname = this.quicksearchkeyword + this.abbreviation = this.quicksearchkeyword + this.tradename = this.quicksearchkeyword + this.SMILES = this.quicksearchkeyword + } + if (this.chemicalname === '') { + this.renderDialog( + 'Input Error', + 'Please input the chemical name.' + ) + return + } + if (this.pfRadios === '') { + this.renderDialog( + 'Input Error', + 'Please select the collection.' + ) + return + } + // TODO need to configure after nmcp API done + this.setLoading() + // Axios.request({ + // url: `${URL}/chemprops?polfil=${this.pfRadios}&nmId=restNmId&chemicalname=${this.chemicalname}&abbreviation=${this.abbreviation}&tradename=${this.tradename}&smiles=${this.SMILES}`, + // method: 'get', + // headers: { + // Accept: 'application/json', + // 'Content-Type': 'application/json', + // Authorization: 'Bearer ' + this.chempropsToken + // } + // }) + fetch(new URL(`${URL}/chemprops?polfil=${this.pfRadios}&nmId=restNmId&chemicalname=${this.chemicalname}&abbreviation=${this.abbreviation}&tradename=${this.tradename}&smiles=${this.SMILES}`), + { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + this.chempropsToken + } + } + ) + .then(function (res) { + return res + }) + .then(function (response) { + this.stdname = response.data.data.StandardName + this.density = parseFloat(response.data.data.density) + // show uSMILES if it's polymer search + if (this.pfRadios === 'pol') { + this.uSMILES = response.data.data.uSMILES + } + // check if stdname is found + if (this.stdname === '') { + this.renderDialog( + 'Search Error', + 'No results found. Admin will update the database soon. Please try again in a week.' + ) + this.resetOutput() + } + this.resetLoading() + }) + .catch(function (error) { + console.log(error) + this.resetOutput() + if (error.message.includes('404')) { + this.renderDialog( + 'Search Error', + 'No results found. Admin will update the database soon. Please try again in a week.' + ) + } else { + this.renderDialog( + 'Search Error', + 'An exception occurred when calling the ChemProps API service.' + ) + } + this.resetLoading() + }) + .then(function () { + // always executed + this.inputStr = this.uSMILES + // reset input if using quick search + if (this.quicksearchkeyword.trim() !== '') { + this.chemicalname = '' + this.abbreviation = '' + this.tradename = '' + this.SMILES = '' + } + }) + }, + onSuccess () { + this.smilesError = false + }, + formulaUpdated (formula) { + this.molecularFormula = formula + }, + onError (err) { + console.trace('Error handler called: ') + if (err) { + this.smilesMessage = err + } else { + this.smilesMessage = 'Undefined error' + } + this.smilesError = true + console.log('SmilesTest - error: ' + this.smilesMessage) + }, + renderDialog (title, content, minWidth) { + this.dialog = { + title, + content, + minWidth + } + this.toggleDialogBox() + } + }, created () { this.$store.commit('setAppHeaderInfo', { icon: 'workspaces', name: 'ChemProps' }) + }, + computed: { + ...mapGetters({ + dialogBoxActive: 'dialogBox' + }) } } diff --git a/app/src/pages/nanomine/tools/chemPropsAPIToken/ChemPropsAPIToken.vue b/app/src/pages/nanomine/tools/chemPropsAPIToken/ChemPropsAPIToken.vue new file mode 100644 index 00000000..ffe38e7a --- /dev/null +++ b/app/src/pages/nanomine/tools/chemPropsAPIToken/ChemPropsAPIToken.vue @@ -0,0 +1,2 @@ + + diff --git a/app/src/pages/nanomine/tools/chemPropsAPIToken/chemPropsAPIToken.html b/app/src/pages/nanomine/tools/chemPropsAPIToken/chemPropsAPIToken.html new file mode 100644 index 00000000..df5dc21e --- /dev/null +++ b/app/src/pages/nanomine/tools/chemPropsAPIToken/chemPropsAPIToken.html @@ -0,0 +1,54 @@ +
      +
      +
      +

      + Request token here for ChemProps - A growing polymer name and filler name standardization database +

      +
      + +
      +

      Instructions

      +

      In this page, you can request token for API access to ChemProps. For the first-time users, you will + need to create access token by entering a domain secret. The token information will display once the + secret is submitted. Please keep the token safe. In case of losing the token, the token information + will show again when users log in and land on this page once the access token is created. +

      +
      +
      +

      If you already have a Duke University account, proceed to login. Otherwise create a + Duke OneLink account. +

      + Login +
      +
      +
      + + + + + Request Token +
      +
      + + API URL: {{address}}/nmr/api/chemprops +
      API Token: {{accessAuth}}
      +
      +

      + To access this protected api resource, the user agent should send the API Token, + typically in the Authorization header using the Bearer schema. The content of the header should look like the following:
      + + 'Content-Type': 'application/json', + Authorization: Bearer <token> + + Copy and keep the above token safe. +

      +
      +
      +
      +
      \ No newline at end of file diff --git a/app/src/pages/nanomine/tools/chemPropsAPIToken/chemPropsAPIToken.js b/app/src/pages/nanomine/tools/chemPropsAPIToken/chemPropsAPIToken.js new file mode 100644 index 00000000..d031b1f2 --- /dev/null +++ b/app/src/pages/nanomine/tools/chemPropsAPIToken/chemPropsAPIToken.js @@ -0,0 +1,104 @@ +import {} from 'vuex' +// import { Auth } from '@/modules/Auth.js' +const SERVER = `${window.location.origin}/nmr/api` +const URL = SERVER + +export default { + name: 'ChemPropsAPIToken', + data () { + return { + title: 'ChemPropsAPIToken', + auth: { // AUTH MOCKED because auth is not yet implemented + isLoggedIn: () => false, + isTestUser: () => false + }, + accessAuth: false, + domainsecret: null, + submitError: false, + sValue: true, + address: window.location.origin, + chempropsToken: null, + loginRequired: false, + loginRequiredMsg: '' + } + }, + beforeMount: function () { + const vm = this + // vm.auth = new Auth() + if (!vm.auth.isLoggedIn()) { + vm.loginRequired = true + } + }, + async mounted () { + const vm = this + vm.checkIfApiExist() + }, + methods: { + getUserLoginLink () { + let rv = '/secure' + if (this.auth.isTestUser() === true) { + rv = '/nmr/nmdevlogin' + } + return rv + }, + async submitRequest () { + this.submitError = false + this.loginRequiredMsg = null + if (this.auth.isLoggedIn() && this.domainsecret != null) { + try { + const cookies = this.auth.getCookieToken() + let result = await fetch(`${URL}/create`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + cookies + }, + body: JSON.stringify({ domain: this.domainname, token: this.domainsecret }) + }) + if (result && result.status === 201) { + result = await result.json() + this.accessAuth = result + return this.accessAuth + } else { + result = await result.json() + this.submitError = true + this.loginRequiredMsg = result.mssg + return this.loginRequiredMsg + } + } catch (err) { + this.submitError = true + this.loginRequiredMsg = err + console.log(err) + throw err + } + } else { + this.submitError = true + this.loginRequiredMsg = 'Secret fields are required!' + } + }, + async checkIfApiExist () { + if (this.auth.isLoggedIn()) { + const cookies = this.auth.getCookieToken() + let result = await fetch(`${URL}/check`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + cookies + } + }) + if (result && result.status === 201) { + result = await result.json() + if (result && result.token) { + this.accessAuth = result + return this.accessAuth + } + } + } + } + }, + created () { + this.$store.commit('setAppHeaderInfo', { icon: 'workspaces', name: 'ChemProps API' }) + } +} diff --git a/app/src/pages/nanomine/tools/csvPlotter/CsvPlotter.vue b/app/src/pages/nanomine/tools/csvPlotter/CsvPlotter.vue deleted file mode 100644 index be5e3d6d..00000000 --- a/app/src/pages/nanomine/tools/csvPlotter/CsvPlotter.vue +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/app/src/pages/nanomine/tools/csvPlotter/csvPlotter.html b/app/src/pages/nanomine/tools/csvPlotter/csvPlotter.html deleted file mode 100644 index e1da917d..00000000 --- a/app/src/pages/nanomine/tools/csvPlotter/csvPlotter.html +++ /dev/null @@ -1,5 +0,0 @@ -
      -
      -

      Curation Plot

      -
      -
      \ No newline at end of file diff --git a/app/src/pages/nanomine/tools/csvPlotter/csvPlotter.js b/app/src/pages/nanomine/tools/csvPlotter/csvPlotter.js deleted file mode 100644 index 1886ab80..00000000 --- a/app/src/pages/nanomine/tools/csvPlotter/csvPlotter.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - name: 'CSVPlotter', - created () { - this.$store.commit('setAppHeaderInfo', { icon: 'workspaces', name: 'Curation Plot' }) - } -} diff --git a/app/src/pages/nanomine/tools/dynamfitResult/DynamfitResult.vue b/app/src/pages/nanomine/tools/dynamfitResult/DynamfitResult.vue new file mode 100644 index 00000000..6034b343 --- /dev/null +++ b/app/src/pages/nanomine/tools/dynamfitResult/DynamfitResult.vue @@ -0,0 +1,2 @@ + + diff --git a/app/src/pages/nanomine/tools/dynamfitResult/dynamfitResult.html b/app/src/pages/nanomine/tools/dynamfitResult/dynamfitResult.html new file mode 100644 index 00000000..5ef2d97b --- /dev/null +++ b/app/src/pages/nanomine/tools/dynamfitResult/dynamfitResult.html @@ -0,0 +1,86 @@ +
      +
      +

      + Dynamfit - Prony Series coefficient fitting +

      + +

      The fitting result is shown below:

      +
      +
      +

      Epsilon Prime

      + +
      +
      +

      Epsilon Double Prime

      + +
      +
      +

      + Prony Series Coefficients (the program writes three files.) +

      +
      File #.XPR
      +

      + This file contains the Prony series terms. It consists of N lines of + data with each line containing (γi, P-SVDi, + RMS-SVD, P-Signi, RMS-Sign), where γi are the + relaxation times (constant term has γi set to + 1050, P-SVDi and P-Signiare the Prony + series coefficients for the linear (SVD) and sign controlled method, + respectively, and RMS-SVD and RMS-Sign are the RMS percent errors + between the obtained fit and the entire data for the linear (SVD) and + sign controlled method, respectively. Note that the RMS errors are + provided on every line; this is a simplification to keep all lines in + the file identical in size. +

      +
      File #.XFF
      + +

      + This file contains the predicted frequency domain response obtained by + the program. It consists of U lines of data, where U is the number of + points specified by the user for the response predictions. Each line + contains (ωi, X'-SVDi, + X-SVDi, X-Signi, X-Signi), where + ωi are the frequency points of evaluation (U points + evenly spaced in the log domain between ωmin and + ωmax. +

      +
      File #.XTF
      +

      + This file contains the predicted time domain response obtained by the + program. It consists of U lines of data, where U is the number of points + specified by the user for the response predictions. Each line contains + (ti, X-SVDi, X-Signi, where ti + are the time points of evaluation (U points evenly spaced in the log + domain between tmin = 2 π/ ω min), and + X-SVDi and X-Signi are the predicted time domain + values from the Prony series obtained by the linear (SVD) and sign + controlled method, respectively. +

      +

      + These Prony Series coefficients associated with the elastic parameters + of nanoparticles are then imported into the material section of finite + element simulation. +

      +

      Your results are ready to download

      +

      + Click here to download #.XPR file. +

      +

      + Click here to download #.XFF file. +

      +

      + Click here to download #.XTF file. +

      +
      + Run another file? +
      +
      + +
      +
      +
      \ No newline at end of file diff --git a/app/src/pages/nanomine/tools/dynamfitResult/dynamfitResult.js b/app/src/pages/nanomine/tools/dynamfitResult/dynamfitResult.js new file mode 100644 index 00000000..009f57b5 --- /dev/null +++ b/app/src/pages/nanomine/tools/dynamfitResult/dynamfitResult.js @@ -0,0 +1,86 @@ +// import Axios from 'axios' +import ReferenceContainer from '@/components/nanomine/ReferenceContainer' + +export default { + name: 'DynamfitResult', + components: { + ReferenceContainer + }, + data () { + return { + resultsError: false, + resultsErrorMsg: '', + Eimg: '', + EEimg: '', + XPR: '', + XFF: '', + XTF: '', + references: [ + '10.1023/A:1009772018066' + ] + } + }, + mounted: function () { + this.getJobOutputParams() + }, + methods: { + setLoading: function () { + // this.$store.commit('isLoading') + }, + resetLoading: function () { + // this.$store.commit('notLoading') + }, + getEImage: function () { + return this.$route.query.ref + '/' + this.Eimg + }, + getEEImage: function () { + return this.$route.query.ref + '/' + this.EEimg + }, + getXPRFile: function () { + return this.$route.query.ref + '/' + this.XPR + }, + getXFFFile: function () { + return this.$route.query.ref + '/' + this.XFF + }, + getXTFFile: function () { + return this.$route.query.ref + '/' + this.XTF + }, + getJobOutputParams: async function () { + const url = this.$route.query.ref + '/job_output_parameters.json' + this.setLoading() + var response + try { + response = await fetch(url) + } catch (err) { + console.log(err) + this.resultsErrorMsg = err + this.resultsError = true + this.resetLoading() + return + } + var myOutputParams + try { + myOutputParams = await response.json() + } catch (err) { + console.log(err) + this.resultsErrorMsg = 'Error retrieving result.' + this.resultsError = true + this.resetLoading() + return + } + console.log(myOutputParams) + this.Eimg = myOutputParams.Eimg + this.EEimg = myOutputParams.EEimg + this.XPR = myOutputParams.XPR + this.XFF = myOutputParams.XFF + this.XTF = myOutputParams.XTF + this.resetLoading() + } + }, + created () { + this.$store.commit('setAppHeaderInfo', { + icon: 'workspaces', + name: 'Dynamfit Result' + }) + } +} diff --git a/app/src/pages/nanomine/tools/dynamfitTool/Dynamfit.vue b/app/src/pages/nanomine/tools/dynamfitTool/Dynamfit.vue new file mode 100644 index 00000000..d68d7e23 --- /dev/null +++ b/app/src/pages/nanomine/tools/dynamfitTool/Dynamfit.vue @@ -0,0 +1,2 @@ + + diff --git a/app/src/pages/nanomine/tools/dynamfitTool/dynamfit.html b/app/src/pages/nanomine/tools/dynamfitTool/dynamfit.html new file mode 100644 index 00000000..3d196d64 --- /dev/null +++ b/app/src/pages/nanomine/tools/dynamfitTool/dynamfit.html @@ -0,0 +1,246 @@ + +
      +
      +
      +

      + Dynamfit - Prony Series coefficient fitting +

      +
      + +
      +

      An Example - Part I

      +

      + Please click here to download example + data file. This file is a .X_T file with three columns per line + (Frequency, X', X''). +

      +
      +
      +

      An Example - Part II

      +

      + In this page, you will learn to use and modify all the parameters + available in Dynamfit. An email will be sent to your registered email + address once the job is completed. You will then be able to compare the + fitting results with the example given in the previous page. +

      +
      +
      +

      Description

      +

      + This program fits a viscoelastic mastercurve (tan δ vs. frequency) + from DMA experiments with a Prony Series. The Prony Series coefficients + can be used as baseline properties for the matrix in a FEA simulation of + nanocomposites. +

      +

      + If this tool is new to you, please click + + Example of Dynamfit + + to get familiar with this tool. +

      +
      +
      +

      Instructions

      +
      +
      +
        +
        +
      1. + Upload #.X_T file containing three values per line (Frequency X' + X''): +
      2. +
        +

        Upload #.X_T file here:

        +

        + Upload "EXAMPLE.X_T" here: +

        + Browse + + + + check_circle_outline + + + +
        +
        +

        + EXAMPLE.X_T is preloaded in this example. For general use, you + will need to upload your .X_T file. +

        +
        +
        +
        +
      3. Factor For Weighting X' and X'' data:
      4. +
        +

        0.0 Means Consider Only X'' Data

        +

        2.0 Means Consider Only X' Data

        +

        1.0 Means Weight Evenly X' and X''

        +

        All Other Values Represent Uneven Weighting

        +
        + + + + +
        +
        +
      5. Standard deviation:
      6. +
        + Data point values + Unity +
        +
        +
        +
      7. + Number of elements (should larger than 2 and should NOT be too + large): +
      8. + + + + +
        +
        +
      9. Data type:
      10. +
        + Compliance + Modulus +
        +
        +
      +
      +
      +

      + The fitting result is shown below: +

      +
      +

      Epsilon Prime

      + +
      +
      +

      Epsilon Double Prime

      + +
      +
      +

      + Now please click the arrow to advance to the next part of the example, + where you can change the parameters of simulation, compare your result + with result above and get familiar with the tool. +

      + + Part IIarrow_forward + +
      + < +
      +
      + Run Simulation + + + arrow_backPart I + +
      + + + + + + + + +
      Dynamfit Job Submitted Successfully
      +
      + + Your uploader job is: {{jobId}}
      + You should receive an email with a link to the job output. +
      + + Close + +
      +
      +
      +
      +
      \ No newline at end of file diff --git a/app/src/pages/nanomine/tools/dynamfitTool/dynamfit.js b/app/src/pages/nanomine/tools/dynamfitTool/dynamfit.js new file mode 100644 index 00000000..3016af2a --- /dev/null +++ b/app/src/pages/nanomine/tools/dynamfitTool/dynamfit.js @@ -0,0 +1,226 @@ +import { mapMutations, mapGetters } from 'vuex' +import { JobMgr } from '@/modules/JobMgr.js' +import Dialog from '@/components/Dialog' +import ToolTemplate from '../ToolTemplate' +// import { Auth } from '@/modules/Auth.js' +export default { + name: 'Dynamfit', + components: { + ToolTemplate, + dialogbox: Dialog + }, + props: { + card: { + type: Boolean, + required: false, + default: false + } + }, + data () { + return { + // title: 'Dynamfit', + templateName: '', + templateUrl: '', + template: null, + templateUploaded: false, + weight: 1.0, + stdRadios: '', + nEle: 20, + dtRadios: '', + uploadError: false, + uploadErrorMsg: '', + loginRequired: false, + loginRequiredMsg: '', + successDlg: false, + jobId: '', + examplePage: 'noExample', + dialog: { + title: '' + }, + auth: { + // AUTH MOCKED because auth is not yet implemented + isLoggedIn: () => false, + isTestUser: () => false + }, + tool: { + appHeaderInfo: { + icon: '', + type: 'home', + name: 'MaterialsMine', + subtitle: 'An open source repository for nanocomposite data (NanoMine), and mechanical metamaterials data (MetaMine)' + }, + name: 'Dynamfit', + link: 'Dynamfit', + title: 'Dynamfit', + imageFile: 'nanomine/dynamfit.png', + text: 'Dynamfit is a sign control algorithm for Prony Series fitting. This program fits a viscoelastic mastercurve from DMA ' + + 'experiments with a Prony Series. The Prony Series coefficients can be used as baseline properties for the matrix in a FEA simulation ' + + 'of nanocomposites.', + display: true, + references: [ + '10.1023/A:1009772018066' + ] + } + } + }, + beforeMount: function () { + // this.auth = new Auth() + if (!this.auth.isLoggedIn()) { + this.loginRequired = true + this.loginRequiredMsg = 'Login is required.' + } + }, + methods: { + ...mapMutations({ + toggleDialogBox: 'setDialogBox' + }), + setLoading: function () { + this.$store.commit('isLoading') + }, + resetLoading: function () { + this.$store.commit('notLoading') + }, + pickTemplate () { + this.$refs.myTemplate.click() + }, + resetTemplate: function () { + this.templateName = '' + this.templateUrl = '' + this.template = null + this.templateUploaded = false + }, + onTemplatePicked (e) { + console.log('inside onTemplatePicked') + this.resetTemplate() + const files = e.target.files + console.log('shouldnt reach here') + const file = {} + const f = files[0] + if (f !== undefined) { + this.templateName = f.name + file.fileName = this.templateName + if (this.templateName.lastIndexOf('.') <= 0) { + console.log('Error No Extension: ' + this.templateName) + } + const fr = new FileReader() + fr.readAsDataURL(f) + fr.addEventListener('load', () => { + this.templateUrl = fr.result + file.fileUrl = this.templateUrl + this.template = file + this.templateUploaded = true + }) + } else { + this.resetTemplate() + } + }, + successDlgClicked: function () { + console.log('Success dlg button clicked') + // this.$router.go(-1) // go back to previous page + this.successDlg = false + }, + submit: function () { + if (!this.templateUploaded) { + if (this.examplePage === 'inputTest') { + this.renderDialog('Upload Error', 'Please upload EXAMPLE.X_T.') + } else { + this.renderDialog('Upload Error', 'Please upload the .X_T file.') + } + return + } + if (this.weight === '') { + this.renderDialog( + 'Input Error', + 'Please input the weighting parameter.' + ) + return + } + if (this.stdRadios === '') { + this.renderDialog( + 'Input Error', + 'Please select the type of the standard deviation.' + ) + return + } + if (this.nEle === '') { + this.renderDialog( + 'Input Error', + 'Please input the number of Prony elements.' + ) + return + } + if (this.dtRadios === '') { + this.renderDialog('Input Error', 'Please select the data type.') + return + } + console.log('Job Submitted!') + this.setLoading() + const jm = new JobMgr() + jm.setJobType('dynamfit') + jm.setJobParameters({ + templateName: this.templateName, + weight: this.weight, + stddev: this.stdRadios, + nEle: this.nEle, + dt: this.dtRadios + }) + jm.addInputFile(this.templateName, this.templateUrl) + return jm.submitJob( + function (jobId) { + console.log('Success! JobId is: ' + jobId) + this.jobId = jobId + this.resetLoading() + this.successDlg = true + }, + function (errCode, errMsg) { + console.log('error: ' + errCode + ' msg: ' + errMsg) + this.uploadError = true + this.uploadErrorMsg = + 'Error submitting files for upload: errCode: ' + + errCode + + ' msg: ' + + errMsg + this.resetLoading() + } + ) + }, + displayExample: function (example) { + const examplePages = ['noExample', 'exampleInput', 'inputTest'] + if (examplePages.includes(example)) { + this.examplePage = example + } else { + this.examplePage = 'noExample' + } + }, + renderDialog (title, content, minWidth) { + this.dialog = { + title, + content, + minWidth + } + this.toggleDialogBox() + } + }, + watch: { + examplePage: function () { + if (this.examplePage === 'exampleInput') { + this.stdRadios = 'std1' + this.dtRadios = 'dt2' + } else { + this.stdRadios = '' + this.dtRadios = '' + } + } + }, + created () { + this.$store.commit('setAppHeaderInfo', { + icon: 'workspaces', + name: 'Dynamfit' + }) + }, + computed: { + ...mapGetters({ + dialogBoxActive: 'dialogBox' + }) + } +} diff --git a/app/src/pages/nanomine/tools/index.js b/app/src/pages/nanomine/tools/index.js new file mode 100644 index 00000000..7944af86 --- /dev/null +++ b/app/src/pages/nanomine/tools/index.js @@ -0,0 +1,27 @@ +import CorrelationCharacterize from './CorrelationCharacterize.vue' +import CorrelationReconstruct from './CorrelationReconstruct.vue' +import DescriptorCharacterize from './DescriptorCharacterize.vue' +import DescriptorReconstruct from './DescriptorReconstruct.vue' +import IntelligentCharacterize from './IntelligentCharacterize.vue' +import NiblackBinarization from './NiblackBinarization.vue' +import OtsuBinarization from './OtsuBinarization.vue' +import Polymerizer from './Polymerizer.vue' +import SDFCharacterize from './SDFCharacterize.vue' +import SDFReconstruct from './SDFReconstruct.vue' +import TransferLearning from './TransferLearning.vue' +import Dynamfit from './dynamfitTool/Dynamfit.vue' + +export default { + CorrelationCharacterize, + CorrelationReconstruct, + DescriptorCharacterize, + DescriptorReconstruct, + IntelligentCharacterize, + NiblackBinarization, + OtsuBinarization, + Polymerizer, + SDFCharacterize, + SDFReconstruct, + TransferLearning, + Dynamfit +} diff --git a/app/src/pages/nanomine/tools/module/ModuleTools.vue b/app/src/pages/nanomine/tools/module/ModuleTools.vue deleted file mode 100644 index ce09cb0e..00000000 --- a/app/src/pages/nanomine/tools/module/ModuleTools.vue +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/app/src/pages/nanomine/tools/module/moduleTools.html b/app/src/pages/nanomine/tools/module/moduleTools.html deleted file mode 100644 index 0db08234..00000000 --- a/app/src/pages/nanomine/tools/module/moduleTools.html +++ /dev/null @@ -1,5 +0,0 @@ -
      -
      -

      Statistical Learning and Analysis Module Tools

      -
      -
      \ No newline at end of file diff --git a/app/src/pages/nanomine/tools/module/moduleTools.js b/app/src/pages/nanomine/tools/module/moduleTools.js deleted file mode 100644 index 8183cba0..00000000 --- a/app/src/pages/nanomine/tools/module/moduleTools.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - name: 'ModuleTools', - created () { - this.$store.commit('setAppHeaderInfo', { icon: 'workspaces', name: 'Tools' }) - } -} diff --git a/app/src/pages/nanomine/tools/simulation/SimulationTools.vue b/app/src/pages/nanomine/tools/simulation/SimulationTools.vue deleted file mode 100644 index 7f71a96b..00000000 --- a/app/src/pages/nanomine/tools/simulation/SimulationTools.vue +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/app/src/pages/nanomine/tools/simulation/simulationTools.html b/app/src/pages/nanomine/tools/simulation/simulationTools.html deleted file mode 100644 index 438816a5..00000000 --- a/app/src/pages/nanomine/tools/simulation/simulationTools.html +++ /dev/null @@ -1,5 +0,0 @@ -
      -
      -

      Material Property Simulation

      -
      -
      \ No newline at end of file diff --git a/app/src/pages/nanomine/tools/simulation/simulationTools.js b/app/src/pages/nanomine/tools/simulation/simulationTools.js deleted file mode 100644 index e3c8e09a..00000000 --- a/app/src/pages/nanomine/tools/simulation/simulationTools.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - name: 'SimulationTools', - created () { - this.$store.commit('setAppHeaderInfo', { icon: 'workspaces', name: 'Tools' }) - } -} diff --git a/app/src/router/module/nanomine.js b/app/src/router/module/nanomine.js index 6d5f9a25..ca54b26a 100644 --- a/app/src/router/module/nanomine.js +++ b/app/src/router/module/nanomine.js @@ -12,28 +12,85 @@ const nanomineRoutes = [ meta: { requiresAuth: false } }, { - path: '/modtools', - name: 'ModuleTools', - component: () => import(/* webpackChunkName: "modtools" */ '@/pages/nanomine/tools/module/ModuleTools.vue'), - meta: { requiresAuth: false } - }, - { - path: '/simtools', - name: 'SimulationTools', - component: () => import(/* webpackChunkName: "simtools" */ '@/pages/nanomine/tools/simulation/SimulationTools.vue'), - meta: { requiresAuth: false } + name: 'ToolSets', + path: 'tools', + component: () => import(/* webpackChunkName: "toolsetbase" */ '@/pages/nanomine/toolSets/ToolSetBase.vue'), + children: [ + { + path: 'module_homepage', + alias: '', + props: { toolProp: 'ModuleTools' }, + component: () => import(/* webpackChunkName: "toolsettemplate" */ '@/pages/nanomine/toolSets/ModuleTools.vue'), + meta: { requiresAuth: false } + }, + { + path: 'mcr_homepage', + props: { toolProp: 'MCRTools' }, + component: () => import(/* webpackChunkName: "toolsettemplate" */ '@/pages/nanomine/toolSets/MCRTools.vue'), + meta: { requiresAuth: false } + }, + { + path: 'binarization_homepage', + props: { toolProp: 'BinarizationTools' }, + component: () => import(/* webpackChunkName: "toolsettemplate" */ '@/pages/nanomine/toolSets/BinarizationTools.vue'), + meta: { requiresAuth: false } + }, + { + path: 'characterization_homepage', + props: { toolProp: 'CharacterizationTools' }, + component: () => import(/* webpackChunkName: "toolsettemplate" */ '@/pages/nanomine/toolSets/CharacterizationTools.vue'), + meta: { requiresAuth: false } + }, + { + path: 'reconstruction_homepage', + props: { toolProp: 'ReconstructionTools' }, + component: () => import(/* webpackChunkName: "toolsettemplate" */ '@/pages/nanomine/toolSets/ReconstructionTools.vue'), + meta: { requiresAuth: false } + }, + { + path: 'simtools', + props: { toolProp: 'SimulationTools' }, + component: () => import(/* webpackChunkName: "toolsettemplate" */ '@/pages/nanomine/toolSets/SimulationTools.vue'), + meta: { requiresAuth: false } + } + ] }, { - path: '/plot-curation', - name: 'CsvPlotter', - component: () => import(/* webpackChunkName: "plotcuration" */ '@/pages/nanomine/tools/csvPlotter/CsvPlotter.vue'), - meta: { requiresAuth: false } - }, - { - path: '/chemprops', - name: 'ChemProps', - component: () => import(/* webpackChunkName: "chemprops" */ '@/pages/nanomine/tools/chemProps/ChemProps.vue'), - meta: { requiresAuth: false } + name: 'Tools', + path: 'tools', + component: () => import(/* webpackChunkName: "toolsetbase" */ '@/pages/nanomine/tools/ToolBase.vue'), + children: [ + { + path: 'dynamfit', + name: 'Dynamfit', + component: () => import(/* webpackChunkName: "dynamfit" */ '@/pages/nanomine/tools/dynamfitTool/Dynamfit.vue'), + meta: { requiresAuth: false } + }, + { + path: 'dynamfitResult', + name: 'DynamfitResult', + component: () => import(/* webpackChunkName: "dynamfitresult" */ '@/pages/nanomine/tools/dynamfitResult/DynamfitResult.vue'), + meta: { requiresAuth: false } + }, + { + path: 'plot-curation', + name: 'CsvPlotter', + component: () => import(/* webpackChunkName: "plotcuration" */ '@/pages/nanomine/csvPlotter/CsvPlotter.vue'), + meta: { requiresAuth: false } + }, + { + path: 'chemprops', + name: 'ChemProps', + component: () => import(/* webpackChunkName: "chemprops" */ '@/pages/nanomine/tools/chemProps/ChemProps.vue'), + meta: { requiresAuth: false } + }, + { + path: 'chempropsapitoken', + name: 'ChemPropsAPIToken', + component: () => import(/* webpackChunkName: "chempropsapi" */ '@/pages/nanomine/tools/chemPropsAPIToken/ChemPropsAPIToken.vue'), + meta: { requiresAuth: false } + } + ] }, { path: 'about', diff --git a/app/src/store/modules/nanomine/index.js b/app/src/store/modules/nanomine/index.js index aa83a137..c08a2636 100644 --- a/app/src/store/modules/nanomine/index.js +++ b/app/src/store/modules/nanomine/index.js @@ -1,7 +1,9 @@ import howtoModule from './howto/index.js' +import referenceContainerModule from './referenceContainer/index.js' export default { modules: { - howto: howtoModule + howto: howtoModule, + referenceContainer: referenceContainerModule } } diff --git a/app/src/store/modules/nanomine/referenceContainer/getters.js b/app/src/store/modules/nanomine/referenceContainer/getters.js new file mode 100644 index 00000000..cafdc534 --- /dev/null +++ b/app/src/store/modules/nanomine/referenceContainer/getters.js @@ -0,0 +1,5 @@ +export default { + getReferenceById: (state) => (id) => { + return state.references[id] + } +} diff --git a/app/src/store/modules/nanomine/referenceContainer/index.js b/app/src/store/modules/nanomine/referenceContainer/index.js new file mode 100644 index 00000000..d1d5769d --- /dev/null +++ b/app/src/store/modules/nanomine/referenceContainer/index.js @@ -0,0 +1,108 @@ +import getters from './getters' + +export default { + state () { + return { + appHeaderInfo: { + icon: '', + type: 'home', + name: 'MaterialsMine', + subtitle: 'An open source repository for nanocomposite data (NanoMine), and mechanical metamaterials data (MetaMine)' + }, + references: { + '10.1006/jcis.1996.4675': { + authors: 'Rintoul, M.D. and Torquato, S.', + title: 'Reconstruction of the structure of dispersions', + venue: 'Journal of Colloid and Interface Science, 186(2), pp.467-476', + date: '1997' + }, + '10.1103/PhysRevE.57.495': { + authors: 'Yeong,C. and Torquato,S.', + title: 'Reconstructing random media', + venue: 'Physical Review E, vol. 57, no. 1, p.495', + date: '1998' + }, + '10.1115/1.4026649': { + authors: 'Xu, H., Li, Y., Brinson, C. and Chen, W.', + title: 'A descriptor-based design methodology for developing heterogeneous microstructural materials system', + venue: 'Journal of Mechanical Design, 136(5), p.051007', + date: '2014' + }, + '10.1016/j.commatsci.2013.12.046': { + authors: 'Xu, H., Dikin, D.A., Burkhart, C. and Chen, W.', + title: 'Descriptor-based methodology for statistical characterization and 3D reconstruction of microstructural materials', + venue: 'Computational Materials Science, 85, pp.206-216', + date: '2014' + }, + '10.1023/A:1009772018066': { + authors: 'Bradshaw et al.', + title: 'A Sign Control Method for Fitting and Interconverting Material Functions for Linearly Viscoelastic Solids', + venue: 'Mechanics of Time-Dependent Materials. 1997 1(1)', + date: '1997' + }, + '10.1016/j.pmatsci.2018.01.005': { + authors: 'Bostanabad, R., Zhang, Y., Li, X., Kearney, T., Brinson, L. C., Apley, D., Wing K., and Chen, W.', + title: 'Computational Microstructure Characterization and Reconstruction: Review of the State-of-the-art Techniques', + venue: 'Progress in Materials Science 95', + date: 'June 2018' + }, + '978-0134806747': { + keyType: 'ISBN', + authors: 'W. Niblack', + title: 'An Introduction to Image Processing', + venue: 'Englewood Cliffs, NJ: Prentice-Hall, 1986, pp. 115-116.', + date: '1986' + }, + '10.1117/12.805827': { + authors: 'Khurshid, K.,Siddiqi, I., Faure, C. and Vincent, N.', + title: 'Comparison of Niblack inspired Binarization methods for ancient document', + venue: 'DRR, 7247, pp.1-10', + date: '2009' + }, + '10.1109/TSMC.1979.4310076': { + authors: 'N. Otsu', + title: 'A threshold selection method from gray-level histograms', + venue: 'IEEE transactions on systems, man, and cybernetics, vol. 9, no. 1, pp. 62-66', + date: '1979' + }, + '10.1115/DETC201886154': { + authors: 'Ghumman, U.F., Iyer, A., Dulal, R., Munshi, J., Wang, A., Chien, T., Balasubramanian, G., and Chen, W.', + title: 'A Spectral Density Function Approach for Active Layer Design of Organic Photovoltaic Cells', + venue: 'Journal of Mechanical Design, Special Issue on Design of Engineered Materials and Structures', + date: 'July 2018' + }, + '10.1115/1.4036582': { + authors: 'Yu, S., Zhang, Y., Wang, C., Lee, W.K., Dong, B., Odom, T.W., Sun, C. and Chen, W.', + title: 'Characterization and design of functional quasi-random nanostructured materials using spectral density function', + venue: 'Journal of Mechanical Design, 139(7), p.071401', + date: '2017' + }, + '10.1073/pnas.1704711114': { + authors: 'Lee, W. K., Yu, S., Engel, C. J., Reese, T., Rhee, D., Chen, W., & Odom, T. W.', + title: 'Concurrent design of quasi-random photonic nanostructures', + venue: 'Proceedings of the National Academy of Sciences, 114(33), 8734-8739', + date: '2017' + }, + '10.1038/s41598-018-31571-7': { + authors: 'Li, X., Zhang, Y., Zhao, H., Burkhart, C., Brinson, L.C., Chen, W.', + title: 'A Transfer Learning Approach for Microstructure Reconstruction and Structure-property Predictions', + venue: 'Scientific Report', + date: '2018' + }, + '10.1186/s13321-021-00502-6': { + authors: 'Hu, Bingyin, Anqi Lin, and L. Catherine Brinson', + title: 'ChemProps: A RESTful API enabled database for composite polymer name standardization.', + venue: 'Journal of cheminformatics 13.1 (2021): 1-13', + date: '2021' + }, + '10.1021/acs.jcim.7b00425': { + authors: 'Probst, Daniel, and Jean-Louis Reymond', + title: 'Smilesdrawer: parsing and drawing SMILES-encoded molecular structures using client-side javascript.', + venue: 'Journal of chemical information and modeling 58.1 (2018): 1-7.', + date: '2018' + } + } + } + }, + getters +} diff --git a/app/tests/jest/script/test-setup.js b/app/tests/jest/script/test-setup.js index e5ad9b18..20edbc3c 100644 --- a/app/tests/jest/script/test-setup.js +++ b/app/tests/jest/script/test-setup.js @@ -1,2 +1,13 @@ +/* eslint-env jest */ const noop = () => {} Object.defineProperty(window, 'scrollTo', { value: noop, writable: true }) +global.console = { + log: jest.fn(), // console.log are suppressed in tests + + // Keep native behavior for other methods + error: console.error, + warn: console.warn, + info: console.info, + debug: console.debug +} +global.fetch = jest.fn() diff --git a/app/tests/unit/components/nanomine/linechart.spec.js b/app/tests/unit/components/nanomine/linechart.spec.js new file mode 100644 index 00000000..982bb3ec --- /dev/null +++ b/app/tests/unit/components/nanomine/linechart.spec.js @@ -0,0 +1,59 @@ +import createWrapper from '../../../jest/script/wrapper' +import LineChart from '@/components/nanomine/LineChart.vue' + +var wrapper = null + +describe('LineChart.vue', () => { + beforeAll(() => { + wrapper = createWrapper(LineChart, { + props: dataProps + }) + }) + + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + it('loads dataset and options props', async () => { + expect(parseInt(wrapper.find('svg').attributes().width)).toEqual(dataProps.options.width + wrapper.vm.margin.left + wrapper.vm.margin.right) + expect(wrapper.vm.data).toEqual(dataProps.dataset.data) + }) +}) + +const dataProps = { + options: { + height: 400, + width: 500 + }, + dataset: { + xlabel: 'Raman shift (cm-1)', + ylabel: 'Intensity (a.u.)', + data: [ + { x: 1259.041794, y: 7461.002069 }, + { x: 1284.455822, y: 7668.678442 }, + { x: 1305.029083, y: 7979.071219 }, + { x: 1315.114014, y: 8255.669292 }, + { x: 1328.748842, y: 8541.484406 }, + { x: 1342.34333, y: 8832.990198 }, + { x: 1357.672426, y: 8538.21589 }, + { x: 1363.118289, y: 8307.301556 }, + { x: 1372.178117, y: 8090.092543 }, + { x: 1375.75807, y: 7955.790364 }, + { x: 1399.424044, y: 7641.96282 }, + { x: 1426.048263, y: 7480.513694 }, + { x: 1452.672483, y: 7418.153012 }, + { x: 1479.296703, y: 7409.353652 }, + { x: 1505.920923, y: 7462.149812 }, + { x: 1531.576989, y: 7629.835006 }, + { x: 1546.099291, y: 7878.422573 }, + { x: 1550.841977, y: 8146.204404 }, + { x: 1558.125275, y: 8580.580345 }, + { x: 1570.061089, y: 9200.405986 }, + { x: 1576.672058, y: 8969.469607 }, + { x: 1587.003774, y: 8519.735716 }, + { x: 1600.315884, y: 8171.387941 }, + { x: 1616.048377, y: 7837.185866 }, + { x: 1625.326514, y: 7572.507389 } + ] + } +} diff --git a/app/tests/unit/components/nanomine/referencecontainer.spec.js b/app/tests/unit/components/nanomine/referencecontainer.spec.js new file mode 100644 index 00000000..334c56f2 --- /dev/null +++ b/app/tests/unit/components/nanomine/referencecontainer.spec.js @@ -0,0 +1,69 @@ +import createWrapper from '../../../jest/script/wrapper' +import ReferenceContainer from '@/components/nanomine/ReferenceContainer.vue' + +var wrapper = null + +const referenceProp = ['10.1073/pnas.1704711114'] + +const referenceAnswer = { + authors: 'Lee, W. K., Yu, S., Engel, C. J., Reese, T., Rhee, D., Chen, W., & Odom, T. W.', + title: 'Concurrent design of quasi-random photonic nanostructures', + venue: 'Proceedings of the National Academy of Sciences, 114(33), 8734-8739', + date: '2017' +} + +const textMatch = new RegExp(referenceAnswer.title) + +describe('ReferenceContainer.vue', () => { + beforeAll(() => { + wrapper = createWrapper(ReferenceContainer, { + props: { + references: referenceProp, + openOnLoad: false + } + }, false) + }) + + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + it('does not display until opened', () => { + expect(wrapper.text()).not.toMatch(textMatch) + }) + + it('opens when told to, displays correct data', async () => { + const referenceHeader = wrapper.find('h4') + expect(referenceHeader.exists()).toBeTruthy() + await referenceHeader.trigger('click') + expect(wrapper.text()).toMatch(textMatch) + }) + + it('handles empty reference prop', async () => { + wrapper.setProps({ references: [] }) + await wrapper.vm.$nextTick() + expect(wrapper.text()).toEqual('') + }) +}) + +describe('ReferenceContainer.vue', () => { + beforeAll(() => { + wrapper = createWrapper(ReferenceContainer, { + props: { + references: referenceProp, + openOnLoad: true + } + }) + }) + + it('opens on load when told to', () => { + expect(wrapper.text()).toMatch(textMatch) + }) + + it('closes when told to', async () => { + const referenceHeader = wrapper.find('h4') + expect(referenceHeader.exists()).toBeTruthy() + await referenceHeader.trigger('click') + expect(wrapper.text()).not.toMatch(textMatch) + }) +}) diff --git a/app/tests/unit/components/nanomine/smilescanvas.spec.js b/app/tests/unit/components/nanomine/smilescanvas.spec.js new file mode 100644 index 00000000..9410781f --- /dev/null +++ b/app/tests/unit/components/nanomine/smilescanvas.spec.js @@ -0,0 +1,38 @@ +import createWrapper from '../../../jest/script/wrapper' +import SmilesCanvas from '@/components/nanomine/SmilesCanvas.vue' + +var wrapper = null + +const smilesCanvasProps = { + smilesOptions: { + Padding: 0.0, + atomVisualization: 'default', // 'balls', + explicitHydrogens: true, + terminalCarbons: true, + debug: false + }, + smilesInput: '', + formulaHandler: jest.fn(), + onSuccessHandler: jest.fn(), + onErrorHandler: jest.fn() +} + +describe('SmilesCanvas.vue', () => { + beforeAll(() => { + wrapper = createWrapper(SmilesCanvas, { + props: smilesCanvasProps + }) + }) + + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + // Can't debug why, but SmilesCanvas is unable to locate the canvas tag + // internally when run using jest, so it errors out and doesn't parse + // anything. This does not happen when loaded in browser. + // it('parses uSMILES successfully', () => { + // wrapper.setProps({ smilesInput: 'C(C(Cl)[*])[*]' }) + // expect(smilesCanvasProps.formulaHandler.mock.calls[0]).toMatch('C2H3Cl') + // }) +}) diff --git a/app/tests/unit/components/nanomine/toolcard.spec.js b/app/tests/unit/components/nanomine/toolcard.spec.js new file mode 100644 index 00000000..4514a0a5 --- /dev/null +++ b/app/tests/unit/components/nanomine/toolcard.spec.js @@ -0,0 +1,26 @@ +import createWrapper from '../../../jest/script/wrapper' +import ToolCard from '@/components/nanomine/ToolCard.vue' + +var wrapper = null + +const toolProp = { + title: 'PropTitle', + text: 'PropTest', + link: 'testLink', + display: true +} + +describe('ToolCard.vue', () => { + beforeAll(() => { + wrapper = createWrapper(ToolCard, { props: toolProp }, false) + wrapper.vm.$router.push('localhost/nm') + }) + + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + it('displays the provided prop tool', () => { + expect(wrapper.text()).toMatch(new RegExp(toolProp.title)) + }) +}) diff --git a/app/tests/unit/modules/explorer/articleMetadata.spec.js b/app/tests/unit/modules/explorer/articleMetadata.spec.js index 67fc3a25..e252bcdd 100644 --- a/app/tests/unit/modules/explorer/articleMetadata.spec.js +++ b/app/tests/unit/modules/explorer/articleMetadata.spec.js @@ -1,18 +1,6 @@ import articleMetadata from '@/modules/explorer/article/services/articleMetadata' import { rawResponse, cleanResponse } from '@/modules/explorer/article/services/__mocks__/articleMetadata' -global.fetch = jest.fn() - -global.console = { - log: jest.fn(), // console.log are ignored in tests - - // Keep native behavior for other methods - error: console.error, - warn: console.warn, - info: console.info, - debug: console.debug -} - const doi = { doi: '10.1063/1.5046839' } describe('articleMetadata.js', () => { diff --git a/app/tests/unit/pages/nanomine/chemprops.spec.js b/app/tests/unit/pages/nanomine/chemprops.spec.js new file mode 100644 index 00000000..ea50fe00 --- /dev/null +++ b/app/tests/unit/pages/nanomine/chemprops.spec.js @@ -0,0 +1,16 @@ +import createWrapper from '../../../jest/script/wrapper' +import ChemProps from '@/pages/nanomine/tools/chemProps/ChemProps.vue' + +var wrapper = null + +describe('ChemProps.vue', () => { + beforeAll(() => { + wrapper = createWrapper(ChemProps, {}) + }) + + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + // TODO write tests for form logic, once SMILES api is in place +}) diff --git a/app/tests/unit/pages/nanomine/chempropsapitoken.spec.js b/app/tests/unit/pages/nanomine/chempropsapitoken.spec.js new file mode 100644 index 00000000..ca59a73f --- /dev/null +++ b/app/tests/unit/pages/nanomine/chempropsapitoken.spec.js @@ -0,0 +1,16 @@ +import createWrapper from '../../../jest/script/wrapper' +import ChemPropsAPIToken from '@/pages/nanomine/tools/chemPropsAPIToken/ChemPropsAPIToken.vue' + +var wrapper = null + +describe('ChemPropsAPIToken.vue', () => { + beforeAll(() => { + wrapper = createWrapper(ChemPropsAPIToken, {}) + }) + + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + // TODO write tests for API token logic, once authorization is in place +}) diff --git a/app/tests/unit/pages/nanomine/dynamfit.spec.js b/app/tests/unit/pages/nanomine/dynamfit.spec.js new file mode 100644 index 00000000..23f30928 --- /dev/null +++ b/app/tests/unit/pages/nanomine/dynamfit.spec.js @@ -0,0 +1,20 @@ +import createWrapper from '../../../jest/script/wrapper' +import Dynamfit from '@/pages/nanomine/tools/dynamfitTool/Dynamfit.vue' + +var wrapper = null + +describe('Dynamfit.vue', () => { + beforeAll(() => { + wrapper = createWrapper(Dynamfit, {}) + }) + + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + it('displays reference container', () => { + expect(wrapper.find('.reference-container').exists()).toBeTruthy() + }) + + // TODO write tests for form logic, once Dynamfit api is in place +}) diff --git a/app/tests/unit/pages/nanomine/dynamfitresult.spec.js b/app/tests/unit/pages/nanomine/dynamfitresult.spec.js new file mode 100644 index 00000000..dde4d6d3 --- /dev/null +++ b/app/tests/unit/pages/nanomine/dynamfitresult.spec.js @@ -0,0 +1,20 @@ +import createWrapper from '../../../jest/script/wrapper' +import DynamfitResult from '@/pages/nanomine/tools/dynamfitResult/DynamfitResult.vue' + +var wrapper = null + +describe('DynamfitResult.vue', () => { + beforeAll(() => { + wrapper = createWrapper(DynamfitResult, {}) + }) + + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + it('displays reference container', () => { + expect(wrapper.find('.reference-container').exists()).toBeTruthy() + }) + + // TODO write tests for API response logic, once Dynamfit API is in place +}) diff --git a/app/tests/unit/pages/nanomine/howto.spec.js b/app/tests/unit/pages/nanomine/howto.spec.js index cac1d295..d1da7763 100644 --- a/app/tests/unit/pages/nanomine/howto.spec.js +++ b/app/tests/unit/pages/nanomine/howto.spec.js @@ -5,15 +5,6 @@ var wrapper = null // suppress jsdom alert 'Not implemented window.open' window.open = jest.fn() window.open.mockClear() -global.console = { - log: jest.fn(), // console.log are ignored in tests - - // Keep native behavior for other methods - error: console.error, - warn: console.warn, - info: console.info, - debug: console.debug -} describe('HowTo.vue', () => { beforeAll(async () => { diff --git a/app/tests/unit/pages/nanomine/toolsettemplate.spec.js b/app/tests/unit/pages/nanomine/toolsettemplate.spec.js new file mode 100644 index 00000000..626a7ab0 --- /dev/null +++ b/app/tests/unit/pages/nanomine/toolsettemplate.spec.js @@ -0,0 +1,36 @@ +import createWrapper from '../../../jest/script/wrapper' +import ToolSetTemplate from '@/pages/nanomine/toolSets/ToolSetTemplate.vue' + +var wrapper = null + +const toolSetTemplateProps = { + pageContent: { + name: 'ModuleTools', + title: 'Statistical Learning and Analysis Module Tools', + text: 'Statistical learning and analysis modules include web and downloadable packages that can be used to pre-process ' + + 'and analyze structure and material property data. Each of the modules will specify the required input format and output data, and provide ' + + 'a brief introduction behind the mechanism of the algorithm.', + link: 'module_homepage', + tools: [ + 'Dynamfit' + ], + toolSets: [ + 'MCRTools' + ] + } +} + +describe('ToolSetTemplate.vue', () => { + beforeAll(() => { + wrapper = createWrapper(ToolSetTemplate, { + props: toolSetTemplateProps + }) + }) + it('mounts properly', () => { + expect(wrapper.exists()).toBeTruthy() + }) + + it('displays tool cards', async () => { + expect(wrapper.find('.tool-card').exists()).toBeTruthy() + }) +}) From e970804839596f9a565318ba2e6f3cde8e659508 Mon Sep 17 00:00:00 2001 From: Jamie McCusker Date: Tue, 22 Mar 2022 13:52:01 -0400 Subject: [PATCH 171/306] Updated dockerfile to use released whyis. --- whyis/Dockerfile | 16 ++-------------- whyis/Dockerfile.dev | 16 ++-------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/whyis/Dockerfile b/whyis/Dockerfile index 25fd9ec0..9a7a1a38 100644 --- a/whyis/Dockerfile +++ b/whyis/Dockerfile @@ -1,17 +1,5 @@ -FROM ubuntu:20.04 -RUN apt-get update && apt-get install -y software-properties-common gcc - -RUN apt-get update && apt-get install -y \ - python3.8-distutils \ - python3.8-dev \ - python3-pip \ - python3.8-venv \ - curl \ - libdb5.3-dev \ - default-jdk-headless -RUN python3.8 -m venv /opt/venv -RUN /opt/venv/bin/pip install requests>=2.27.1 wheel gunicorn -RUN /opt/venv/bin/pip install whyis==2.0b1 whyis-unit-converter==0.0.2 +FROM tetherlessworld/whyis:latest +RUN /opt/venv/bin/pip install whyis-unit-converter==0.0.2 COPY ./materialsmine /app WORKDIR '/app' CMD [ "/bin/bash" ] diff --git a/whyis/Dockerfile.dev b/whyis/Dockerfile.dev index f0dbe426..83432f03 100644 --- a/whyis/Dockerfile.dev +++ b/whyis/Dockerfile.dev @@ -1,16 +1,4 @@ -FROM ubuntu:20.04 as dependencies -RUN apt-get update && apt-get install -y software-properties-common gcc - -RUN apt-get update && apt-get install -y \ - python3.8-distutils \ - python3.8-dev \ - python3-pip \ - python3.8-venv \ - curl \ - libdb5.3-dev \ - default-jdk-headless -RUN python3.8 -m venv /opt/venv -RUN /opt/venv/bin/pip install requests>=2.27.1 wheel gunicorn -RUN /opt/venv/bin/pip install whyis==2.0b1 whyis-unit-converter==0.0.2 +FROM tetherlessworld/whyis:latest +RUN /opt/venv/bin/pip install whyis-unit-converter==0.0.2 WORKDIR '/app' CMD [ "/bin/bash" ] From 1f4bef6cb51623f84337c7b2f2d6a4fde0c43ca2 Mon Sep 17 00:00:00 2001 From: Anya Wallace Date: Tue, 22 Mar 2022 12:45:28 -0700 Subject: [PATCH 172/306] #144: Data voyager initial working migration --- app/package.json | 1 + app/src/components/explorer/DataVoyager.vue | 54 +++++++++++++ .../chart/datavoyager/DataVoyagerPage.vue | 2 + .../chart/datavoyager/data-voyager-page.html | 68 ++++++++++++++++ .../chart/datavoyager/data-voyager-page.js | 79 +++++++++++++++++++ .../pages/explorer/chart/view/vega-view.html | 12 +-- app/src/router/module/explorer.js | 6 ++ 7 files changed, 216 insertions(+), 6 deletions(-) create mode 100644 app/src/components/explorer/DataVoyager.vue create mode 100644 app/src/pages/explorer/chart/datavoyager/DataVoyagerPage.vue create mode 100644 app/src/pages/explorer/chart/datavoyager/data-voyager-page.html create mode 100644 app/src/pages/explorer/chart/datavoyager/data-voyager-page.js diff --git a/app/package.json b/app/package.json index fce00e9d..6c71c6be 100644 --- a/app/package.json +++ b/app/package.json @@ -65,6 +65,7 @@ "sass": "^1.26.5", "sass-loader": "^8.0.2", "sinon": "^12.0.1", + "style-loader": "^2.0.0", "vue-template-compiler": "^2.6.11" }, "gitHooks": { diff --git a/app/src/components/explorer/DataVoyager.vue b/app/src/components/explorer/DataVoyager.vue new file mode 100644 index 00000000..f68b37c0 --- /dev/null +++ b/app/src/components/explorer/DataVoyager.vue @@ -0,0 +1,54 @@ + + + diff --git a/app/src/pages/explorer/chart/datavoyager/DataVoyagerPage.vue b/app/src/pages/explorer/chart/datavoyager/DataVoyagerPage.vue new file mode 100644 index 00000000..f0f8c2d7 --- /dev/null +++ b/app/src/pages/explorer/chart/datavoyager/DataVoyagerPage.vue @@ -0,0 +1,2 @@ + + diff --git a/app/src/pages/explorer/chart/datavoyager/data-voyager-page.html b/app/src/pages/explorer/chart/datavoyager/data-voyager-page.html new file mode 100644 index 00000000..f30e03c4 --- /dev/null +++ b/app/src/pages/explorer/chart/datavoyager/data-voyager-page.html @@ -0,0 +1,68 @@ +
      +
      +
      +
      + + + Save current spec as new chart + + save + + + + Select current spec and return to Viz Editor + + check + + + Return to chart view + arrow_back + +
      +
      +
      +
      + Data Voyager + : {{chart.title}} +
      +
      + +
      +
      + +
      +
      \ No newline at end of file diff --git a/app/src/pages/explorer/chart/datavoyager/data-voyager-page.js b/app/src/pages/explorer/chart/datavoyager/data-voyager-page.js new file mode 100644 index 00000000..0f3afab1 --- /dev/null +++ b/app/src/pages/explorer/chart/datavoyager/data-voyager-page.js @@ -0,0 +1,79 @@ +import { mapGetters, mapActions, mapMutations } from 'vuex' +// import { Slug } from "../../../../modules"; +// import { +// copyChart, +// saveChart, +// transformSparqlData +// } from "@/modules/vega-chart"; +import { querySparql, parseSparql } from '@/modules/sparql' +import DataVoyager from '@/components/explorer/DataVoyager' +import spinner from '@/components/Spinner' + +export default { + data () { + return { + loading: true, + voyagerSpec: null, + specJsonEditorOpts: { + mode: 'code', + mainMenuBar: false + } + } + }, + components: { + DataVoyager, + spinner + }, + computed: { + ...mapGetters('vega', ['chart']), + isNewChart () { + // return this.pageUri === VIEW_URIS.CHART_EDITOR + return false + } + }, + methods: { + ...mapActions('vega', ['loadChart']), + ...mapMutations('vega', ['setBaseSpec']), + // slugify: Slug, + async loadData () { + this.loading = true + if (!this.isNewChart) { + await this.loadChart(`http://nanomine.org/viz/${this.$route.params.uri}`) + } + const sparqlResults = await querySparql(this.chart.query) + this.data = { values: parseSparql(sparqlResults) } + this.loading = false + }, + saveAsChart () { + // this.loading = true; + // const newChart = copyChart(this.chart); + // newChart.title = `DataVoyager Variant: ${newChart.title}`; + // newChart.baseSpec = this.voyagerSpec; + // console.log(newChart); + // delete newChart.depiction; + // saveChart(newChart).then(() => + // goToView(newChart.uri, DEFAULT_VIEWS.EDIT) + // ); + }, + selectSpec () { + // this.setBaseSpec(this.voyagerSpec) + // this.goToChartEditor() + }, + goToChartView () { + // goToView(this.pageUri, DEFAULT_VIEWS.VIEW); + }, + goToChartEditor () { + // goToView(VIEW_URIS.CHART_EDITOR, DEFAULT_VIEWS.NEW); + }, + goBack () { + // if (this.isNewChart) { + // this.goToChartEditor() + // } else { + // this.goToChartView() + // } + } + }, + mounted () { + this.loadData() + } +} diff --git a/app/src/pages/explorer/chart/view/vega-view.html b/app/src/pages/explorer/chart/view/vega-view.html index 162f8e57..969f8978 100644 --- a/app/src/pages/explorer/chart/view/vega-view.html +++ b/app/src/pages/explorer/chart/view/vega-view.html @@ -27,12 +27,12 @@ integration_instructions
      -
      - - View Data in Voyager - dynamic_form - -
      + + + View Data in Voyager + dynamic_form + +
      Edit Chart diff --git a/app/src/router/module/explorer.js b/app/src/router/module/explorer.js index 321e0462..929b2224 100644 --- a/app/src/router/module/explorer.js +++ b/app/src/router/module/explorer.js @@ -49,6 +49,12 @@ const explorerRoutes = [ name: 'ChartView', component: () => import('@/pages/explorer/chart/view/VegaView.vue'), meta: { requiresAuth: false } + }, + { + path: 'voyager/:uri', + name: 'ChartDataVoyager', + component: () => import('@/pages/explorer/chart/datavoyager/DataVoyagerPage.vue'), + meta: { requiresAuth: false } } ] }, From 95257a55b5e0e16153737ac1262ab516d8c285f4 Mon Sep 17 00:00:00 2001 From: Rory Schadler <48921090+roryschadler@users.noreply.github.com> Date: Fri, 25 Mar 2022 12:38:13 -0400 Subject: [PATCH 173/306] #24 migrate upload (#147) * #24: Initial XML Uploader commit Converted vuetify to vue-material, added references to the reference store. * #24: Fix old references to xml-uploader * #24: Remove mock dataset from testing * #24: Write unit test for dataset viewer * #24: Rename DatasetCreateOrSelect to DatasetViewer * #24: Updated dialog rendering, removed autologin --- app/src/components/nanomine/DatasetViewer.vue | 353 ++++++++++++++++++ app/src/pages/nanomine/Home/Home.vue | 2 +- .../nanomine/xmlUploader/XmlUploader.vue | 8 + .../nanomine/xmlUploader/xmlUploader.html | 115 +++++- .../pages/nanomine/xmlUploader/xmlUploader.js | 157 +++++++- app/src/router/module/nanomine.js | 2 +- .../nanomine/referenceContainer/index.js | 12 + .../components/nanomine/datasetviewer.spec.js | 58 +++ app/tests/unit/pages/nanomine/home.spec.js | 2 +- 9 files changed, 702 insertions(+), 7 deletions(-) create mode 100644 app/src/components/nanomine/DatasetViewer.vue create mode 100644 app/tests/unit/components/nanomine/datasetviewer.spec.js diff --git a/app/src/components/nanomine/DatasetViewer.vue b/app/src/components/nanomine/DatasetViewer.vue new file mode 100644 index 00000000..3e303884 --- /dev/null +++ b/app/src/components/nanomine/DatasetViewer.vue @@ -0,0 +1,353 @@ + + + + + diff --git a/app/src/pages/nanomine/Home/Home.vue b/app/src/pages/nanomine/Home/Home.vue index b7f23dfd..3fe4d732 100644 --- a/app/src/pages/nanomine/Home/Home.vue +++ b/app/src/pages/nanomine/Home/Home.vue @@ -29,7 +29,7 @@