001 package dk.deepthought.sidious.rules;
002 
003 import java.util.ArrayList;
004 import java.util.Collection;
005 import java.util.Properties;
006 
007 import org.apache.commons.logging.Log;
008 import org.apache.commons.logging.LogFactory;
009 
010 import dk.deepthought.sidious.goalhandler.Goal;
011 import dk.deepthought.sidious.greenhouse.ClimaticState;
012 import dk.deepthought.sidious.greenhouse.SensorInput;
013 import dk.deepthought.sidious.services.ServiceEngine;
014 import dk.deepthought.sidious.supportsystem.State;
015 import dk.deepthought.sidious.supportsystem.Step;
016 import dk.deepthought.sidious.supportsystem.SuperLinkID;
017 import dk.deepthought.sidious.supportsystem.SystemSettings;
018 import dk.deepthought.sidious.util.RuleProperty;
019 
020 /**
021  * This class represents a temperature rule.
022  <p>
023  * The rule advocates for maintaining a mean temperature, and avoiding
024  * temperature boundaries.
025  
026  @author Deepthought
027  
028  */
029 public final class TemperatureRule extends Rule {
030 
031     private static final Log logger = LogFactory.getLog(TemperatureRule.class);
032 
033     /**
034      * The ID of the sensor this Rule depends on.
035      */
036     private final SuperLinkID SENSOR_ID;
037 
038     /**
039      * The RuleProperty of this class
040      */
041     private static RuleProperty ruleProperty;
042 
043     /**
044      * The mean temperature.
045      */
046     private final double T_MEAN;
047 
048     /**
049      * The max temperature.
050      */
051     private final double T_MAX;
052 
053     /**
054      * Coefficient for mathematical calculations
055      */
056     private final double K_MAX;
057 
058     /**
059      * Coefficient for mathematical calculations
060      */
061     private final double K_MIN;
062 
063     /**
064      * The min temperature.
065      */
066     private final double T_MIN;
067 
068     /**
069      * Arbitrary max value.
070      */
071     private static final double MAXVALUE = 1000;
072 
073     /**
074      * Constructor.
075      
076      @param parentId
077      *            the id of the parent <code>PlanRequester</code>
078      */
079     public TemperatureRule(final SuperLinkID parentId) {
080         if (parentId == null) {
081             logger.error("TemperatureRule(SuperLinkID parentId=null) "
082                     "- not valid input");
083             throw new IllegalArgumentException("parentID=null not valid input");
084         }
085         if (ruleProperty == null) {
086             ruleProperty = new RuleProperty(this.getClass().getSimpleName());
087         }
088         SENSOR_ID = SystemSettings.getTemperatureID();
089         //FIXME hent fra property igen!
090 //        SENSOR_ID = ruleProperty.getID("sensor_id");
091         T_MEAN = ruleProperty.getFloat("t_mean"20);
092         T_MAX = ruleProperty.getFloat("t_max"30);
093         K_MAX = ruleProperty.getFloat("k_max"0.5f);
094         K_MIN = ruleProperty.getFloat("k_min"0.5f);
095         T_MIN = ruleProperty.getFloat("t_min"5);
096         setParentID(parentId);
097         if (logger.isDebugEnabled()) {
098             logger.debug("TemperatureRule(SuperLinkID parentId=" + parentId
099                     ") - 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 = ((ClimaticStatecurrentState)
142                 .getSensors();
143         Collection<SensorInput> newSensors = ((ClimaticStatenewState)
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 (doubleMath.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 }