1 | package dk.deepthought.sidious.rules; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.Collection; |
5 | import java.util.Properties; |
6 | |
7 | import org.apache.commons.logging.Log; |
8 | import org.apache.commons.logging.LogFactory; |
9 | |
10 | import dk.deepthought.sidious.goalhandler.Goal; |
11 | import dk.deepthought.sidious.greenhouse.ClimaticState; |
12 | import dk.deepthought.sidious.greenhouse.SensorInput; |
13 | import dk.deepthought.sidious.services.ServiceEngine; |
14 | import dk.deepthought.sidious.supportsystem.State; |
15 | import dk.deepthought.sidious.supportsystem.Step; |
16 | import dk.deepthought.sidious.supportsystem.SuperLinkID; |
17 | import dk.deepthought.sidious.supportsystem.SystemSettings; |
18 | import dk.deepthought.sidious.util.RuleProperty; |
19 | |
20 | /** |
21 | * This class represents a temperature rule. |
22 | * <p> |
23 | * The rule advocates for maintaining a mean temperature, and avoiding |
24 | * temperature boundaries. |
25 | * |
26 | * @author Deepthought |
27 | * |
28 | */ |
29 | public final class TemperatureRule extends Rule { |
30 | |
31 | private static final Log logger = LogFactory.getLog(TemperatureRule.class); |
32 | |
33 | /** |
34 | * The ID of the sensor this Rule depends on. |
35 | */ |
36 | private final SuperLinkID SENSOR_ID; |
37 | |
38 | /** |
39 | * The RuleProperty of this class |
40 | */ |
41 | private static RuleProperty ruleProperty; |
42 | |
43 | /** |
44 | * The mean temperature. |
45 | */ |
46 | private final double T_MEAN; |
47 | |
48 | /** |
49 | * The max temperature. |
50 | */ |
51 | private final double T_MAX; |
52 | |
53 | /** |
54 | * Coefficient for mathematical calculations |
55 | */ |
56 | private final double K_MAX; |
57 | |
58 | /** |
59 | * Coefficient for mathematical calculations |
60 | */ |
61 | private final double K_MIN; |
62 | |
63 | /** |
64 | * The min temperature. |
65 | */ |
66 | private final double T_MIN; |
67 | |
68 | /** |
69 | * Arbitrary max value. |
70 | */ |
71 | private static final double MAXVALUE = 1000; |
72 | |
73 | /** |
74 | * Constructor. |
75 | * |
76 | * @param parentId |
77 | * the id of the parent <code>PlanRequester</code> |
78 | */ |
79 | public TemperatureRule(final SuperLinkID parentId) { |
80 | if (parentId == null) { |
81 | logger.error("TemperatureRule(SuperLinkID parentId=null) " |
82 | + "- not valid input"); |
83 | throw new IllegalArgumentException("parentID=null not valid input"); |
84 | } |
85 | if (ruleProperty == null) { |
86 | ruleProperty = new RuleProperty(this.getClass().getSimpleName()); |
87 | } |
88 | SENSOR_ID = SystemSettings.getTemperatureID(); |
89 | //FIXME hent fra property igen! |
90 | // SENSOR_ID = ruleProperty.getID("sensor_id"); |
91 | T_MEAN = ruleProperty.getFloat("t_mean", 20); |
92 | T_MAX = ruleProperty.getFloat("t_max", 30); |
93 | K_MAX = ruleProperty.getFloat("k_max", 0.5f); |
94 | K_MIN = ruleProperty.getFloat("k_min", 0.5f); |
95 | T_MIN = ruleProperty.getFloat("t_min", 5); |
96 | setParentID(parentId); |
97 | if (logger.isDebugEnabled()) { |
98 | logger.debug("TemperatureRule(SuperLinkID parentId=" + parentId |
99 | + ") - SENSOR_ID=" + SENSOR_ID + ", T_MEAN=" + T_MEAN |
100 | + ", T_MAX=" + T_MAX + ", K_MAX=" + K_MAX + ", K_MIN=" |
101 | + K_MIN + ", T_MIN=" + T_MIN); |
102 | } |
103 | } |
104 | |
105 | /** |
106 | * Static factory for constructing a TemperatureRule with the specified |
107 | * properties. |
108 | * |
109 | * @param parentID |
110 | * the id of the parent <code>PlanRequester</code> |
111 | * @param properties |
112 | * the properties |
113 | * @return a new TemperatureRule from the given properties |
114 | */ |
115 | public static TemperatureRule constructTemperatureRule( |
116 | SuperLinkID parentID, Properties properties) { |
117 | ruleProperty = new RuleProperty(properties); |
118 | return new TemperatureRule(parentID); |
119 | } |
120 | |
121 | /* |
122 | * (non-Javadoc) |
123 | * |
124 | * @see dk.deepthought.sidious.rules.Rule#desire(dk.deepthought.sidious.supportsystem.State, |
125 | * dk.deepthought.sidious.supportsystem.State) |
126 | */ |
127 | public double desire(State currentState, State newState, Step step) { |
128 | if (logger.isDebugEnabled()) { |
129 | logger.debug("desire(State currentState=" + currentState |
130 | + ", State newState=" + newState + ") - start"); |
131 | } |
132 | |
133 | double defaultValue = 0; |
134 | if (currentState == null || newState == null) { |
135 | logger.error("desire(State currentState=" + currentState |
136 | + ", State newState=" + newState + ") - currentState=" |
137 | + currentState + ", newState=" + newState |
138 | + " - null not valid input"); |
139 | return defaultValue; |
140 | } |
141 | Collection<SensorInput> curSensors = ((ClimaticState) currentState) |
142 | .getSensors(); |
143 | Collection<SensorInput> newSensors = ((ClimaticState) newState) |
144 | .getSensors(); |
145 | SensorInput curTempSensor = null; |
146 | SensorInput newTempSensor = null; |
147 | for (SensorInput input : curSensors) { |
148 | if (input.getID().equals(SENSOR_ID)) { |
149 | curTempSensor = input; |
150 | } |
151 | } |
152 | for (SensorInput input : newSensors) { |
153 | if (input.getID().equals(SENSOR_ID)) { |
154 | newTempSensor = input; |
155 | } |
156 | } |
157 | if (curTempSensor == null || newTempSensor == null) { |
158 | if (logger.isDebugEnabled()) { |
159 | logger.debug("desire(State currentState=" + currentState |
160 | + ", State newState=" + newState |
161 | + ") - end - return defaultValue=" + defaultValue); |
162 | } |
163 | return defaultValue; |
164 | } |
165 | double returndouble = total(curTempSensor.getValue(), newTempSensor |
166 | .getValue()); |
167 | if (logger.isDebugEnabled()) { |
168 | logger |
169 | .debug("desire(State currentState=" + currentState + ", State newState=" + newState + ") - end - return value=" + returndouble); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
170 | } |
171 | return returndouble; |
172 | } |
173 | |
174 | /** |
175 | * Method returns the calculated total desire of the input temperatures. |
176 | * |
177 | * @param curTemperature |
178 | * current temperature |
179 | * @param newTemperature |
180 | * the new temperature |
181 | * @return the combined total desire |
182 | */ |
183 | double total(double curTemperature, double newTemperature) { |
184 | if (newTemperature > T_MAX || newTemperature < T_MIN) { |
185 | return MAXVALUE; |
186 | } |
187 | double newDesire = calculateDesire(newTemperature); |
188 | double combinedDesire = newDesire - calculateDesire(curTemperature); |
189 | if (combinedDesire < 0) { |
190 | return newDesire; |
191 | } |
192 | return Math.abs(combinedDesire); |
193 | } |
194 | |
195 | /** |
196 | * This method calculates the desire for a given temperature. |
197 | * |
198 | * @param temperature |
199 | * the temperature |
200 | * @return the desire for the given temperature |
201 | */ |
202 | double calculateDesire(double temperature) { |
203 | if (temperature > T_MAX || temperature < T_MIN) { |
204 | return MAXVALUE; // Large value due to plant fatality |
205 | } |
206 | double dMax = Math.pow(K_MAX, Math.abs(T_MAX - temperature)); |
207 | double dMin = Math.pow(K_MIN, Math.abs(temperature - T_MIN)); |
208 | double dMean = Math.abs((T_MEAN - temperature) / (T_MAX - T_MIN)); |
209 | // Rounding to eliminate negligible values |
210 | double maxPower = Math.max(dMin, dMax); |
211 | if (maxPower < 0.001) { |
212 | maxPower = 0; |
213 | } |
214 | return (double) Math.max(maxPower, dMean); |
215 | } |
216 | |
217 | /* |
218 | * (non-Javadoc) |
219 | * |
220 | * @see dk.deepthought.sidious.rules.Rule#getGoals() |
221 | */ |
222 | public Collection<Goal> getGoals() { |
223 | SensorInput sensorInput = new SensorInput(SENSOR_ID, T_MEAN); |
224 | ArrayList<SensorInput> list = new ArrayList<SensorInput>(); |
225 | list.add(sensorInput); |
226 | double currentTemperature = ServiceEngine.getSensorValue(SENSOR_ID); |
227 | State goalState = new ClimaticState(list); |
228 | double calculateDesire = calculateDesire(currentTemperature); |
229 | Goal g = new Goal(goalState, calculateDesire, getParentID()); |
230 | ArrayList<Goal> goalList = new ArrayList<Goal>(); |
231 | goalList.add(g); |
232 | return goalList; |
233 | } |
234 | |
235 | } |