Source code for AFL.automation.prepare.factory
from itertools import product
import numpy as np
import periodictable
import functools, operator
from AFL.automation.prepare.Solution import Solution
from AFL.automation.shared.units import units,has_units,is_mass,is_volume,is_molarity,is_concentration
from AFL.automation.shared.utilities import listify
[docs]
def HD2OFactory(name,phi_D2O=None,sld=None,properties=None):
'''Create a list of H2O/D2O solutions'''
solution_base = Solution(name,['H2O','D2O'])
solution_base.set_properties_from_dict(properties,inplace=True)
results = []
if (phi_D2O is not None) and (sld is not None):
raise ValueError('Can only specify phi_D2O OR sld')
elif phi_D2O is not None:
for vfrac in listify(phi_D2O):
solution = solution_base.copy()
solution.volume_fraction = {'D2O':vfrac}
solution.name += f' D2O:{vfrac:4.3f}'
results.append(solution)
elif sld is not None:
sldH = periodictable.formula('H2O@1n').neutron_sld(wavelength=5)[0]
sldD = periodictable.formula('D2O@1n').neutron_sld(wavelength=5)[0]
for s in listify(sld):
solution = solution_base.copy()
vfrac = (s-sldH)/(sldD-sldH)
solution.volume_fraction = {'D2O':vfrac}
solution.name += f' sld:{s:4.3f}'
results.append(solution)
else:
raise ValueError('Must specify phi_D2O or sld')
return results
[docs]
def compositionSweepFactory(name,components,vary_components,lo,hi,num,logspace=False,properties=None,progress=None):
solution_base = Solution(name,components)
solution_base.set_properties_from_dict(properties,inplace=True)
lo = listify(lo)
hi = listify(hi)
num = listify(num)
if (len(lo)==1) and (len(hi)==1) and (len(num)==1):
lo *= len(vary_components)
hi *= len(vary_components)
num *= len(vary_components)
elif not ((len(lo)==len(vary_components)) and (len(hi)==len(vary_components)) and (len(num)==len(vary_components))):
raise ValueError('Poorly specified sweep. Number of lo/hi/num specs must be 1 or equal to the number of vary_components')
params = []
for l,h,n in zip(lo,hi,num):
if not (has_units(l) and has_units(h)):
raise ValueError('Lo and hi must have units')
if logspace:
params.append(np.geomspace(l,h,n))
else:
params.append(np.linspace(l,h,n))
if progress is not None:
progress.value = 0
progress.max = functools.reduce(operator.mul, map(len, params), 1)-1
sweep = []
for j,param in enumerate(product(*params)):
if progress is not None:
progress.value = j
solution = solution_base.copy()
for i,value in enumerate(param):
component = vary_components[i]
solution.name += f' {component}:{value.magnitude:4.3f}'
if is_mass(value):
solution[component].mass = value
elif is_volume(value):
solution[component].volume = value
elif is_concentration(value):
solution.concentration = {component:value}
elif is_molarity(value):
solution.molarity = {component:value}
else: #assume mass_fraction
if solution.size>2:
raise ValueError('Variation by mass fraction only works for two component solutions')
solution.mass_fraction = {component:value}
solution.set_properties_from_dict(properties,inplace=True)
sweep.append(solution)
return sweep