applyBasalPercentConstraints refactor & tests part2

This commit is contained in:
Milos Kozak 2018-03-21 22:06:28 +01:00
parent e2ea44a8a8
commit c68ab9f1ca
9 changed files with 78 additions and 71 deletions

View file

@ -37,34 +37,34 @@ public class Constraint<T extends Comparable> {
return this;
}
public Constraint<T> set(T value, String reason) {
public Constraint<T> set(T value, String reason, Object from) {
this.value = value;
reason(reason);
reason(reason, from);
return this;
}
public Constraint<T> setIfSmaller(T value, String reason) {
public Constraint<T> setIfSmaller(T value, String reason, Object from) {
if (value.compareTo(this.value) < 0) {
this.value = value;
}
if (value.compareTo(this.originalValue) < 0) {
reason(reason);
reason(reason, from);
}
return this;
}
public Constraint<T> setIfGreater(T value, String reason) {
public Constraint<T> setIfGreater(T value, String reason, Object from) {
if (value.compareTo(this.value) > 0) {
this.value = value;
}
if (value.compareTo(this.originalValue) > 0) {
reason(reason);
reason(reason, from);
}
return this;
}
public Constraint reason(String reason) {
reasons.add(reason);
public Constraint reason(String reason, Object from) {
reasons.add(from.getClass().getSimpleName() + ": " + reason);
return this;
}
@ -79,4 +79,13 @@ public class Constraint<T extends Comparable> {
return sb.toString();
}
public List<String> getReasonList() {
return reasons;
}
public void copyReasons(Constraint<?> another) {
for (String s: another.getReasonList()) {
reasons.add(s);
}
}
}

View file

@ -302,35 +302,35 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
@Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
if (objectives.get(0).started.getTime() == 0)
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1));
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1), this);
return value;
}
@Override
public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
if (objectives.get(3).started.getTime() == 0)
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 4));
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 4), this);
return value;
}
@Override
public Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
if (objectives.get(5).started.getTime() == 0)
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 6));
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 6), this);
return value;
}
@Override
public Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) {
if (objectives.get(6).started.getTime() == 0)
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 7));
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 7), this);
return value;
}
@Override
public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
if (objectives.get(7).started.getTime() == 0)
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 8));
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 8), this);
return value;
}

View file

@ -3,16 +3,12 @@ package info.nightscout.androidaps.plugins.ConstraintsSafety;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.HardLimits;
@ -99,18 +95,18 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
@Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable)
value.set(false, MainApp.gs(R.string.pumpisnottempbasalcapable));
value.set(false, MainApp.gs(R.string.pumpisnottempbasalcapable), this);
return value;
}
@Override
public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
if (!MainApp.isEngineeringModeOrRelease())
value.set(false, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch));
value.set(false, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch), this);
String mode = SP.getString("aps_mode", "open");
if (!mode.equals("closed"))
value.set(false, MainApp.gs(R.string.closedmodedisabledinpreferences));
value.set(false, MainApp.gs(R.string.closedmodedisabledinpreferences), this);
return value;
}
@ -123,7 +119,7 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
public Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) {
boolean enabled = SP.getBoolean("openapsama_useautosens", false);
if (!enabled)
value.set(false, MainApp.gs(R.string.amadisabledinpreferences));
value.set(false, MainApp.gs(R.string.amadisabledinpreferences), this);
return value;
}
@ -131,26 +127,26 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
boolean enabled = SP.getBoolean(R.string.key_use_smb, false);
if (!enabled)
value.set(false, MainApp.gs(R.string.smbdisabledinpreferences));
value.set(false, MainApp.gs(R.string.smbdisabledinpreferences), this);
return value;
}
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
absoluteRate.setIfGreater(0d, String.format(MainApp.gs(R.string.limitingbasalratio), 0d, MainApp.gs(R.string.basalmustbepositivevalue)));
absoluteRate.setIfGreater(0d, String.format(MainApp.gs(R.string.limitingbasalratio), 0d, MainApp.gs(R.string.basalmustbepositivevalue)), this);
double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
absoluteRate.setIfSmaller(maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), maxBasal, MainApp.gs(R.string.maxbasalinpreferences)));
absoluteRate.setIfSmaller(maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), maxBasal, MainApp.gs(R.string.maxbasalinpreferences)), this);
// Check percentRate but absolute rate too, because we know real current basal in pump
Double maxBasalMult = SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d);
double maxFromBasalMult = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
absoluteRate.setIfSmaller(maxFromBasalMult, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromBasalMult, MainApp.gs(R.string.maxbasalmultiplier)));
absoluteRate.setIfSmaller(maxFromBasalMult, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromBasalMult, MainApp.gs(R.string.maxbasalmultiplier)), this);
Double maxBasalFromDaily = SP.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d);
double maxFromDaily = Math.floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100;
absoluteRate.setIfSmaller(maxFromDaily, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromDaily, MainApp.gs(R.string.maxdailybasalmultiplier)));
absoluteRate.setIfSmaller(maxFromDaily, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromDaily, MainApp.gs(R.string.maxdailybasalmultiplier)), this);
return absoluteRate;
}
@ -160,18 +156,18 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
Double currentBasal = profile.getBasal();
Double absoluteRate = currentBasal * ((double) percentRate.originalValue() / 100);
percentRate.reason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h");
percentRate.reason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this);
Constraint<Double> absoluteConstraint = new Constraint<>(absoluteRate);
applyBasalConstraints(absoluteConstraint, profile);
percentRate.copyReasons(absoluteConstraint);
Integer percentRateAfterConst = Double.valueOf(absoluteConstraint.value() / currentBasal * 100).intValue();
if (percentRateAfterConst < 100)
percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, 10d).intValue();
else percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, 10d).intValue();
percentRate.set(percentRateAfterConst, String.format(MainApp.gs(R.string.limitingpercentrate), percentRateAfterConst, MainApp.gs(R.string.pumplimit)));
percentRate.set(percentRateAfterConst, String.format(MainApp.gs(R.string.limitingpercentrate), percentRateAfterConst, MainApp.gs(R.string.pumplimit)), this);
return percentRate;
}

View file

@ -1428,7 +1428,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
@Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
if (!validBasalRateProfileSelectedOnPump)
value.set(false, MainApp.gs(R.string.novalidbasalrate));
value.set(false, MainApp.gs(R.string.novalidbasalrate), this);
return value;
}

View file

@ -7,7 +7,6 @@ import org.json.JSONObject;
import org.slf4j.Logger;
import java.util.Date;
import java.util.Objects;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
@ -19,13 +18,13 @@ import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.DanaRInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
@ -462,14 +461,14 @@ public abstract class AbstractDanaRPlugin implements PluginBase, PumpInterface,
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
if (pump != null)
absoluteRate.setIfSmaller(pump.maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), pump.maxBasal, MainApp.gs(R.string.pumplimit)));
absoluteRate.setIfSmaller(pump.maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), pump.maxBasal, MainApp.gs(R.string.pumplimit)), this);
return absoluteRate;
}
@Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.basalmustbepositivevalue)));
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)));
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.basalmustbepositivevalue)), this);
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)), this);
return percentRate;
}

View file

@ -15,7 +15,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
@ -30,13 +29,13 @@ import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.DanaRInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
@ -301,14 +300,14 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
if (pump != null)
absoluteRate.setIfSmaller(pump.maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), pump.maxBasal, MainApp.gs(R.string.pumplimit)));
absoluteRate.setIfSmaller(pump.maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), pump.maxBasal, MainApp.gs(R.string.pumplimit)), this);
return absoluteRate;
}
@Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.basalmustbepositivevalue)));
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)));
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.basalmustbepositivevalue)), this);
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)), this);
return percentRate;
}

View file

@ -1116,15 +1116,15 @@ public class InsightPumpPlugin implements PluginBase, PumpInterface, Constraints
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
if (statusResult != null) {
absoluteRate.setIfSmaller(statusResult.maximumBasalAmount, String.format(MainApp.gs(R.string.limitingbasalratio), statusResult.maximumBasalAmount, MainApp.gs(R.string.pumplimit)));
absoluteRate.setIfSmaller(statusResult.maximumBasalAmount, String.format(MainApp.gs(R.string.limitingbasalratio), statusResult.maximumBasalAmount, MainApp.gs(R.string.pumplimit)), this);
}
return absoluteRate;
}
@Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.basalmustbepositivevalue)));
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)));
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.basalmustbepositivevalue)), this);
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)), this);
return percentRate;
}

View file

@ -21,23 +21,23 @@ public class ConstraintTest {
b.set(false);
Assert.assertEquals(Boolean.FALSE, b.value());
Assert.assertEquals("", b.getReasons());
b.set(true, "Set true");
b.set(true, "Set true", this);
Assert.assertEquals(Boolean.TRUE, b.value());
Assert.assertEquals("Set true", b.getReasons());
b.set(false, "Set false");
Assert.assertEquals("ConstraintTest: Set true", b.getReasons());
b.set(false, "Set false", this);
Assert.assertEquals(Boolean.FALSE, b.value());
Assert.assertEquals("Set true\nSet false", b.getReasons());
Assert.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getReasons());
Constraint<Double> d = new Constraint<>(10d);
d.set(5d, "Set 5d");
d.set(5d, "Set 5d", this);
Assert.assertEquals(5d, d.value());
Assert.assertEquals("Set 5d", d.getReasons());
d.setIfSmaller(6d, "Set 6d");
Assert.assertEquals("ConstraintTest: Set 5d", d.getReasons());
d.setIfSmaller(6d, "Set 6d", this);
Assert.assertEquals(5d, d.value());
Assert.assertEquals("Set 5d\nSet 6d", d.getReasons());
d.setIfSmaller(4d, "Set 4d");
Assert.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d", d.getReasons());
d.setIfSmaller(4d, "Set 4d", this);
Assert.assertEquals(4d, d.value());
Assert.assertEquals("Set 5d\nSet 6d\nSet 4d", d.getReasons());
Assert.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d", d.getReasons());
Assert.assertEquals(10d, d.originalValue());
}
}

View file

@ -200,18 +200,18 @@ public class ConstraintsCheckerTest {
Constraint<Double> d = new Constraint<>(-0.5d);
constraintChecker.applyBasalConstraints(d, profile);
Assert.assertEquals(0d, d.value());
Assert.assertEquals("Limiting basal rate to 0.00 U/h because of basal must be positive value", d.getReasons());
Assert.assertEquals("SafetyPlugin: Limiting basal rate to 0.00 U/h because of basal must be positive value", d.getReasons());
// Apply all limits
d = new Constraint<>(Constants.REALLYHIGHBASALRATE);
constraintChecker.applyBasalConstraints(d, profile);
Assert.assertEquals(0.8d, d.value());
Assert.assertEquals("Limiting basal rate to 1.00 U/h because of max basal settings in preferences\n" +
"Limiting basal rate to 4.00 U/h because of max basal multiplier\n" +
"Limiting basal rate to 3.00 U/h because of max daily basal multiplier\n" +
"Limiting basal rate to 0.80 U/h because of pump limit\n" +
"Limiting basal rate to 0.80 U/h because of pump limit\n" +
"Limiting basal rate to 1.10 U/h because of pump limit", d.getReasons());
Assert.assertEquals("SafetyPlugin: Limiting basal rate to 1.00 U/h because of max basal settings in preferences\n" +
"SafetyPlugin: Limiting basal rate to 4.00 U/h because of max basal multiplier\n" +
"SafetyPlugin: Limiting basal rate to 3.00 U/h because of max daily basal multiplier\n" +
"DanaRPlugin: Limiting basal rate to 0.80 U/h because of pump limit\n" +
"DanaRSPlugin: Limiting basal rate to 0.80 U/h because of pump limit\n" +
"InsightPumpPlugin: Limiting basal rate to 1.10 U/h because of pump limit", d.getReasons());
}
@ -239,21 +239,25 @@ public class ConstraintsCheckerTest {
Constraint<Integer> i = new Constraint<>(-22);
constraintChecker.applyBasalPercentConstraints(i, profile);
Assert.assertEquals((Integer)0, i.value());
Assert.assertEquals("Percent rate -22% recalculated to -0.22 U/h with current basal 1.00 U/h\n" + // SafetyPlugin
"Limiting percent rate to 0% because of pump limit\n" + // SafetyPlugin
"Limiting percent rate to 0% because of basal must be positive value\n" + // DanaRPlugin
"Limiting percent rate to 0% because of basal must be positive value\n" + // DanaRSPlugin
"Limiting percent rate to 0% because of basal must be positive value", i.getReasons()); // InsightPlugin
Assert.assertEquals("SafetyPlugin: Percent rate -22% recalculated to -0.22 U/h with current basal 1.00 U/h\n" +
"SafetyPlugin: Limiting basal rate to 0.00 U/h because of basal must be positive value\n" +
"SafetyPlugin: Limiting percent rate to 0% because of pump limit\n" +
"DanaRPlugin: Limiting percent rate to 0% because of basal must be positive value\n" +
"DanaRSPlugin: Limiting percent rate to 0% because of basal must be positive value\n" +
"InsightPumpPlugin: Limiting percent rate to 0% because of basal must be positive value", i.getReasons()); // InsightPlugin
// Apply all limits
i = new Constraint<>(Constants.REALLYHIGHPERCENTBASALRATE);
constraintChecker.applyBasalPercentConstraints(i, profile);
Assert.assertEquals((Integer)100, i.value());
Assert.assertEquals("Percent rate 1111111% recalculated to 11111.11 U/h with current basal 1.00 U/h\n" + // SafetyPlugin
"Limiting percent rate to 100% because of pump limit\n" +
"Limiting percent rate to 200% because of pump limit\n" +
"Limiting percent rate to 200% because of pump limit\n" +
"Limiting percent rate to 250% because of pump limit", i.getReasons());
Assert.assertEquals("SafetyPlugin: Percent rate 1111111% recalculated to 11111.11 U/h with current basal 1.00 U/h\n" +
"SafetyPlugin: Limiting basal rate to 1.00 U/h because of max basal settings in preferences\n" +
"SafetyPlugin: Limiting basal rate to 4.00 U/h because of max basal multiplier\n" +
"SafetyPlugin: Limiting basal rate to 3.00 U/h because of max daily basal multiplier\n" +
"SafetyPlugin: Limiting percent rate to 100% because of pump limit\n" +
"DanaRPlugin: Limiting percent rate to 200% because of pump limit\n" +
"DanaRSPlugin: Limiting percent rate to 200% because of pump limit\n" +
"InsightPumpPlugin: Limiting percent rate to 250% because of pump limit", i.getReasons());
}