definput_target(self): f = input("Enter target formula: ").strip() self.target = FormulaParser.parse(f) for e, c inself.target.items(): if e notinself.atomic_masses: raise ValueError(f"Mass of element {e} not defined") self.target_mm += c * self.atomic_masses[e] print(f"Parsed: {self.target}") print(f"Target molar mass = {self.target_mm.normalize()} g/mol")
definput_reagents(self): n = int(input("Enter number of reagents: ")) for i inrange(n): f = input(f"Reagent {i+1} formula: ").strip() self.reagent_formulas.append(f) parsed = FormulaParser.parse(f) mm = sum(parsed[e] * self.atomic_masses[e] for e in parsed) self.reagents.append(parsed) self.molar_masses.append(mm) print(f"{f} molar mass = {mm.normalize()} g/mol")
defvalidate(self): tgt = set(self.target) prov = set().union(*(r.keys() for r inself.reagents)) miss = tgt - prov extra = prov - tgt if miss: print(f"Error: Missing elements: {miss}") exit() if extra: print(f"Warning: Extra elements: {extra}")
defsolve_basis(self): # Construct A, b corresponding to 1 mol elems = sorted(set(self.target) | set().union(*(r.keys() for r inself.reagents))) A = [[r.get(e, Decimal(0)) for r inself.reagents] for e in elems] b = [self.target.get(e, Decimal(0)) for e in elems] # Convert to rational number to avoid floating point error A_rat = [[Rational(str(val)) for val in row] for row in A] b_rat = [Rational(str(val)) for val in b] vars = symbols(f'x0:{len(self.reagents)}') sol = linsolve((Matrix(A_rat), Matrix(b_rat)), vars) ifnot sol: print("Error: No exact solution for 1 mol target.") exit() tup = next(iter(sol)) # Convert rational to decimal exact representation base = {} for i, r inenumerate(tup): base[vars[i]] = Decimal(r.p) / Decimal(r.q) return base, elems
defcalculate(self): t = input("Input type (0 mass g, 1 moles): ").strip() if t notin ['0','1']: print("Invalid type") exit() v = Decimal(input("Amount: ").strip()) n = v / self.target_mm if t=='0'else v print(f"Target moles = {n.normalize()}")
base, elems = self.solve_basis() print("\nReagent requirements:\n" + "="*40) total_mass = Decimal(0) for i, var inenumerate(sorted(base.keys(), key=lambda x: int(str(x)[1:]))): moles = base[var] * n mass = moles * self.molar_masses[i] total_mass += mass print(f"Reagent {i+1} ({self.reagent_formulas[i]}):") print(f" Moles: {moles.normalize():.10f} mol") print(f" Mass: {mass.normalize():.10f} g\n") print(f"Total mass = {total_mass.normalize():.10f} g")
#Verify element balance print("Verification:") for e in elems: actual = sum((base[symbols(f'x{i}')] * n) * r.get(e, Decimal(0)) for i, r inenumerate(self.reagents)) target_amt = self.target.get(e, Decimal(0)) * n print(f"{e}: target {target_amt.normalize():.10f}, actual {actual.normalize():.10f}")