Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1033 | werner | 1 | /******************************************************************************************** |
2 | ** iLand - an individual based forest landscape and disturbance model |
||
3 | ** http://iland.boku.ac.at |
||
4 | ** Copyright (C) 2009- Werner Rammer, Rupert Seidl |
||
5 | ** |
||
6 | ** This program is free software: you can redistribute it and/or modify |
||
7 | ** it under the terms of the GNU General Public License as published by |
||
8 | ** the Free Software Foundation, either version 3 of the License, or |
||
9 | ** (at your option) any later version. |
||
10 | ** |
||
11 | ** This program is distributed in the hope that it will be useful, |
||
12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | ** GNU General Public License for more details. |
||
15 | ** |
||
16 | ** You should have received a copy of the GNU General Public License |
||
17 | ** along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
18 | ********************************************************************************************/ |
||
19 | |||
813 | werner | 20 | #ifndef FOMESCRIPT_H |
21 | #define FOMESCRIPT_H |
||
22 | |||
23 | #include <QObject> |
||
1065 | werner | 24 | #include <QStringList> |
813 | werner | 25 | |
26 | #include "fmstand.h" |
||
27 | #include "fmunit.h" |
||
905 | werner | 28 | namespace ABE { |
813 | werner | 29 | |
815 | werner | 30 | class StandObj; |
940 | werner | 31 | class UnitObj; |
815 | werner | 32 | class SimulationObj; |
958 | werner | 33 | class SchedulerObj; |
1061 | werner | 34 | class STPObj; |
884 | werner | 35 | class FMTreeList; // forward |
1061 | werner | 36 | class FMSTP; // forward |
963 | werner | 37 | class ActivityObj; |
815 | werner | 38 | |
813 | werner | 39 | /// FomeScript provides general helping functions for the Javascript world. |
934 | werner | 40 | /// the object is known as 'fmengine'. |
813 | werner | 41 | class FomeScript : public QObject |
42 | { |
||
43 | Q_OBJECT |
||
890 | werner | 44 | Q_PROPERTY(bool verbose READ verbose WRITE setVerbose) |
897 | werner | 45 | Q_PROPERTY(int standId READ standId WRITE setStandId) |
813 | werner | 46 | public: |
47 | explicit FomeScript(QObject *parent = 0); |
||
884 | werner | 48 | ~FomeScript(); |
815 | werner | 49 | // prepare scripting features |
50 | void setupScriptEnvironment(); |
||
51 | // functions |
||
887 | werner | 52 | /// prepares the context for executing javascript functions |
53 | /// by setting up all internal structures for the forest stand 'stand'. |
||
938 | werner | 54 | static void setExecutionContext(FMStand *stand, bool add_agent=false); |
887 | werner | 55 | |
893 | werner | 56 | /// special function for setting context without a valid stand |
57 | static void setActivity(Activity *act); |
||
58 | |||
887 | werner | 59 | /// static accessor function for the responsible script bridge |
886 | werner | 60 | static FomeScript *bridge(); |
887 | werner | 61 | /// returns a string for debug/trace messages |
62 | const QString &context() const { return mStand?mStand->context():mInvalidContext; } |
||
813 | werner | 63 | |
1063 | werner | 64 | /// convert a javascript object to a string (for debug output) |
65 | static QString JStoString(QJSValue value); |
||
885 | werner | 66 | |
1063 | werner | 67 | |
885 | werner | 68 | StandObj *standObj() const { return mStandObj; } |
940 | werner | 69 | UnitObj *siteObj() const { return mUnitObj; } |
885 | werner | 70 | FMTreeList *treesObj() const { return mTrees; } |
901 | werner | 71 | ActivityObj *activityObj() const { return mActivityObj; } |
885 | werner | 72 | |
890 | werner | 73 | // Properties |
74 | /// verbose: when true, the logging intensity is increased significantly. |
||
75 | bool verbose() const; |
||
76 | void setVerbose(bool arg); |
||
77 | |||
897 | werner | 78 | int standId() const; |
79 | void setStandId(int new_stand_id); |
||
80 | |||
813 | werner | 81 | signals: |
82 | |||
83 | public slots: |
||
887 | werner | 84 | /// logging function (which includes exeuction context) |
85 | void log(QJSValue value); |
||
901 | werner | 86 | /// abort execution |
87 | void abort(QJSValue message); |
||
870 | werner | 88 | /// adds a management program (STP) that is provided as the Javascript object 'program'. 'name' is used internally. |
89 | bool addManagement(QJSValue program, QString name); |
||
1207 | werner | 90 | /// set the STP with the name 'name' to the (new) 'program'. This reloads the STP definition (and all activities). |
91 | /// if 'name' is not present, nothing happens. |
||
92 | bool updateManagement(QJSValue program, QString name); |
||
1208 | werner | 93 | /// add a certain stp (given by 'name') to the agent 'agentname'. Returns false if either stp or agent were not found. |
94 | bool addManagementToAgentType(QString name, QString agentname); |
||
884 | werner | 95 | /// add an agent definition (Javascript). 'name' is used internally. Returns true on success. |
938 | werner | 96 | bool addAgentType(QJSValue program, QString name); |
97 | /// create an agent of type 'agent_type' (the name of an agent type) and give the name 'agent_name'. 'agent_name' needs to be unique. |
||
98 | QJSValue addAgent(QString agent_type, QString agent_name); |
||
884 | werner | 99 | /// executes an activity for stand 'stand_id'. This bypasses the normal scheduling (useful for debugging/testing). |
100 | /// returns false if activity could not be found for the stand. |
||
101 | bool runActivity(int stand_id, QString activity); |
||
1061 | werner | 102 | /// executes an the "evaluate" part of the activity for stand 'stand_id'. This bypasses the normal scheduling (useful for debugging/testing). |
103 | /// returns false if activity could not be found for the stand. |
||
104 | bool runActivityEvaluate(int stand_id, QString activity); |
||
105 | |||
938 | werner | 106 | /// execute 'function' of the agent for the given stand; this is primarily aimed at testing/debugging. |
107 | bool runAgent(int stand_id, QString function); |
||
934 | werner | 108 | // special functions |
951 | werner | 109 | bool isValidStand(int stand_id); |
1059 | werner | 110 | QStringList standIds(); |
1089 | werner | 111 | QJSValue activity(QString stp_name, QString activity_name); |
890 | werner | 112 | |
934 | werner | 113 | void runPlanting(int stand_id, QJSValue planting_item); |
940 | werner | 114 | public: |
115 | static int levelIndex(const QString &level_label); |
||
116 | static const QString levelLabel(const int level_index); |
||
890 | werner | 117 | |
815 | werner | 118 | private: |
887 | werner | 119 | static QString mInvalidContext; |
120 | const FMStand *mStand; |
||
815 | werner | 121 | StandObj *mStandObj; |
940 | werner | 122 | UnitObj *mUnitObj; |
815 | werner | 123 | SimulationObj *mSimulationObj; |
893 | werner | 124 | ActivityObj *mActivityObj; |
884 | werner | 125 | FMTreeList *mTrees; |
958 | werner | 126 | SchedulerObj *mSchedulerObj; |
1061 | werner | 127 | STPObj *mSTPObj; |
901 | werner | 128 | QString mLastErrorMessage; |
893 | werner | 129 | |
813 | werner | 130 | }; |
131 | |||
132 | /// StandObj is the bridge to stand variables from the Javascript world |
||
133 | class StandObj: public QObject |
||
134 | { |
||
135 | Q_OBJECT |
||
885 | werner | 136 | Q_PROPERTY (bool trace READ trace WRITE setTrace) |
938 | werner | 137 | Q_PROPERTY (QJSValue agent READ agent) |
813 | werner | 138 | Q_PROPERTY (double basalArea READ basalArea) |
139 | Q_PROPERTY (double age READ age) |
||
934 | werner | 140 | Q_PROPERTY (double absoluteAge READ absoluteAge WRITE setAbsoluteAge) |
813 | werner | 141 | Q_PROPERTY (double volume READ volume) |
1059 | werner | 142 | Q_PROPERTY (double height READ height) |
143 | Q_PROPERTY (double topHeight READ topHeight) |
||
869 | werner | 144 | Q_PROPERTY (int id READ id) |
875 | werner | 145 | Q_PROPERTY (int nspecies READ nspecies) |
1059 | werner | 146 | Q_PROPERTY (double area READ area) |
934 | werner | 147 | Q_PROPERTY (int elapsed READ timeSinceLastExecution) |
148 | Q_PROPERTY (QString lastActivity READ lastActivity) |
||
940 | werner | 149 | |
934 | werner | 150 | Q_PROPERTY (double U READ rotationLength) |
940 | werner | 151 | Q_PROPERTY(QString speciesComposition READ speciesComposition ) |
152 | Q_PROPERTY(QString thinningIntensity READ thinningIntensity ) |
||
153 | |||
154 | |||
813 | werner | 155 | /* basalArea: 0, // total basal area/ha of the stand |
156 | volume: 100, // total volume/ha of the stand |
||
157 | speciesCount: 3, // number of species present in the stand with trees > 4m |
||
158 | age: 100, // "age" of the stand (in relation to "U") |
||
159 | flags: {}*/ |
||
160 | public slots: |
||
897 | werner | 161 | /// basal area of a given species (m2/ha) given by Id. |
1101 | werner | 162 | double speciesBasalAreaOf(QString species_id) const {return mStand->basalArea(species_id); } |
163 | double relSpeciesBasalAreaOf(QString species_id) const {return mStand->relBasalArea(species_id); } |
||
164 | double speciesBasalArea(int index) const { if (index>=0 && index<nspecies()) return mStand->speciesData(index).basalArea; else return 0.; } |
||
165 | double relSpeciesBasalArea(int index) const { if (index>=0 && index<nspecies()) return mStand->speciesData(index).relBasalArea; else return 0.; } |
||
897 | werner | 166 | QString speciesId(int index) const; |
813 | werner | 167 | |
168 | // set and get standspecific data (persistent!) |
||
815 | werner | 169 | void setFlag(const QString &name, QJSValue value){ const_cast<FMStand*>(mStand)->setProperty(name, value);} |
170 | QJSValue flag(const QString &name) { return const_cast<FMStand*>(mStand)->property(name); } |
||
888 | werner | 171 | QJSValue activity(QString name); |
938 | werner | 172 | QJSValue agent(); |
888 | werner | 173 | |
897 | werner | 174 | // actions |
175 | /// force a reload of the stand data. |
||
1063 | werner | 176 | void reload() { if (mStand) mStand->reload(true); } |
177 | void sleep(int years) { if (mStand) mStand->sleep(years); } |
||
897 | werner | 178 | |
934 | werner | 179 | void setAbsoluteAge(double arg); |
1208 | werner | 180 | /// start the management program again (initialize the stand) |
181 | void reset(); |
||
934 | werner | 182 | |
813 | werner | 183 | public: |
184 | explicit StandObj(QObject *parent = 0): QObject(parent), mStand(0) {} |
||
885 | werner | 185 | // system stuff |
887 | werner | 186 | void setStand(FMStand* stand) { mStand = stand; } |
885 | werner | 187 | bool trace() const; |
188 | void setTrace(bool do_trace); |
||
189 | |||
190 | // properties of the forest |
||
901 | werner | 191 | double basalArea() const { if (mStand)return mStand->basalArea(); throwError("basalArea"); return -1.;} |
1059 | werner | 192 | double height() const { if (mStand)return mStand->height(); throwError("height"); return -1.;} |
193 | double topHeight() const { if (mStand)return mStand->topHeight(); throwError("topHeight"); return -1.;} |
||
901 | werner | 194 | double age() const {if (mStand)return mStand->age(); throwError("age"); return -1.;} |
934 | werner | 195 | double absoluteAge() const {if (mStand)return mStand->absoluteAge(); throwError("absoluteAge"); return -1.; } |
901 | werner | 196 | double volume() const {if (mStand) return mStand->volume(); throwError("volume"); return -1.; } |
197 | int id() const { if (mStand) return mStand->id(); throwError("id"); return -1; } |
||
198 | int nspecies() const {if (mStand) return mStand->nspecies(); throwError("id"); return -1;} |
||
1059 | werner | 199 | double area() const {if (mStand) return mStand->area(); throwError("area"); return -1;} |
934 | werner | 200 | int timeSinceLastExecution() const; |
201 | QString lastActivity() const; |
||
202 | double rotationLength() const; |
||
940 | werner | 203 | QString speciesComposition() const; |
204 | QString thinningIntensity() const; |
||
885 | werner | 205 | |
206 | |||
934 | werner | 207 | |
940 | werner | 208 | |
813 | werner | 209 | private: |
901 | werner | 210 | void throwError(QString msg) const; |
887 | werner | 211 | FMStand *mStand; |
813 | werner | 212 | }; |
213 | |||
1061 | werner | 214 | /** @brief The UnitObj class is the Javascript object known as 'unit' in JS and represents |
215 | * a management unit. |
||
216 | */ |
||
940 | werner | 217 | class UnitObj: public QObject |
813 | werner | 218 | { |
219 | Q_OBJECT |
||
220 | Q_PROPERTY (QString harvestMode READ harvestMode) |
||
940 | werner | 221 | Q_PROPERTY(QString speciesComposition READ speciesComposition ) |
222 | Q_PROPERTY(double U READ U ) |
||
223 | Q_PROPERTY(QString thinningIntensity READ thinningIntensity ) |
||
224 | // performance indicators |
||
225 | Q_PROPERTY(double MAIChange READ MAIChange ) |
||
226 | Q_PROPERTY(double MAILevel READ MAILevel ) |
||
977 | werner | 227 | Q_PROPERTY(double landscapeMAI READ landscapeMAI ) |
940 | werner | 228 | Q_PROPERTY(double mortalityChange READ mortalityChange ) |
229 | Q_PROPERTY(double mortalityLevel READ mortalityLevel ) |
||
230 | Q_PROPERTY(double regenerationChange READ regenerationChange ) |
||
231 | Q_PROPERTY(double regenerationLevel READ regenerationLevel ) |
||
232 | |||
233 | public slots: |
||
234 | /// main function to provide agent decisions to the engine |
||
235 | bool agentUpdate(QString what, QString how, QString when); |
||
813 | werner | 236 | public: |
940 | werner | 237 | explicit UnitObj(QObject *parent = 0): QObject(parent) {} |
815 | werner | 238 | void setStand(const FMStand* stand) { mStand = stand; } |
940 | werner | 239 | QString harvestMode() const; |
240 | QString speciesComposition() const; |
||
241 | double U() const; |
||
242 | QString thinningIntensity() const; |
||
243 | |||
244 | // performance indicators |
||
245 | double MAIChange() const; |
||
246 | double MAILevel() const; |
||
977 | werner | 247 | double landscapeMAI() const; |
940 | werner | 248 | double mortalityChange() const; |
249 | double mortalityLevel() const; |
||
250 | double regenerationChange() const; |
||
251 | double regenerationLevel() const; |
||
252 | |||
253 | |||
813 | werner | 254 | private: |
815 | werner | 255 | const FMStand *mStand; |
813 | werner | 256 | |
257 | }; |
||
258 | |||
1061 | werner | 259 | /** @brief The SimulationObj encapsulates the 'simulation' object in JS. The 'simulation' object |
260 | * is used for global scenarios (e.g., changes in timber price). |
||
261 | */ |
||
813 | werner | 262 | class SimulationObj: public QObject |
263 | { |
||
264 | Q_OBJECT |
||
265 | Q_PROPERTY (double timberPriceIndex READ timberPriceIndex) |
||
266 | public: |
||
267 | explicit SimulationObj(QObject *parent = 0): QObject(parent) {} |
||
268 | double timberPriceIndex() const { return 1.010101; } // dummy |
||
269 | private: |
||
270 | |||
271 | }; |
||
870 | werner | 272 | |
1061 | werner | 273 | /** @brief The STPObj encapsulates the 'stp' object in JS. The 'stp' object |
274 | * is provides a link to the currently active stand treatment programme. |
||
275 | */ |
||
276 | class STPObj: public QObject |
||
277 | { |
||
278 | Q_OBJECT |
||
279 | Q_PROPERTY (QString name READ name) |
||
280 | Q_PROPERTY (QJSValue options READ options) |
||
281 | public: |
||
282 | void setSTP(FMStand *stand); |
||
283 | explicit STPObj(QObject *parent = 0): QObject(parent) { mSTP = 0;} |
||
284 | QJSValue options() { return mOptions; } |
||
285 | QString name(); |
||
286 | private: |
||
287 | FMSTP *mSTP; |
||
288 | QJSValue mOptions; ///< options of the current STP |
||
870 | werner | 289 | |
1061 | werner | 290 | |
291 | }; |
||
292 | /** |
||
293 | * @brief The ActivityObj class encapsulates the 'activity' object in JS. The 'activity' |
||
294 | * can be used to fine-tune the management activities (e.g., set the enable/disable flags). |
||
295 | */ |
||
888 | werner | 296 | class ActivityObj : public QObject |
297 | { |
||
298 | Q_OBJECT |
||
299 | Q_PROPERTY (bool enabled READ enabled WRITE setEnabled) |
||
893 | werner | 300 | Q_PROPERTY(bool active READ active WRITE setActive) |
301 | Q_PROPERTY(bool finalHarvest READ finalHarvest WRITE setFinalHarvest) |
||
302 | Q_PROPERTY(bool scheduled READ scheduled WRITE setScheduled) |
||
888 | werner | 303 | Q_PROPERTY(QString name READ name) |
304 | public: |
||
893 | werner | 305 | explicit ActivityObj(QObject *parent = 0): QObject(parent) { mActivityIndex=-1; mStand=0; mActivity=0; } |
306 | // used to construct a link to a given activty (with an index that could be not the currently active index!) |
||
307 | ActivityObj(FMStand *stand, Activity *act, int index ): QObject(0) { mActivityIndex=index; mStand=stand; mActivity=act; } |
||
901 | werner | 308 | /// default-case: set a forest stand as the context. |
893 | werner | 309 | void setStand(FMStand *stand) { mStand = stand; mActivity=0; mActivityIndex=-1;} |
901 | werner | 310 | /// set an activity context (without a stand) to access base properties of activities |
893 | werner | 311 | void setActivity(Activity *act) { mStand = 0; mActivity=act; mActivityIndex=-1;} |
901 | werner | 312 | /// set an activity that is not the current activity of the stand |
313 | void setActivityIndex(const int index) { mActivityIndex = index; } |
||
893 | werner | 314 | |
315 | // properties |
||
316 | |||
317 | QString name() const; |
||
888 | werner | 318 | bool enabled() const; |
319 | void setEnabled(bool do_enable); |
||
893 | werner | 320 | |
321 | bool active() const { return flags().active(); } |
||
322 | void setActive(bool activate) { flags().setActive(activate);} |
||
323 | |||
324 | bool finalHarvest() const { return flags().isFinalHarvest(); } |
||
325 | void setFinalHarvest(bool isfinal) { flags().setFinalHarvest(isfinal);} |
||
326 | |||
327 | bool scheduled() const { return flags().isScheduled(); } |
||
328 | void setScheduled(bool issched) { flags().setIsScheduled(issched);} |
||
888 | werner | 329 | public slots: |
330 | private: |
||
893 | werner | 331 | ActivityFlags &flags() const; // get (depending on the linked objects) the right flags |
1063 | werner | 332 | static ActivityFlags mEmptyFlags; |
888 | werner | 333 | int mActivityIndex; // link to base activity |
334 | Activity *mActivity; // pointer |
||
335 | FMStand *mStand; // and to the forest stand.... |
||
336 | |||
337 | }; |
||
338 | |||
1061 | werner | 339 | /** |
340 | * @brief The SchedulerObj class is accessible via 'scheduler' in Javascript. |
||
341 | */ |
||
958 | werner | 342 | class SchedulerObj : public QObject |
343 | { |
||
344 | Q_OBJECT |
||
345 | Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) |
||
346 | Q_PROPERTY(double harvestIntensity READ harvestIntensity WRITE setHarvestIntensity) |
||
347 | Q_PROPERTY(double useSustainableHarvest READ useSustainableHarvest WRITE setUseSustainableHarvest) |
||
348 | Q_PROPERTY(double maxHarvestLevel READ maxHarvestLevel WRITE setMaxHarvestLevel) |
||
1063 | werner | 349 | public slots: |
350 | void dump() const; ///< write log to console |
||
958 | werner | 351 | public: |
352 | explicit SchedulerObj(QObject *parent = 0): QObject(parent) {mStand=0; } |
||
353 | void setStand(FMStand *stand) { mStand = stand;} |
||
354 | |||
355 | bool enabled(); |
||
356 | void setEnabled(bool is_enabled); |
||
357 | double harvestIntensity(); |
||
358 | void setHarvestIntensity(double new_intensity); |
||
359 | double useSustainableHarvest(); |
||
360 | void setUseSustainableHarvest(double new_level); |
||
361 | double maxHarvestLevel(); |
||
362 | void setMaxHarvestLevel(double new_harvest_level); |
||
363 | |||
364 | private: |
||
365 | FMStand *mStand; // link to the forest stand |
||
366 | }; |
||
367 | |||
368 | |||
870 | werner | 369 | } // namespace |
370 | |||
813 | werner | 371 | #endif // FOMESCRIPT_H |