def test_softminus_softplus(self): a = pybamm.Scalar(1) b = pybamm.StateVector(slice(0, 1)) minimum = pybamm.softminus(a, b, 50) self.assertAlmostEqual(minimum.evaluate(y=np.array([2]))[0, 0], 1) self.assertAlmostEqual(minimum.evaluate(y=np.array([0]))[0, 0], 0) self.assertEqual( str(minimum), "log(1.9287498479639178e-22 + exp(-50.0 * y[0:1])) / -50.0" ) maximum = pybamm.softplus(a, b, 50) self.assertAlmostEqual(maximum.evaluate(y=np.array([2]))[0, 0], 2) self.assertAlmostEqual(maximum.evaluate(y=np.array([0]))[0, 0], 1) self.assertEqual( str(maximum), "log(5.184705528587072e+21 + exp(50.0 * y[0:1])) / 50.0" ) # Test that smooth min/max are used when the setting is changed pybamm.settings.min_smoothing = 10 pybamm.settings.max_smoothing = 10 self.assertEqual(str(pybamm.minimum(a, b)), str(pybamm.softminus(a, b, 10))) self.assertEqual(str(pybamm.maximum(a, b)), str(pybamm.softplus(a, b, 10))) # But exact min/max should still be used if both variables are constant a = pybamm.Scalar(1) b = pybamm.Scalar(2) self.assertEqual(str(pybamm.minimum(a, b)), str(a)) self.assertEqual(str(pybamm.maximum(a, b)), str(b)) # Change setting back for other tests pybamm.settings.min_smoothing = "exact" pybamm.settings.max_smoothing = "exact"
def maximum(left, right): """ Returns the larger of two objects, possibly with a smoothing approximation. Not to be confused with :meth:`pybamm.max`, which returns max function of child. """ k = pybamm.settings.max_smoothing # Return exact approximation if that is the setting or the outcome is a constant # (i.e. no need for smoothing) if k == "exact" or (pybamm.is_constant(left) and pybamm.is_constant(right)): out = Maximum(left, right) else: out = pybamm.softplus(left, right, k) return pybamm.simplify_if_constant(out, keep_domains=True)