IAMJB HF staff commited on
Commit
f121890
1 Parent(s): 606b16c

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +26 -0
  2. app.py +125 -0
  3. requirements.txt +9 -0
Dockerfile ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use the official Python image from Docker Hub
2
+ FROM python:3.9-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && \
6
+ apt-get install -y --no-install-recommends \
7
+ cmake \
8
+ build-essential \
9
+ libssl-dev \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ # Set the working directory
13
+ WORKDIR /app
14
+
15
+ # Copy requirements and install
16
+ COPY requirements.txt .
17
+ RUN pip install --no-cache-dir -r requirements.txt
18
+
19
+ # Copy the application code
20
+ COPY app.py .
21
+
22
+ # Expose the port Dash will run on
23
+ EXPOSE 7860
24
+
25
+ # Run the app
26
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pymatgen.ext.matproj import MPRester
3
+ import crystal_toolkit.components as ctc
4
+ from crystal_toolkit.settings import SETTINGS
5
+
6
+ import dash
7
+ from dash import html, dcc
8
+ from dash.dependencies import Input, Output, State
9
+
10
+ # Set your Materials Project API key
11
+ MATERIALS_PROJECT_API_KEY = os.getenv('MATERIALS_PROJECT_API_KEY')
12
+
13
+ # Initialize the Dash app
14
+ app = dash.Dash(__name__, assets_folder=SETTINGS.ASSETS_PATH)
15
+ server = app.server # Expose the server for deployment
16
+
17
+ # Define the app layout
18
+ layout = html.Div([
19
+ dcc.Markdown("## Interactive Crystal Viewer"),
20
+ html.Div([
21
+ html.Div([
22
+ html.Label("Search by Chemical System (e.g., 'Ac-Cd-Ge')"),
23
+ dcc.Input(
24
+ id='query-input',
25
+ type='text',
26
+ value='Ac-Cd-Ge',
27
+ placeholder='Ac-Cd-Ge',
28
+ style={'width': '100%'}
29
+ ),
30
+ ], style={'width': '70%', 'display': 'inline-block', 'verticalAlign': 'top'}),
31
+ html.Div([
32
+ html.Button('Search', id='search-button', n_clicks=0),
33
+ ], style={'width': '28%', 'display': 'inline-block', 'paddingLeft': '2%', 'verticalAlign': 'top'}),
34
+ ], style={'margin-bottom': '20px'}),
35
+ html.Div([
36
+ html.Label("Select Material"),
37
+ dcc.Dropdown(
38
+ id='material-dropdown',
39
+ options=[], # Empty options initially
40
+ value=None
41
+ ),
42
+ ], style={'margin-bottom': '20px'}),
43
+ html.Button('Display Material', id='display-button', n_clicks=0),
44
+ html.Div([
45
+ html.Div(id='structure-container', style={'width': '48%', 'display': 'inline-block', 'verticalAlign': 'top'}),
46
+ html.Div(id='properties-container',
47
+ style={'width': '48%', 'display': 'inline-block', 'paddingLeft': '4%', 'verticalAlign': 'top'}),
48
+ ], style={'margin-top': '20px'}),
49
+ ])
50
+
51
+
52
+ # Function to search for materials
53
+ def search_materials(query):
54
+ with MPRester(MATERIALS_PROJECT_API_KEY) as mpr:
55
+ results = mpr.summary.search(
56
+ chemsys=query,
57
+ fields=["material_id", "formula_pretty"]
58
+ )
59
+ options = [{'label': f"{res.formula_pretty} ({res.material_id})", 'value': res.material_id} for res in results]
60
+ return options
61
+
62
+
63
+ # Callback to update the material dropdown based on search
64
+ @app.callback(
65
+ [Output('material-dropdown', 'options'),
66
+ Output('material-dropdown', 'value')],
67
+ Input('search-button', 'n_clicks'),
68
+ State('query-input', 'value'),
69
+ )
70
+ def update_material_dropdown(n_clicks, query):
71
+ if n_clicks is None or not query:
72
+ return [], None
73
+ options = search_materials(query)
74
+ if not options:
75
+ return [], None
76
+ return options, options[0]['value']
77
+
78
+
79
+ # Callback to display the selected material
80
+ @app.callback(
81
+ [Output('structure-container', 'children'),
82
+ Output('properties-container', 'children')],
83
+ Input('display-button', 'n_clicks'),
84
+ State('material-dropdown', 'value')
85
+ )
86
+ def display_material(n_clicks, material_id):
87
+ if n_clicks is None or not material_id:
88
+ return '', ''
89
+ with MPRester(MATERIALS_PROJECT_API_KEY) as mpr:
90
+ material = mpr.get_structure_by_material_id(material_id)
91
+ summary = mpr.summary.get_data_by_id(material_id)
92
+
93
+ # Create the StructureMoleculeComponent
94
+ structure_component = ctc.StructureMoleculeComponent(material)
95
+
96
+ # Extract key properties
97
+ properties = {
98
+ "Material ID": material_id,
99
+ "Formula": summary.formula_pretty,
100
+ "Energy Above Hull (eV/atom)": summary.energy_above_hull,
101
+ "Space Group": summary.symmetry.symbol,
102
+ "Band Gap (eV)": summary.band_gap,
103
+ "Formation Energy (eV/atom)": summary.formation_energy_per_atom,
104
+ "Magnetic Ordering": summary.ordering,
105
+ "Total Magnetization (μB/f.u.)": summary.total_magnetization,
106
+ "Is Stable": summary.is_stable,
107
+ "Crystal System": summary.symmetry.crystal_system,
108
+ "Density (g/cm³)": summary.density,
109
+ }
110
+
111
+ # Format properties as an HTML table
112
+ properties_html = html.Table([
113
+ html.Tbody([
114
+ html.Tr([html.Th(key), html.Td(str(value))]) for key, value in properties.items()
115
+ ])
116
+ ], style={'border': '1px solid black', 'width': '100%', 'borderCollapse': 'collapse'})
117
+
118
+ return structure_component.layout(), properties_html
119
+
120
+
121
+ # Register crystal toolkit with the app
122
+ ctc.register_crystal_toolkit(app, layout)
123
+
124
+ if __name__ == '__main__':
125
+ app.run_server(debug=True, port=7860)
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ dash==2.11.1
2
+ crystal-toolkit[all]
3
+ pymatgen
4
+ numpy
5
+ scipy
6
+ matplotlib
7
+ plotly
8
+ pandas
9
+ dash-bootstrap-components