Skip to content

Commit

Permalink
update website ui 🍒 (#440)
Browse files Browse the repository at this point in the history
  • Loading branch information
jacksund authored May 4, 2023
1 parent 3eb84db commit 08c0144
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 50 deletions.
12 changes: 12 additions & 0 deletions src/simmate/engine/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,18 @@ def _deserialize_parameters(
"supercell_start": Structure,
"supercell_end": Structure,
}
# Add extra parameter mappings from internal code
try:
from simmate_corteva.rdkit import Molecule

parameter_mappings.update(
{
"molecule": Molecule,
"molecules": Molecule,
}
)
except:
pass # just move on if there's no module present

for parameter, target_class in parameter_mappings.items():
if parameter in parameters.keys():
Expand Down
1 change: 1 addition & 0 deletions src/simmate/utilities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
chunk_list,
get_app_submodule,
get_chemical_subsystems,
get_class,
get_conda_env,
get_latest_version,
str_to_datatype,
Expand Down
21 changes: 14 additions & 7 deletions src/simmate/utilities/other.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import sys

import requests
from django.apps import AppConfig

import simmate

Expand Down Expand Up @@ -207,6 +208,18 @@ def str_to_datatype(
return value


def get_class(class_path: str):
"""
Given the import path for a python class (e.g. path.to.MyClass), this
utility will load the class given (MyClass).
"""
config_modulename = ".".join(class_path.split(".")[:-1])
config_name = class_path.split(".")[-1]
config_module = importlib.import_module(config_modulename)
config = getattr(config_module, config_name)
return config


def get_app_submodule(
app_name: str,
submodule_name: str,
Expand All @@ -216,13 +229,7 @@ def get_app_submodule(
This is useful for checking if there are workflows or urls defined, which
are optional accross all apps. None is return if no app exists
"""
# modulename is by cutting off the "apps.AppConfig" part of the config
# path. For example, "simmate.apps.vasp.apps.VaspConfig" would
# give an app_modulename of "simmate.apps.vasp"
config_modulename = ".".join(app_name.split(".")[:-1])
config_name = app_name.split(".")[-1]
config_module = importlib.import_module(config_modulename)
config = getattr(config_module, config_name)
config = get_class(app_name)
app_path = config.name
submodule_path = f"{app_path}.{submodule_name}"

Expand Down
30 changes: 11 additions & 19 deletions src/simmate/website/core/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-

import importlib

from django.contrib.auth.decorators import login_required
from django.db.models import F
from django.shortcuts import render
Expand All @@ -14,6 +12,7 @@
MatprojStructure,
OqmdStructure,
)
from simmate.utilities import get_app_submodule, get_class
from simmate.website.data_explorer.forms import ChemicalSystemForm


Expand Down Expand Up @@ -112,25 +111,18 @@ def home(request):


def apps(request):
################
# This section of code is copied from...
# simmate.web.core.urls
# Consider making another util. I might want a SimmateConfig class that
# subclasses Django app's Config class. Add things like "learn-more" links
# and short descriptions
extra_apps = []
for app_name in SIMMATE_APPS:
config_modulename = ".".join(app_name.split(".")[:-1])
config_name = app_name.split(".")[-1]
config_module = importlib.import_module(config_modulename)
config = getattr(config_module, config_name)
app_path = config.name
simple_name = app_path.split(".")[-1]
urls_found = importlib.util.find_spec(f"{app_path}.urls") is not None
if urls_found:
extra_apps.append(simple_name)
# TODO: maybe grab a short description too?
################
urls_path = get_app_submodule(app_name, "urls")
if urls_path:
app_config = get_class(app_name)
extra_apps.append(
{
"verbose_name": app_config.verbose_name,
"short_name": app_config.name.split(".")[-1],
"description_short": app_config.description_short,
}
)
context = {"extra_apps": extra_apps}
template = "core_components/apps.html"
return render(request, template, context)
Expand Down
12 changes: 7 additions & 5 deletions src/simmate/website/templates/core_components/apps.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ <h1 class="jumbotron-heading">Apps</h1>
</section>
<!-- List of Cards -->
<div class="row">
{% for app_name in extra_apps %}
{% for extra_app in extra_apps %}
<div class="col-md-4">
<div class="card border-primary border">
<div class="card border-primary border" style="height: 90%">
<div class="card-body">
<h5 class="card-title text-primary">{{ app_name }}</h5>
<p class="card-text">an example description for this app</p>
<a role="button" class="btn btn-primary btn-sm" href="{{ app_name }}">Try it out!</a>
<h5 class="card-title text-primary">{{ extra_app.verbose_name }}</h5>
<p class="card-text">{{ extra_app.description_short }}</p>
<a role="button"
class="btn btn-primary btn-sm"
href="{{ extra_app.short_name }}">Explore</a>
</div>
</div>
</div>
Expand Down
43 changes: 39 additions & 4 deletions src/simmate/website/templates/core_components/site_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
id="app-style"/>
<!-- Load Plotly Javascript -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<!-- Django-unicorn scripts for dynamic webpages -->
{% unicorn_scripts %}
<!-- Load ChemDoodle Javascript, CSS, default styling setting, and a custom drawing util -->
<link rel="stylesheet"
href="https://archives.simmate.org/assets/chemdoodle/ChemDoodleWeb.css"
Expand All @@ -42,6 +44,7 @@
type="text/css">
<script type="text/javascript"
src="https://archives.simmate.org/assets/chemdoodle/uis/ChemDoodleWeb-uis.js"></script>
<!-- Custom Javascript (this should move to a static file)-->
<script>
//ChemDoodle.DEFAULT_STYLES.
ChemDoodle.DEFAULT_STYLES.bondLength_2D = 14.4;
Expand All @@ -65,12 +68,44 @@
let molecule = ChemDoodle.readMOL(sdf_str);
myCanvas.loadMolecule(molecule);
// I can't find how to remove the boarders... so I just remove the class
var test = document.getElementById(canvas_id);
test.classList.remove("ChemDoodleWebComponent");
var canvas = document.getElementById(canvas_id);
canvas.classList.remove("ChemDoodleWebComponent");
};
// function to grab value from sketcher and paste it into a target unicorn input
var get_mol_from_sketcher = function(
sketcher,
textarea_id,
unicorn_view,
unicorn_method,
) {
// priority is given to the text input
var user_input = document.getElementById(textarea_id);
var molStr;
if (user_input.value) {
molStr = user_input.value;
}
// otherwise we pull what is in the sketcher and use that
else {
let mol = sketcher.getMolecule();
molStr = ChemDoodle.writeMOL(mol); // or .writeMOLV3(mol); ...?
}
// and then we call unicorn to update the value
Unicorn.call(unicorn_view, unicorn_method, JSON.stringify(molStr));
};
// function to unhide + update a canvas for doodle molecules
var refresh_doodle = function(canvas_id, new_sdf_str) {
// todo-- combine with doodle_molecule fxn above
myCanvas = new ChemDoodle.ViewerCanvas(canvas_id);
myCanvas.styles.backgroundColor = undefined;
myCanvas.emptyMessage = 'No molecule loaded!';
let molecule = ChemDoodle.readMOL(new_sdf_str);
myCanvas.loadMolecule(molecule);
// make canvas visible and remove boarder
let canvas = document.getElementById(canvas_id);
canvas.removeAttribute("hidden");
canvas.classList.remove("ChemDoodleWebComponent");
};
</script>
<!-- Django-unicorn scripts for dynamic webpages -->
{% unicorn_scripts %}
<!-- Some pages may require extra lines in the header such as loading extra libraries -->
{% block extraheader %}{% endblock %}
</head>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ <h1 class="jumbotron-heading">Data Explorer</h1>
<div class="row">
{% for data_type, datasets in all_datasets.items %}
{% if datasets %}
<h3>{{ data_type }}</h3>
<h3 class="mt-4">{{ data_type }}</h3>
{% for dataset in datasets %}
<div class="col-md-4">
<div class="card border-primary border" style="height: 90%">
Expand Down
9 changes: 8 additions & 1 deletion src/simmate/website/templates/workflows/all.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,19 @@ <h1 class="jumbotron-heading">Workflows</h1>
Explore all of the workflows available with Simmate, submit new calculations, and view the results of past runs
</p>
</div>
<div class="alert alert-danger" role="alert">
<i class="mdi mdi-alert"></i><i class="mdi mdi-alert"></i>
<strong>DANGER</strong>
<i class="mdi mdi-alert"></i><i class="mdi mdi-alert"></i>
<br>
These web pages are still in early testing and some links may be broken. We expect that workflow submissions/views will go through many changes in the next few months.
</div>
</section>
<!-- List of Cards -->
<div class="row pt-3">
{% for workflow_type, workflow_description in workflows_metadata.items %}
<div class="col-md-4">
<div class="card border-primary border">
<div class="card border-primary border" style="height: 90%">
<div class="card-body">
<h5 class="card-title text-primary">{{ workflow_type }}</h5>
<p class="card-text">{{ workflow_description }}</p>
Expand Down
39 changes: 27 additions & 12 deletions src/simmate/website/workflows/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,42 @@
"Evaluate where electrons exist in a structure and assign them to a "
"specific site/atom. Used to predicted oxidation states."
),
# "band-structure": (
# "These workflows calculate the electronic band structure for a material."
# ),
# "density-of-states": (
# "These workflows calculate the electronic density of states for a material."
# ),
"band-structure": (
"These workflows calculate the electronic band structure for a material."
),
"density-of-states": (
"These workflows calculate the electronic density of states for a material."
),
"dynamics": (
"Run a molecular dynamics simulation for a material. Involves "
"iteratively evaluating the energy/forces at "
"specific temperature (or temperature ramp)."
),
# "diffusion": (
# "These workflows evaluate the diffusion of an atom through a material. "
# "At this time, these workflows are entirely Nudged-Elastic-Band (NEB) "
# "calculations."
# ),
"diffusion": (
"These workflows evaluate the diffusion of an atom through a material. "
"At this time, these workflows are entirely Nudged-Elastic-Band (NEB) "
"calculations."
),
"structure-prediction": (
"Predict the most stable structure when given only chemical composition "
"or system. Strategies range from evolutionary searches to "
"substituition of known materials."
),
"conformer-generation": (
"Predict the most stable structure when given only chemical composition "
"or system. Strategies range from evolutionary searches to "
"substituition of known materials."
),
"docking": (
"Analyze ligand-protein binding affinity and preferred orientation. "
"Simulations can also be ran accross larger datasets "
"to evaluate probable mode(s) of action."
),
"clustering": (
"Group a list of molecules or crystals based on chemical similarity. "
"These workflows can also be used to generate diverse subsets of compounds "
"for further analysis."
),
}


Expand Down Expand Up @@ -73,7 +88,7 @@ def workflows_by_type(request, workflow_type):
workflow_names = get_workflow_names_by_type(
workflow_type,
app,
remove_no_database_flows=True,
remove_no_database_flows=False, # BUG: this breaks some views...
)
workflow_dict[app] = [get_workflow(n) for n in workflow_names]

Expand Down
2 changes: 1 addition & 1 deletion src/simmate/workflows/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ def get_all_workflows(
"""
app_workflows = []
for app_name in apps_to_search:
# check if there is a workflow module for this app and load it if so
workflow_path = get_app_submodule(app_name, "workflows")
if not workflow_path:
continue # skip to the next app

app_workflow_module = importlib.import_module(workflow_path)

# iterate through each available object in the workflows file and find
Expand Down

0 comments on commit 08c0144

Please sign in to comment.