3-phase Composite Example¶
from hashin_shtrikman_mp.core.user_input import Aggregate, MaterialProperty, Material, MixtureProperty, Mixture, UserInput
from hashin_shtrikman_mp.core import GeneticAlgorithm
from hashin_shtrikman_mp.core.genetic_algorithm import OptimizationParams
from hashin_shtrikman_mp.core.visualization import OptimizationResultVisualizer
from hashin_shtrikman_mp.core.match_finder import MatchFinder
from IPython.display import Image
Define properties for each material
properties_mat_1 = [
MaterialProperty(prop='elec_cond_300k_low_doping', upper_bound=120, lower_bound=1e-7),
MaterialProperty(prop='therm_cond_300k_low_doping', upper_bound=2, lower_bound=1e-7),
MaterialProperty(prop='bulk_modulus', upper_bound=500, lower_bound=50),
MaterialProperty(prop='shear_modulus', upper_bound=500, lower_bound=80),
MaterialProperty(prop='universal_anisotropy', upper_bound=6, lower_bound=1),
]
properties_mat_2 = [
MaterialProperty(prop='elec_cond_300k_low_doping', upper_bound=78, lower_bound=1e-7),
MaterialProperty(prop='therm_cond_300k_low_doping', upper_bound=2, lower_bound=1e-7),
MaterialProperty(prop='bulk_modulus', upper_bound=400, lower_bound=20),
MaterialProperty(prop='shear_modulus', upper_bound=500, lower_bound=100),
MaterialProperty(prop='universal_anisotropy', upper_bound=4.3, lower_bound=1.3),
]
properties_mat_3 = [
MaterialProperty(prop='elec_cond_300k_low_doping', upper_bound=78, lower_bound=1e-7),
MaterialProperty(prop='therm_cond_300k_low_doping', upper_bound=2, lower_bound=1e-7),
MaterialProperty(prop='bulk_modulus', upper_bound=700, lower_bound=20),
MaterialProperty(prop='shear_modulus', upper_bound=600, lower_bound=100),
MaterialProperty(prop='universal_anisotropy', upper_bound=2.1, lower_bound=0.9),
]
Create an instance of the Material
class for each material
mat_1 = Material(name='mat_1', properties=properties_mat_1)
mat_2 = Material(name='mat_2', properties=properties_mat_2)
mat_3 = Material(name='mat_3', properties=properties_mat_3)
Define properties for the mixture
properties_mixture = [
MixtureProperty(prop='elec_cond_300k_low_doping', desired_prop=9),
MixtureProperty(prop='therm_cond_300k_low_doping', desired_prop=0.9),
MixtureProperty(prop='bulk_modulus', desired_prop=280),
MixtureProperty(prop='shear_modulus', desired_prop=230),
MixtureProperty(prop='universal_anisotropy', desired_prop=1.5),
]
Create an instance of the Mixture
class to store the desired composite properties and aggregate the materials and mixture into a list for later iteration
mixture = Mixture(name='mixture', properties=properties_mixture)
Create an instance of the Aggregate
class which aggregates the material property search bounds across materials to find the maximum upper bound per property and minimum lower bound per property.
Then call get_bounds_dict
to store the search bounds in a dictionary for use when finding real material matches in the Materials Project database.
aggregate = Aggregate(name='aggregate', components=[mat_1, mat_2, mat_3, mixture])
bounds_dict = aggregate.get_bounds_dict()
Create an instance of the UserInput
class from the materials and mixture(s) just created
user_input= UserInput(materials=[mat_1, mat_2, mat_3], mixtures=[mixture])
Initialize an instance of the OptimizationParams
class using the previously defined UserInput
, as well as an instance of the GeneticAlgorithm
class
optimization_parameters = OptimizationParams.from_user_input(user_input)
ga = GeneticAlgorithm()
Run the optimization $n=3$ materials. Identify the optimal properties of each material and the respective volume fractions that achieve the desired composite material properties.
ga_result = ga.run(user_input, gen_counter=False)
Create an instance of the OptimizationResultVisualizer
class using the genetic algorithm result
visualizer = OptimizationResultVisualizer(ga_result)
Print the optimization results as a table. Each row represents a theoretical material.
visualizer.print_table_of_best_designs(rows=10)
Plot the genetic algorithm convergence plot
visualizer.plot_optimization_results()

Plot the contributions to the cost function for the best performer
Note on how many contributions to expect: Per property, there is
- 1 effective property term
- (Non-modulus) 2 concentration factor terms per material
- (Modulus) 2 concentration factor terms per coupled (bulk, shear) moduli per material -- not considered individual properties
For example, for a 3-phase composite which considers carrier-transport and elastic property categories, not including volume fraction, there are 5 properties per material, so in total we expect
- 5 effective property terms
- 18 = 6 concentration factor terms (load and response terms for electrical conductivity, thermal conductivity, and universal anisotropy) $\times$ 3 materials
- 6 = 2 concentration factor terms (coupled deviatoric and hydrostatic terms from coupled bulk/shear moduli) $\times$ 3 materials
visualizer.plot_cost_func_contribs()
Cost: 0.04477574762468891, Number effective properties: 5, Number of concentration factors: 24

Create an instance of the MatchFinder
class using the genetic algorithm result
match_finder = MatchFinder(ga_result)
Finally, get real material matches
matches_dict = match_finder.get_material_matches(bounds_dict)
Retrieving SummaryDoc documents: 0%| | 0/261 [00:00<?, ?it/s]
Let's take a peak at the matches that were returned
print(f'Material Matches:')
for mat in matches_dict.keys():
print(f' For {mat}:')
for match_dict in matches_dict[mat]:
for mpid in match_dict.keys():
print(f' {mpid}')
Material Matches: For mat1: mp-684591 mp-752826 mp-3098 mp-3748 mp-3536 mp-4391 mp-5924 mp-753459 mp-2657 mp-755759 mp-4820 For mat2: mp-684591 mp-752826 mp-3098 mp-3748 mp-3536 mp-4391 mp-5924 mp-753459 mp-2657 mp-755759 mp-4820 For mat3: mp-684591 mp-752826 mp-3098 mp-3748 mp-3536 mp-4391 mp-5924 mp-753459 mp-2657 mp-755759 mp-4820
If the above cell fails, the Materials Project API may have been updated. Uncomment and run the following cell and then re-run the entire notebook.
#!pip install --upgrade mp-api
An extra note: For reading bulk and shear moduli from the Materials Project database, there are a few options outlined here. In hashin_shtrikman_mp
we use the Voigt-Reuss-Hill average.