applyMaxIOBConstraints refactor & tests

This commit is contained in:
Milos Kozak 2018-03-22 21:13:26 +01:00
parent 1aba9a2564
commit 76ee3c51e4
14 changed files with 95 additions and 51 deletions

View file

@ -16,6 +16,7 @@ public class Constants {
public static final Integer REALLYHIGHPERCENTBASALRATE = 1111111;
public static final double REALLYHIGHBOLUS = 1111111d;
public static final Integer REALLYHIGHCARBS = 1111111;
public static final double REALLYHIGHIOB = 1111111d;
public static final Integer notificationID = 556677;

View file

@ -145,15 +145,14 @@ public class ConstraintChecker implements ConstraintsInterface {
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
Double maxIobAfterConstrain = maxIob;
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginBase.CONSTRAINTS)) continue;
maxIobAfterConstrain = Math.min(constrain.applyMaxIOBConstraints(maxIob), maxIobAfterConstrain);
constrain.applyMaxIOBConstraints(maxIob);
}
return maxIobAfterConstrain;
return maxIob;
}

View file

@ -25,6 +25,8 @@ public interface ConstraintsInterface {
Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs);
Double applyMaxIOBConstraints(Double maxIob);
default Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
return maxIob;
};
}

View file

@ -11,6 +11,7 @@ import java.util.Date;
import java.util.List;
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;
@ -192,7 +193,7 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
return new RequirementResult(closedLoopEnabled.value(), MainApp.gs(R.string.closedmodeenabled) + ": " + yesOrNo(closedLoopEnabled.value()));
case 4:
double maxIOB = MainApp.getConstraintChecker().applyMaxIOBConstraints(1000d);
double maxIOB = MainApp.getConstraintChecker().applyMaxIOBConstraints(new Constraint<>(Constants.REALLYHIGHIOB)).value();
boolean maxIobSet = maxIOB > 0;
return new RequirementResult(maxIobSet, MainApp.gs(R.string.maxiobset) + ": " + yesOrNo(maxIobSet));
default:
@ -335,14 +336,10 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
if (objectives.get(3).started.getTime() > 0 && objectives.get(3).accomplished.getTime() == 0) {
if (Config.logConstraintsChanges)
log.debug("Limiting maxIOB " + maxIob + " to " + 0 + "U");
return 0d;
} else {
return maxIob;
}
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
if (objectives.get(3).started.getTime() > 0&& objectives.get(3).accomplished.getTime() == 0)
maxIob.set(0d, String.format(MainApp.gs(R.string.objectivenotfinished), 4), this);
return maxIob;
}
@Override

View file

@ -10,6 +10,9 @@ import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.HardLimits;
import info.nightscout.utils.Round;
@ -194,7 +197,16 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
double maxIobPref = SP.getDouble(R.string.key_openapsma_max_iob, 1.5d);
maxIob.setIfSmaller(maxIobPref, String.format(MainApp.gs(R.string.limitingiob), maxIobPref, MainApp.gs(R.string.maxvalueinpreferences)), this);
if (OpenAPSMAPlugin.getPlugin().isEnabled(PluginBase.APS))
maxIob.setIfSmaller(HardLimits.maxIobAMA(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobAMA(), MainApp.gs(R.string.hardlimit)), this);
if (OpenAPSAMAPlugin.getPlugin().isEnabled(PluginBase.APS))
maxIob.setIfSmaller(HardLimits.maxIobAMA(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobAMA(), MainApp.gs(R.string.hardlimit)), this);
if (OpenAPSSMBPlugin.getPlugin().isEnabled(PluginBase.APS))
maxIob.setIfSmaller(HardLimits.maxIobSMB(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobSMB(), MainApp.gs(R.string.hardlimit)), this);
return maxIob;
}

View file

@ -8,6 +8,7 @@ import java.io.IOException;
import java.util.Date;
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.GlucoseStatus;
@ -17,6 +18,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
@ -74,7 +76,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
@Override
public boolean isEnabled(int type) {
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump() != null && ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
return type == APS && fragmentEnabled && pumpCapable;
}
@ -173,7 +175,6 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
String units = profile.getUnits();
double maxIob = SP.getDouble(R.string.key_openapsma_max_iob, 1.5d);
double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
double minBg = Profile.toMgdl(profile.getTargetLow(), units);
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
@ -191,7 +192,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
MealData mealData = MainApp.getConfigBuilder().getMealData();
Profiler.log(log, "getMealData()", startPart);
maxIob = MainApp.getConstraintChecker().applyMaxIOBConstraints(maxIob);
double maxIob = MainApp.getConstraintChecker().applyMaxIOBConstraints(new Constraint<>(Constants.REALLYHIGHIOB)).value();
minBg = HardLimits.verifyHardLimits(minBg, "minBg", HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1]);
maxBg = HardLimits.verifyHardLimits(maxBg, "maxBg", HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1]);
@ -207,8 +208,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface {
}
maxIob = HardLimits.verifyHardLimits(maxIob, "maxIob", 0, HardLimits.maxIobAMA());
maxBasal = HardLimits.verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal());
maxBasal = HardLimits.verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal());
if (!HardLimits.checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA))
return;

View file

@ -8,6 +8,7 @@ import java.io.IOException;
import java.util.Date;
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.GlucoseStatus;
@ -17,6 +18,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
@ -74,13 +76,13 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
@Override
public boolean isEnabled(int type) {
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump() != null && ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
return type == APS && fragmentEnabled && pumpCapable;
}
@Override
public boolean isVisibleInTabs(int type) {
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump() != null && ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
return type == APS && fragmentVisible && pumpCapable;
}
@ -173,7 +175,6 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
String units = profile.getUnits();
double maxIob = SP.getDouble(R.string.key_openapsma_max_iob, 1.5d);
double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
double minBg = Profile.toMgdl(profile.getTargetLow(), units);
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
@ -192,7 +193,7 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
MealData mealData = MainApp.getConfigBuilder().getMealData();
maxIob = MainApp.getConstraintChecker().applyMaxIOBConstraints(maxIob);
double maxIob = MainApp.getConstraintChecker().applyMaxIOBConstraints(new Constraint<>(Constants.REALLYHIGHIOB)).value();
Profiler.log(log, "MA data gathering", start);
minBg = verifyHardLimits(minBg, "minBg", HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1]);
@ -206,7 +207,6 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
targetBg = verifyHardLimits(tempTarget.target(), "targetBg", HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]);
}
maxIob = verifyHardLimits(maxIob, "maxIob", 0, HardLimits.maxIobAMA());
maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal());
if (!checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA))

View file

@ -8,6 +8,7 @@ import java.io.IOException;
import java.util.Date;
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.GlucoseStatus;
@ -17,6 +18,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
@ -79,7 +81,7 @@ public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
@Override
public boolean isEnabled(int type) {
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
boolean pumpCapable = ConfigBuilderPlugin.getActivePump() == null || ConfigBuilderPlugin.getActivePump() != null && ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
return type == APS && fragmentEnabled && pumpCapable;
}
@ -178,7 +180,6 @@ public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
String units = profile.getUnits();
double maxIob = SP.getDouble(R.string.key_openapsma_max_iob, 1.5d);
double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
double minBg = Profile.toMgdl(profile.getTargetLow(), units);
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
@ -196,7 +197,7 @@ public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
MealData mealData = MainApp.getConfigBuilder().getMealData();
Profiler.log(log, "getMealData()", startPart);
maxIob = MainApp.getConstraintChecker().applyMaxIOBConstraints(maxIob);
double maxIob = MainApp.getConstraintChecker().applyMaxIOBConstraints(new Constraint<>(Constants.REALLYHIGHIOB)).value();
minBg = verifyHardLimits(minBg, "minBg", HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1]);
maxBg = verifyHardLimits(maxBg, "maxBg", HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1]);
@ -212,7 +213,6 @@ public class OpenAPSSMBPlugin implements PluginBase, APSInterface {
}
maxIob = verifyHardLimits(maxIob, "maxIob", 0, HardLimits.maxIobSMB());
maxBasal = verifyHardLimits(maxBasal, "max_basal", 0.1, HardLimits.maxBasal());
if (!checkOnlyHardLimits(profile.getDia(), "dia", HardLimits.MINDIA, HardLimits.MAXDIA)) return;

View file

@ -1473,7 +1473,9 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return lowSuspendOnlyLoopEnforcedUntil < System.currentTimeMillis() ? maxIob : 0;
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
if (lowSuspendOnlyLoopEnforcedUntil > System.currentTimeMillis())
maxIob.setIfSmaller(0d, String.format(MainApp.gs(R.string.limitingmaxiob), 0d, MainApp.gs(R.string.unsafeusage)), this);
return maxIob;
}
}

View file

@ -485,11 +485,6 @@ public abstract class AbstractDanaRPlugin implements PluginBase, PumpInterface,
return carbs;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return maxIob;
}
@Nullable
@Override
public ProfileStore getProfile() {

View file

@ -325,11 +325,6 @@ public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface,
return carbs;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return maxIob;
}
// Profile interface
@Nullable

View file

@ -1141,10 +1141,5 @@ public class InsightPumpPlugin implements PluginBase, PumpInterface, Constraints
return carbs;
}
@Override
public Double applyMaxIOBConstraints(Double maxIob) {
return maxIob;
}
}

View file

@ -961,6 +961,7 @@
<string name="combo_bolus_count">Bolus count</string>
<string name="combo_tbr_count">TBR count</string>
<string name="objectivenotstarted" formatted="false">Objective %d not started</string>
<string name="objectivenotfinished" formatted="false">Objective %d not finished</string>
<string name="pumpisnottempbasalcapable">Pump is not temp basal capable</string>
<string name="novalidbasalrate">No valid basal rate read from pump</string>
<string name="closedmodedisabledinpreferences">Closed loop mode disabled in preferences</string>
@ -979,10 +980,13 @@
<string name="basal_set_correctly">Basal set correctly</string>
<string name="limitingpercentrate" formatted="false">Limiting percent rate to %d%% because of %s</string>
<string name="key_treatmentssafety_maxbolus" translatable="false">treatmentssafety_maxbolus</string>
<string name="limitingbolus">Limiting bolus to %.1f U because of %s</string>
<string name="limitingcarbs">Limiting carbs to %d g because of %s</string>
<string name="limitingbolus" formatted="false">Limiting bolus to %.1f U because of %s</string>
<string name="limitingmaxiob" formatted="false">Limiting max IOB to %.1f U because of %s</string>
<string name="limitingcarbs" formatted="false">Limiting carbs to %d g because of %s</string>
<string name="limitingiob" formatted="false">Limiting IOB to %.1f U because of %s</string>
<string name="maxvalueinpreferences">max value in preferences</string>
<string name="hardlimit">hard limit</string>
<string name="key_treatmentssafety_maxcarbs">treatmentssafety_maxcarbs</string>
<string name="unsafeusage">unsafe usage</string>
</resources>

View file

@ -27,6 +27,9 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump;
@ -44,7 +47,7 @@ import static org.mockito.Mockito.when;
* Created by mike on 18.03.2018.
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, FabricPrivacy.class, SP.class, Context.class})
@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, FabricPrivacy.class, SP.class, Context.class, OpenAPSMAPlugin.class, OpenAPSAMAPlugin.class, OpenAPSSMBPlugin.class})
public class ConstraintsCheckerTest {
PumpInterface pump = new VirtualPumpPlugin();
@ -280,7 +283,7 @@ public class ConstraintsCheckerTest {
when(SP.getDouble(R.string.key_treatmentssafety_maxbolus, 3d)).thenReturn(3d);
when(SP.getString(R.string.key_age, "")).thenReturn("child");
// Negative basal not allowed
// Negative bolus not allowed
Constraint<Double> d = new Constraint<>(-22d);
constraintChecker.applyBolusConstraints(d);
Assert.assertEquals(0d, d.value());
@ -304,7 +307,7 @@ public class ConstraintsCheckerTest {
// No limit by default
when(SP.getInt(R.string.key_treatmentssafety_maxcarbs, 48)).thenReturn(48);
// Negative basal not allowed
// Negative carbs not allowed
Constraint<Integer> i = new Constraint<>(-22);
constraintChecker.applyCarbsConstraints(i);
Assert.assertEquals((Integer) 0, i.value());
@ -317,6 +320,39 @@ public class ConstraintsCheckerTest {
Assert.assertEquals("SafetyPlugin: Limiting carbs to 48 g because of max value in preferences", i.getReasons());
}
// applyMaxIOBConstraints tests
@Test
public void iobShouldBeLimited() throws Exception {
// DanaR, RS
danaRPlugin.setFragmentEnabled(PluginBase.PUMP, true);
danaRSPlugin.setFragmentEnabled(PluginBase.PUMP, true);
DanaRPump.getInstance().maxBolus = 6d;
// Insight
insightPlugin.setFragmentEnabled(PluginBase.PUMP, true);
StatusTaskRunner.Result result = new StatusTaskRunner.Result();
result.maximumBolusAmount = 7d;
insightPlugin.setStatusResult(result);
// No limit by default
when(SP.getDouble(R.string.key_openapsma_max_iob, 1.5d)).thenReturn(1.5d);
when(SP.getString(R.string.key_age, "")).thenReturn("teenage");
OpenAPSMAPlugin.getPlugin().setFragmentEnabled(PluginBase.APS, true);
OpenAPSAMAPlugin.getPlugin().setFragmentEnabled(PluginBase.APS, true);
OpenAPSSMBPlugin.getPlugin().setFragmentEnabled(PluginBase.APS, true);
// Apply all limits
Constraint<Double> d = new Constraint<>(Constants.REALLYHIGHIOB);
constraintChecker.applyMaxIOBConstraints(d);
Assert.assertEquals(1.5d, d.value());
Assert.assertEquals("SafetyPlugin: Limiting IOB to 1.5 U because of max value in preferences\n" +
"SafetyPlugin: Limiting IOB to 7.0 U because of hard limit\n" +
"SafetyPlugin: Limiting IOB to 7.0 U because of hard limit\n" +
"SafetyPlugin: Limiting IOB to 12.0 U because of hard limit", d.getReasons());
}
@Before
public void prepareMock() throws Exception {
Locale.setDefault(new Locale("en", "US"));
@ -355,6 +391,12 @@ public class ConstraintsCheckerTest {
when(MainApp.gs(R.string.hardlimit)).thenReturn("hard limit");
when(MainApp.gs(R.string.key_child)).thenReturn("child");
when(MainApp.gs(R.string.limitingcarbs)).thenReturn("Limiting carbs to %d g because of %s");
when(MainApp.gs(R.string.limitingiob)).thenReturn("Limiting IOB to %.1f U because of %s");
PowerMockito.mockStatic(SP.class);
//PowerMockito.mock(OpenAPSMAPlugin.class);
//PowerMockito.mock(OpenAPSAMAPlugin.class);
//PowerMockito.mock(OpenAPSSMBPlugin.class);
PowerMockito.mockStatic(SP.class);
// RS constructor