def setResultBox(self, textBox, value): if value is not None: self.valueFromTextBox[textBox] = value textBox.setText(util.displayWithUnitsNumber(util.roundSigFig(value, 5), textBox.unit)) textBox.setCursorPosition(0) else: self.unsetValue(textBox)
def goalSeek(self): # Newton's method variableTextBox = self.textBox[self.ui.vary.currentText()] resultTextBox = self.textBox[self.ui.target.currentText()] self.ui.solverResult.setText('Searching...') maximumIterations = 1000 success = False dxFactor = 1e-9 try: x0 = self.valueFromTextBox[variableTextBox] except KeyError: x0 = dxFactor bestX = x0 try: goal = util.convertUnitsStringToNumber(self.ui.lineEdit.text(), resultTextBox.unit) y0 = self.calculateValue(variableTextBox, x0, resultTextBox) bestError = abs((y0-goal)/goal) for i in range(maximumIterations): try: y0 = self.calculateValue(variableTextBox, x0, resultTextBox) error = abs((y0-goal)/goal) if error < 1e-6: success = True break else: if error < bestError: bestX = x0 bestError = error dx = abs(dxFactor*x0) slope = self.calculateSlope(variableTextBox, x0, dx, resultTextBox) x0 = x0 - (y0-goal)/slope if x0 < 0: x0 = dx except (ZeroDivisionError, KeyError, OverflowError): dxFactor = 2*dxFactor x0 = x0+dx except ValueError: # "goal" is blank -> find extrema by Newton's method on slope dx = abs(dxFactor*x0) bestSlope = abs(self.calculateSlope(variableTextBox, x0, dx, resultTextBox)) for i in range(maximumIterations): try: dx = abs(dxFactor*x0) slope = self.calculateSlope(variableTextBox, x0, dx, resultTextBox) if abs(slope) < 1e-6: success = True break else: if slope < bestSlope: bestX = x0 bestSlope = slope secondDerivitive = self.calculateSecondDerivitive(variableTextBox, x0, dx, resultTextBox) x0 = x0 - (slope)/secondDerivitive if x0 < 0: x0 = dx except (ZeroDivisionError, KeyError, OverflowError): dxFactor = 2*dxFactor x0 = x0+dx if success: value = x0 self.ui.solverResult.setText('Success.') else: value = bestX self.ui.solverResult.setText('Failed. Could not find a solution.') variableTextBox.setText(util.displayWithUnitsNumber(util.roundSigFig(value, 5), variableTextBox.unit)) variableTextBox.setCursorPosition(0) self.calculateAll()