Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
but may not be possible with other conditions because
there may be multiple (or zero) solutions.
Parameters
----------
conditions : dict
state_variables : iterable of StateVariables
Returns
-------
bool
"""
global_min = True
for cond in conditions.keys():
if cond in state_variables or \
isinstance(cond, v.Composition) or \
isinstance(cond, v.ChemicalPotential) or \
cond == v.N:
continue
global_min = False
return global_min
For binplot only one changing composition and one potential coordinate each is supported.
eq_kwargs : optional
Keyword arguments to equilibrium().
plot_kwargs : optional
Keyword arguments to eqplot().
Returns
-------
A phase diagram as a figure.
Examples
--------
None yet.
"""
eq_kwargs = eq_kwargs if eq_kwargs is not None else dict()
indep_comp = [key for key, value in conds.items() if isinstance(key, v.Composition) and len(np.atleast_1d(value)) > 1]
indep_pot = [key for key, value in conds.items() if (type(key) is v.StateVariable) and len(np.atleast_1d(value)) > 1]
if (len(indep_comp) != 1) or (len(indep_pot) != 1):
raise ValueError('binplot() requires exactly one composition and one potential coordinate')
indep_comp = indep_comp[0]
indep_pot = indep_pot[0]
full_eq = equilibrium(dbf, comps, phases, conds, **eq_kwargs)
return eqplot(full_eq, x=indep_comp, y=indep_pot, **plot_kwargs)
def binplot_map(dbf, comps, phases, conds, tol_zero_one=None, tol_same=None, tol_misc_gap=0.1, eq_kwargs=None,
max_T_backtracks=5, T_backtrack_factor=2, verbose=False, veryverbose=False, backtrack_raise=False,
startpoint_comp_tol=0.05, startpoint_temp_tol=20,
initial_start_points=None):
# naive algorithm to map a binary phase diagram in T-X
# for each temperature, proceed along increasing composition, skipping two phase regions
# assumes conditions in T and X
eq_kwargs = eq_kwargs or {}
if 'callables' not in eq_kwargs:
eq_kwargs['callables'] = build_callables(dbf, comps, phases, build_gradients=True, model=eq_kwargs.get('model'))
eq_kwargs['model'] = eq_kwargs['callables']['model']
# assumes only one composition
x_cond = [c for c in conds.keys() if isinstance(c, v.Composition)][0]
indep_comp = x_cond.species.name
comp_idx = sorted(set(comps) - {'VA'}).index(indep_comp)
# mapping conditions
x_min, x_max, dx = conds[x_cond]
T_min, T_max, dT = conds[v.T]
curr_conds = deepcopy(conds)
tol_zero_one = tol_zero_one if tol_zero_one is not None else dx # convergence tolerance
tol_same = tol_same if tol_same is not None else dx
zpf_boundaries = ZPFBoundarySets(comps, x_cond)
start_points = StartPointsList(eq_comp_tol=startpoint_comp_tol, eq_temp_tol=startpoint_temp_tol)
if initial_start_points is not None:
if isinstance(initial_start_points, StartPoint):
start_points.add_start_point(initial_start_points)
else:
# assume an iterable
eq['Phase'].values = np.array(eq['Phase'].values, dtype='U')
# Select all two- and three-phase regions
three_phase_idx = np.nonzero(np.sum(eq.Phase.values != '', axis=-1, dtype=np.int) == 3)
two_phase_idx = np.nonzero(np.sum(eq.Phase.values != '', axis=-1, dtype=np.int) == 2)
legend_handles, colorlist = phase_legend(phases)
# For both two and three phase, cast the tuple of indices to an array and flatten
# If we found two phase regions:
if two_phase_idx[0].size > 0:
found_two_phase = eq.Phase.values[two_phase_idx][..., :2]
# get tieline endpoint compositions
two_phase_x = eq.X.sel(component=x.species.name).values[two_phase_idx][..., :2]
# handle special case for potential
if isinstance(y, v.Composition):
two_phase_y = eq.X.sel(component=y.species.name).values[two_phase_idx][..., :2]
else:
# it's a StateVariable. This must be True
two_phase_y = np.take(eq[str(y)].values, two_phase_idx[list(str(i) for i in conds.keys()).index(str(y))])
# because the above gave us a shape of (n,) instead of (n,2) we are going to create it ourselves
two_phase_y = np.array([two_phase_y, two_phase_y]).swapaxes(0, 1)
# plot two phase points
two_phase_plotcolors = np.array(list(map(lambda x: [colorlist[x[0]], colorlist[x[1]]], found_two_phase)), dtype='U') # from pycalphad
ax.scatter(two_phase_x[..., 0], two_phase_y[..., 0], s=3, c=two_phase_plotcolors[:,0], edgecolors='None', zorder=2, **kwargs)
ax.scatter(two_phase_x[..., 1], two_phase_y[..., 1], s=3, c=two_phase_plotcolors[:,1], edgecolors='None', zorder=2, **kwargs)
if tielines:
# construct and plot tielines
two_phase_tielines = np.array([np.concatenate((two_phase_x[..., 0][..., np.newaxis], two_phase_y[..., 0][..., np.newaxis]), axis=-1),
np.concatenate((two_phase_x[..., 1][..., np.newaxis], two_phase_y[..., 1][..., np.newaxis]), axis=-1)])
def get_multiphase_constraints(self, conds):
fixed_chempots = [cond for cond in conds.keys() if isinstance(cond, v.ChemicalPotential)]
multiphase_constraints = []
for statevar in sorted(conds.keys(), key=str):
if not is_multiphase_constraint(statevar):
continue
if isinstance(statevar, v.Composition):
multiphase_constraints.append(Symbol('NP') * self.moles(statevar.species))
elif statevar == v.N:
multiphase_constraints.append(Symbol('NP') * (sum(self.moles(spec) for spec in self.nonvacant_elements)))
elif statevar in [v.T, v.P]:
return multiphase_constraints.append(S.Zero)
else:
raise NotImplementedError
return multiphase_constraints
def _adjust_conditions(conds):
"Adjust conditions values to be within the numerical limit of the solver."
new_conds = OrderedDict()
for key, value in sorted(conds.items(), key=str):
if isinstance(key, v.Composition):
new_conds[key] = [max(val, MIN_SITE_FRACTION*1000) for val in unpack_condition(value)]
else:
new_conds[key] = unpack_condition(value)
return new_conds
if v.N not in conds:
conds[v.N] = [1.0]
if 'pdens' not in calc_kwargs:
calc_kwargs['pdens'] = 2000
species = unpack_components(dbf, comps)
parameters = eq_kwargs.get('parameters', {})
models = eq_kwargs.get('model')
statevars = get_state_variables(models=models, conds=conds)
if models is None:
models = instantiate_models(dbf, comps, phases, model=eq_kwargs.get('model'),
parameters=parameters, symbols_only=True)
prxs = build_phase_records(dbf, species, phases, conds, models, output='GM',
parameters=parameters, build_gradients=True, build_hessians=True)
indep_comp = [key for key, value in conds.items() if isinstance(key, v.Composition) and len(np.atleast_1d(value)) > 1]
indep_pot = [key for key, value in conds.items() if (type(key) is v.StateVariable) and len(np.atleast_1d(value)) > 1]
if (len(indep_comp) != 1) or (len(indep_pot) != 1):
raise ValueError('Binary map requires exactly one composition and one potential coordinate')
if indep_pot[0] != v.T:
raise ValueError('Binary map requires that a temperature grid must be defined')
# binary assumption, only one composition specified.
comp_cond = [k for k in conds.keys() if isinstance(k, v.X)][0]
indep_comp = comp_cond.name[2:]
indep_comp_idx = sorted(get_pure_elements(dbf, comps)).index(indep_comp)
composition_grid = unpack_condition(conds[comp_cond])
dX = composition_grid[1] - composition_grid[0]
Xmax = composition_grid.max()
temperature_grid = unpack_condition(conds[v.T])
dT = temperature_grid[1] - temperature_grid[0]
def _adjust_conditions(conds):
"Adjust conditions values to be within the numerical limit of the solver."
new_conds = OrderedDict()
for key, value in sorted(conds.items(), key=str):
if key == str(key):
key = getattr(v, key, key)
if isinstance(key, v.Composition):
new_conds[key] = [max(val, MIN_SITE_FRACTION*1000) for val in unpack_condition(value)]
else:
new_conds[key] = unpack_condition(value)
return new_conds
def _axis_label(ax_var):
if isinstance(ax_var, v.Composition):
return 'X({})'.format(ax_var.species.name)
elif isinstance(ax_var, v.StateVariable):
return _plot_labels[ax_var]
else:
return ax_var
solver = solver if solver is not None else InteriorPointSolver(verbose=verbose)
parameters = parameters if parameters is not None else dict()
if isinstance(parameters, dict):
parameters = OrderedDict(sorted(parameters.items(), key=str))
models = instantiate_models(dbf, comps, active_phases, model=model, parameters=parameters)
# Temporary solution until constraint system improves
if conditions.get(v.N) is None:
conditions[v.N] = 1
if np.any(np.array(conditions[v.N]) != 1):
raise ConditionError('N!=1 is not yet supported, got N={}'.format(conditions[v.N]))
# Modify conditions values to be within numerical limits, e.g., X(AL)=0
# Also wrap single-valued conditions with lists
conds = _adjust_conditions(conditions)
for cond in conds.keys():
if isinstance(cond, (v.Composition, v.ChemicalPotential)) and cond.species not in comps:
raise ConditionError('{} refers to non-existent component'.format(cond))
state_variables = sorted(get_state_variables(models=models, conds=conds), key=str)
str_conds = OrderedDict((str(key), value) for key, value in conds.items())
components = [x for x in sorted(comps)]
desired_active_pure_elements = [list(x.constituents.keys()) for x in components]
desired_active_pure_elements = [el.upper() for constituents in desired_active_pure_elements for el in constituents]
pure_elements = sorted(set([x for x in desired_active_pure_elements if x != 'VA']))
if verbose:
print('Components:', ' '.join([str(x) for x in comps]))
print('Phases:', end=' ')
output = output if output is not None else 'GM'
output = output if isinstance(output, (list, tuple, set)) else [output]
output = set(output)
output |= {'GM'}
output = sorted(output)
phase_records = build_phase_records(dbf, comps, active_phases, conds, models,