Spaces:
				
			
			
	
			
			
					
		Running
		
	
	
	
			
			
	
	
	
	
		
		
					
		Running
		
	Upload 3 files
Browse files- Dockerfile +26 -0
 - app.py +125 -0
 - 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
         
     |