1 | package dk.deepthought.sidious.greenhouse; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.Collection; |
5 | |
6 | import net.jcip.annotations.Immutable; |
7 | |
8 | import org.apache.commons.logging.Log; |
9 | import org.apache.commons.logging.LogFactory; |
10 | |
11 | import dk.deepthought.sidious.supportsystem.Adjustable; |
12 | import dk.deepthought.sidious.supportsystem.State; |
13 | import dk.deepthought.sidious.supportsystem.SuperLinkID; |
14 | import dk.deepthought.sidious.supportsystem.SystemSettings; |
15 | |
16 | /** |
17 | * This class represents the CO2 setpoint of the greenhouse. |
18 | * |
19 | * @author Deepthought |
20 | * |
21 | */ |
22 | @Immutable |
23 | public class CO2SetPoint implements Adjustable { |
24 | /** |
25 | * Logger for this class |
26 | */ |
27 | private static final Log logger = LogFactory.getLog(CO2SetPoint.class); |
28 | |
29 | /** |
30 | * The setting of this CO2SetPoint. |
31 | */ |
32 | private final double setting; |
33 | |
34 | /** |
35 | * The id of the CO2 setpoint. |
36 | */ |
37 | private final SuperLinkID co2ID; |
38 | |
39 | /** |
40 | * Expected increase per minute. |
41 | */ |
42 | private static final double INCREASE_PER_MIN = 10; |
43 | |
44 | /** |
45 | * Expected decrease per minute. |
46 | */ |
47 | private static final double DECREASE_PER_MIN = -4; |
48 | |
49 | /** |
50 | * Internal enum to describe possible adjustments. |
51 | */ |
52 | private enum CO2Step { |
53 | UP(100), DOWN(-100); |
54 | |
55 | private double increment; |
56 | |
57 | CO2Step(double increment) { |
58 | this.increment = increment; |
59 | } |
60 | |
61 | public double getIncrement() { |
62 | return increment; |
63 | } |
64 | } |
65 | |
66 | /** |
67 | * Constructor. |
68 | * |
69 | * @param setting |
70 | * the setting of this CO2SetPoint |
71 | */ |
72 | public CO2SetPoint(double setting) { |
73 | this.co2ID = SystemSettings.getCO2ID(); |
74 | this.setting = setting; |
75 | } |
76 | |
77 | /* |
78 | * (non-Javadoc) |
79 | * |
80 | * @see dk.deepthought.sidious.supportsystem.Adjustable#consequence(dk.deepthought.sidious.supportsystem.State) |
81 | */ |
82 | public State consequence(State state) { |
83 | if (!(state instanceof ClimaticState)) { |
84 | String fail = "Input state must be a climatic state. - state=" |
85 | + state; |
86 | logger.error(fail); |
87 | throw new IllegalArgumentException(fail); |
88 | } |
89 | int timestep = SystemSettings.getTimestep(); |
90 | Collection<SensorInput> inputSensors = ((ClimaticState) state) |
91 | .getSensors(); |
92 | Collection<SensorInput> newSensors = new ArrayList<SensorInput>(); |
93 | for (SensorInput input : inputSensors) { |
94 | if (input.getID().equals(co2ID)) { |
95 | double sensorValue = input.getValue(); |
96 | double delta = setting - sensorValue; |
97 | double newValue = 0; |
98 | if (delta < 0) { |
99 | double decreaseFactor = DECREASE_PER_MIN * timestep; |
100 | if (delta >= decreaseFactor) { |
101 | newValue = setting; |
102 | } else { |
103 | newValue = decreaseFactor + sensorValue; |
104 | } |
105 | } else { |
106 | double increaseFactor = INCREASE_PER_MIN * timestep; |
107 | if (delta <= increaseFactor) { |
108 | newValue = setting; |
109 | } else { |
110 | newValue = increaseFactor + sensorValue; |
111 | } |
112 | } |
113 | newSensors.add(input.newInstanceWithNewValue(newValue)); |
114 | } else { |
115 | newSensors.add(input); |
116 | } |
117 | } |
118 | return new ClimaticState(newSensors); |
119 | } |
120 | |
121 | /* |
122 | * (non-Javadoc) |
123 | * |
124 | * @see dk.deepthought.sidious.supportsystem.Adjustable#possibleAdjustments() |
125 | */ |
126 | public Collection<Adjustable> possibleAdjustments() { |
127 | if (logger.isDebugEnabled()) { |
128 | logger.debug("possibleAdjustments() - start"); |
129 | } |
130 | |
131 | Collection<Adjustable> setpoints = new ArrayList<Adjustable>(); |
132 | for (CO2Step possibleDirection : CO2Step.values()) { |
133 | double result = setting + possibleDirection.getIncrement(); |
134 | assert result != Float.MAX_VALUE : "result exceeded Float.MAX_VALUE"; |
135 | setpoints.add(new CO2SetPoint(result)); |
136 | } |
137 | |
138 | if (logger.isDebugEnabled()) { |
139 | logger.debug("possibleAdjustments() - end - return value=" |
140 | + setpoints); |
141 | } |
142 | return setpoints; |
143 | } |
144 | |
145 | /* |
146 | * (non-Javadoc) |
147 | * |
148 | * @see dk.deepthought.sidious.supportsystem.Adjustable#getID() |
149 | */ |
150 | public SuperLinkID getID() { |
151 | return SystemSettings.getCO2SetPointID(); |
152 | } |
153 | |
154 | /* |
155 | * (non-Javadoc) |
156 | * |
157 | * @see dk.deepthought.sidious.supportsystem.Adjustable#getSetting() |
158 | */ |
159 | public double getSetting() { |
160 | return setting; |
161 | } |
162 | |
163 | |
164 | |
165 | /* (non-Javadoc) |
166 | * @see java.lang.Object#hashCode() |
167 | */ |
168 | @Override |
169 | public int hashCode() { |
170 | final int PRIME = 31; |
171 | int result = 1; |
172 | long temp; |
173 | temp = Double.doubleToLongBits(setting); |
174 | result = PRIME * result + (int) (temp ^ (temp >>> 32)); |
175 | return result; |
176 | } |
177 | |
178 | /* (non-Javadoc) |
179 | * @see java.lang.Object#equals(java.lang.Object) |
180 | */ |
181 | @Override |
182 | public boolean equals(Object obj) { |
183 | if (this == obj) |
184 | return true; |
185 | if (obj == null) |
186 | return false; |
187 | if (getClass() != obj.getClass()) |
188 | return false; |
189 | final CO2SetPoint other = (CO2SetPoint) obj; |
190 | if (Double.doubleToLongBits(setting) != Double.doubleToLongBits(other.setting)) |
191 | return false; |
192 | return true; |
193 | } |
194 | |
195 | @Override |
196 | public String toString() { |
197 | return getClass().getSimpleName() + "[setting=" + setting + "]"; |
198 | } |
199 | } |