def calculate(f: sp.Add, var: Tuple[sp.Symbol, sp.Symbol], eps: float = 0.001, debug: bool = False)\ -> List[Tuple[float, float]]: x, y = var first_diff = sp.Matrix([sp.diff(f, x), sp.diff(f, y)]) a = sp.Symbol('a') point = sp.Matrix([0.0, 0.0]) prev_point = sp.Matrix([0.0, 0.0]) result: List[Tuple[float, float]] = [(point[0], point[1])] iteration = 0 while iteration < 1 or sqrt((point[0] - prev_point[0])**2 + (point[1] - prev_point[1])**2) > eps: if debug: print() prev_point = point next_point = point - a * first_diff.subs({x: point[0], y: point[1]}) step = sp.solve(sp.diff(f.subs({x: next_point[0], y: next_point[1]}), a))[0] point = next_point.subs({a: step}) result.append((point[0], point[1])) iteration += 1 if debug: print(f"Method of quick going down found solution of: {(point[0], point[1])}") return result
def newtons_method( function: sympy.Add, x0, error, max_iteration ): # function is a sympy expresion. x0 is the initial point. x1 = x0 x2 = x0 iteration = 0 while iteration < max_iteration: iteration += 1 x2 = x1 - (float(function.subs(x, x1)) / float(sympy.diff(function, x).subs(x, x1))) x1 = x2 if abs(float(function.subs(x, x2))) < error: break print("Newtons method: ", x2, "The answer was found after ", iteration, "iterations") return x2
def atomic_ordering_energy(self, dbe): """ Return the atomic ordering contribution in symbolic form. Description follows Servant and Ansara, Calphad, 2001. """ phase = dbe.phases[self.phase_name] ordered_phase_name = phase.model_hints.get("ordered_phase", None) disordered_phase_name = phase.model_hints.get("disordered_phase", None) if phase.name != ordered_phase_name: return S.Zero disordered_model = self.__class__(dbe, self.components, disordered_phase_name) constituents = [ sorted(set(c).intersection(self.components)) for c in dbe.phases[ordered_phase_name].constituents ] # Fix variable names variable_rename_dict = {} for atom in disordered_model.energy.atoms(v.SiteFraction): # Replace disordered phase site fractions with mole fractions of # ordered phase site fractions. # Special case: Pure vacancy sublattices all_species_in_sublattice = dbe.phases[disordered_phase_name].constituents[atom.sublattice_index] if atom.species == "VA" and len(all_species_in_sublattice) == 1: # Assume: Pure vacancy sublattices are always last vacancy_subl_index = len(dbe.phases[ordered_phase_name].constituents) - 1 variable_rename_dict[atom] = v.SiteFraction(ordered_phase_name, vacancy_subl_index, atom.species) else: # All other cases: replace site fraction with mole fraction variable_rename_dict[atom] = self.mole_fraction( atom.species, ordered_phase_name, constituents, dbe.phases[ordered_phase_name].sublattices ) # Save all of the ordered energy contributions # This step is why this routine must be called _last_ in build_phase ordered_energy = Add(*list(self.models.values())) self.models.clear() # Copy the disordered energy contributions into the correct bins for name, value in disordered_model.models.items(): self.models[name] = value.xreplace(variable_rename_dict) # All magnetic parameters will be defined in the disordered model self.TC = self.curie_temperature = disordered_model.TC self.TC = self.curie_temperature = self.TC.xreplace(variable_rename_dict) molefraction_dict = {} # Construct a dictionary that replaces every site fraction with its # corresponding mole fraction in the disordered state for sitefrac in ordered_energy.atoms(v.SiteFraction): all_species_in_sublattice = dbe.phases[ordered_phase_name].constituents[sitefrac.sublattice_index] if sitefrac.species == "VA" and len(all_species_in_sublattice) == 1: # pure-vacancy sublattices should not be replaced # this handles cases like AL,NI,VA:AL,NI,VA:VA and # ensures the VA's don't get mixed up continue molefraction_dict[sitefrac] = self.mole_fraction( sitefrac.species, ordered_phase_name, constituents, dbe.phases[ordered_phase_name].sublattices ) return ordered_energy - ordered_energy.subs(molefraction_dict, simultaneous=True)
def _inverse_mellin_transform(F, s, x_, strip, as_meijerg=False): """ A helper for the real inverse_mellin_transform function, this one here assumes x to be real and positive. """ from sympy import (expand, expand_mul, hyperexpand, meijerg, And, Or, arg, pi, re, factor, Heaviside, gamma, Add) x = _dummy('t', 'inverse-mellin-transform', F, positive=True) # Actually, we won't try integration at all. Instead we use the definition # of the Meijer G function as a fairly general inverse mellin transform. F = F.rewrite(gamma) for g in [factor(F), expand_mul(F), expand(F)]: if g.is_Add: # do all terms separately ress = [_inverse_mellin_transform(G, s, x, strip, as_meijerg, noconds=False) \ for G in g.args] conds = [p[1] for p in ress] ress = [p[0] for p in ress] res = Add(*ress) if not as_meijerg: res = factor(res, gens=res.atoms(Heaviside)) return res.subs(x, x_), And(*conds) try: a, b, C, e, fac = _rewrite_gamma(g, s, strip[0], strip[1]) except IntegralTransformError: continue G = meijerg(a, b, C / x**e) if as_meijerg: h = G else: h = hyperexpand(G) if h.is_Piecewise and len(h.args) == 3: # XXX we break modularity here! h = Heaviside(x - abs(C))*h.args[0].args[0] \ + Heaviside(abs(C) - x)*h.args[1].args[0] # We must ensure that the intgral along the line we want converges, # and return that value. # See [L], 5.2 cond = [abs(arg(G.argument)) < G.delta * pi] # Note: we allow ">=" here, this corresponds to convergence if we let # limits go to oo symetrically. ">" corresponds to absolute convergence. cond += [ And(Or(len(G.ap) != len(G.bq), 0 >= re(G.nu) + 1), abs(arg(G.argument)) == G.delta * pi) ] cond = Or(*cond) if cond is False: raise IntegralTransformError('Inverse Mellin', F, 'does not converge') return (h * fac).subs(x, x_), cond raise IntegralTransformError('Inverse Mellin', F, '')
def subs_Eqs(eq: Add, eqs: Sequence[Eq]) -> Add: """ TODO: Проверить какой класс является базовым для всех выражений sympy @param eq: expression @param eqs: Eq @return: expression Например: x = z+2*y Это eq.subs({x: z+2*y}) """ for eq in eqs: left, right = eq.args[0], eq.args[1] eq = eq.subs({left: right}) return eq
def _inverse_mellin_transform(F, s, x_, strip, as_meijerg=False): """ A helper for the real inverse_mellin_transform function, this one here assumes x to be real and positive. """ from sympy import (expand, expand_mul, hyperexpand, meijerg, And, Or, arg, pi, re, factor, Heaviside, gamma, Add) x = _dummy('t', 'inverse-mellin-transform', F, positive=True) # Actually, we won't try integration at all. Instead we use the definition # of the Meijer G function as a fairly general inverse mellin transform. F = F.rewrite(gamma) for g in [factor(F), expand_mul(F), expand(F)]: if g.is_Add: # do all terms separately ress = [_inverse_mellin_transform(G, s, x, strip, as_meijerg, noconds=False) \ for G in g.args] conds = [p[1] for p in ress] ress = [p[0] for p in ress] res = Add(*ress) if not as_meijerg: res = factor(res, gens=res.atoms(Heaviside)) return res.subs(x, x_), And(*conds) try: a, b, C, e, fac = _rewrite_gamma(g, s, strip[0], strip[1]) except IntegralTransformError: continue G = meijerg(a, b, C/x**e) if as_meijerg: h = G else: h = hyperexpand(G) if h.is_Piecewise and len(h.args) == 3: # XXX we break modularity here! h = Heaviside(x - abs(C))*h.args[0].args[0] \ + Heaviside(abs(C) - x)*h.args[1].args[0] # We must ensure that the intgral along the line we want converges, # and return that value. # See [L], 5.2 cond = [abs(arg(G.argument)) < G.delta*pi] # Note: we allow ">=" here, this corresponds to convergence if we let # limits go to oo symetrically. ">" corresponds to absolute convergence. cond += [And(Or(len(G.ap) != len(G.bq), 0 >= re(G.nu) + 1), abs(arg(G.argument)) == G.delta*pi)] cond = Or(*cond) if cond is False: raise IntegralTransformError('Inverse Mellin', F, 'does not converge') return (h*fac).subs(x, x_), cond raise IntegralTransformError('Inverse Mellin', F, '')
def atomic_ordering_energy(self, dbe): """ Return the atomic ordering contribution in symbolic form. Description follows Servant and Ansara, Calphad, 2001. """ phase = dbe.phases[self.phase_name] ordered_phase_name = phase.model_hints.get('ordered_phase', None) disordered_phase_name = phase.model_hints.get('disordered_phase', None) if phase.name != ordered_phase_name: return S.Zero disordered_model = self.__class__(dbe, sorted(self.components), disordered_phase_name) constituents = [sorted(set(c).intersection(self.components)) \ for c in dbe.phases[ordered_phase_name].constituents] # Fix variable names variable_rename_dict = {} for atom in disordered_model.energy.atoms(v.SiteFraction): # Replace disordered phase site fractions with mole fractions of # ordered phase site fractions. # Special case: Pure vacancy sublattices all_species_in_sublattice = \ dbe.phases[disordered_phase_name].constituents[ atom.sublattice_index] if atom.species == 'VA' and len(all_species_in_sublattice) == 1: # Assume: Pure vacancy sublattices are always last vacancy_subl_index = \ len(dbe.phases[ordered_phase_name].constituents)-1 variable_rename_dict[atom] = \ v.SiteFraction( ordered_phase_name, vacancy_subl_index, atom.species) else: # All other cases: replace site fraction with mole fraction variable_rename_dict[atom] = \ self.mole_fraction( atom.species, ordered_phase_name, constituents, dbe.phases[ordered_phase_name].sublattices ) # Save all of the ordered energy contributions # This step is why this routine must be called _last_ in build_phase ordered_energy = Add(*list(self.models.values())) self.models.clear() # Copy the disordered energy contributions into the correct bins for name, value in disordered_model.models.items(): self.models[name] = value.xreplace(variable_rename_dict) # All magnetic parameters will be defined in the disordered model self.TC = self.curie_temperature = disordered_model.TC self.TC = self.curie_temperature = self.TC.xreplace(variable_rename_dict) molefraction_dict = {} # Construct a dictionary that replaces every site fraction with its # corresponding mole fraction in the disordered state for sitefrac in ordered_energy.atoms(v.SiteFraction): all_species_in_sublattice = \ dbe.phases[ordered_phase_name].constituents[ sitefrac.sublattice_index] if sitefrac.species == 'VA' and len(all_species_in_sublattice) == 1: # pure-vacancy sublattices should not be replaced # this handles cases like AL,NI,VA:AL,NI,VA:VA and # ensures the VA's don't get mixed up continue molefraction_dict[sitefrac] = \ self.mole_fraction(sitefrac.species, ordered_phase_name, constituents, dbe.phases[ordered_phase_name].sublattices) return ordered_energy - ordered_energy.subs(molefraction_dict, simultaneous=True)