(root)/src/abe/fomescript.h - Rev 1217
Rev 1208 |
Rev 1218 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/********************************************************************************************
** iLand - an individual based forest landscape and disturbance model
** http://iland.boku.ac.at
** Copyright (C) 2009- Werner Rammer, Rupert Seidl
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
********************************************************************************************/
#ifndef FOMESCRIPT_H
#define FOMESCRIPT_H
#include <QObject>
#include <QStringList>
#include "fmstand.h"
#include "fmunit.h"
namespace ABE {
class StandObj;
class UnitObj;
class SimulationObj;
class SchedulerObj;
class STPObj;
class FMTreeList; // forward
class FMSTP; // forward
class ActivityObj;
/// FomeScript provides general helping functions for the Javascript world.
/// the object is known as 'fmengine'.
class FomeScript : public QObject
{
Q_OBJECT
Q_PROPERTY(bool verbose READ verbose WRITE setVerbose)
Q_PROPERTY(int standId READ standId WRITE setStandId)
public:
explicit FomeScript(QObject *parent = 0);
~FomeScript();
// prepare scripting features
void setupScriptEnvironment();
// functions
/// prepares the context for executing javascript functions
/// by setting up all internal structures for the forest stand 'stand'.
static void setExecutionContext(FMStand *stand, bool add_agent=false);
/// special function for setting context without a valid stand
static void setActivity(Activity *act);
/// static accessor function for the responsible script bridge
static FomeScript *bridge();
/// returns a string for debug/trace messages
const QString &context() const { return mStand?mStand->context():mInvalidContext; }
/// convert a javascript object to a string (for debug output)
static QString JStoString(QJSValue value);
StandObj *standObj() const { return mStandObj; }
UnitObj *siteObj() const { return mUnitObj; }
FMTreeList *treesObj() const { return mTrees; }
ActivityObj *activityObj() const { return mActivityObj; }
// Properties
/// verbose: when true, the logging intensity is increased significantly.
bool verbose() const;
void setVerbose(bool arg);
int standId() const;
void setStandId(int new_stand_id);
signals:
public slots:
/// logging function (which includes exeuction context)
void log(QJSValue value);
/// abort execution
void abort(QJSValue message);
/// adds a management program (STP) that is provided as the Javascript object 'program'. 'name' is used internally.
bool addManagement(QJSValue program, QString name);
/// set the STP with the name 'name' to the (new) 'program'. This reloads the STP definition (and all activities).
/// if 'name' is not present, nothing happens.
bool updateManagement(QJSValue program, QString name);
/// add a certain stp (given by 'name') to the agent 'agentname'. Returns false if either stp or agent were not found.
bool addManagementToAgentType(QString name, QString agentname);
/// add an agent definition (Javascript). 'name' is used internally. Returns true on success.
bool addAgentType(QJSValue program, QString name);
/// 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.
QJSValue addAgent(QString agent_type, QString agent_name);
/// executes an activity for stand 'stand_id'. This bypasses the normal scheduling (useful for debugging/testing).
/// returns false if activity could not be found for the stand.
bool runActivity(int stand_id, QString activity);
/// executes an the "evaluate" part of the activity for stand 'stand_id'. This bypasses the normal scheduling (useful for debugging/testing).
/// returns false if activity could not be found for the stand.
bool runActivityEvaluate(int stand_id, QString activity);
/// execute 'function' of the agent for the given stand; this is primarily aimed at testing/debugging.
bool runAgent(int stand_id, QString function);
// special functions
bool isValidStand(int stand_id);
QStringList standIds();
QJSValue activity(QString stp_name, QString activity_name);
void runPlanting(int stand_id, QJSValue planting_item);
public:
static int levelIndex(const QString &level_label);
static const QString levelLabel(const int level_index);
private:
static QString mInvalidContext;
const FMStand *mStand;
StandObj *mStandObj;
UnitObj *mUnitObj;
SimulationObj *mSimulationObj;
ActivityObj *mActivityObj;
FMTreeList *mTrees;
SchedulerObj *mSchedulerObj;
STPObj *mSTPObj;
QString mLastErrorMessage;
};
/// StandObj is the bridge to stand variables from the Javascript world
class StandObj: public QObject
{
Q_OBJECT
Q_PROPERTY (bool trace READ trace WRITE setTrace)
Q_PROPERTY (QJSValue agent READ agent)
Q_PROPERTY (double basalArea READ basalArea)
Q_PROPERTY (double age READ age)
Q_PROPERTY (double absoluteAge READ absoluteAge WRITE setAbsoluteAge)
Q_PROPERTY (double volume READ volume)
Q_PROPERTY (double height READ height)
Q_PROPERTY (double topHeight READ topHeight)
Q_PROPERTY (int id READ id)
Q_PROPERTY (int nspecies READ nspecies)
Q_PROPERTY (double area READ area)
Q_PROPERTY (int elapsed READ timeSinceLastExecution)
Q_PROPERTY (QString lastActivity READ lastActivity)
Q_PROPERTY (double U READ rotationLength)
Q_PROPERTY(QString speciesComposition READ speciesComposition )
Q_PROPERTY(QString thinningIntensity READ thinningIntensity )
/* basalArea: 0, // total basal area/ha of the stand
volume: 100, // total volume/ha of the stand
speciesCount: 3, // number of species present in the stand with trees > 4m
age: 100, // "age" of the stand (in relation to "U")
flags: {}*/
public slots:
/// basal area of a given species (m2/ha) given by Id.
double speciesBasalAreaOf(QString species_id) const {return mStand->basalArea(species_id); }
double relSpeciesBasalAreaOf(QString species_id) const {return mStand->relBasalArea(species_id); }
double speciesBasalArea(int index) const { if (index>=0 && index<nspecies()) return mStand->speciesData(index).basalArea; else return 0.; }
double relSpeciesBasalArea(int index) const { if (index>=0 && index<nspecies()) return mStand->speciesData(index).relBasalArea; else return 0.; }
QString speciesId(int index) const;
// set and get standspecific data (persistent!)
void setFlag(const QString &name, QJSValue value){ const_cast<FMStand*>(mStand)->setProperty(name, value);}
QJSValue flag(const QString &name) { return const_cast<FMStand*>(mStand)->property(name); }
QJSValue activity(QString name);
QJSValue agent();
// actions
/// force a reload of the stand data.
void reload() { if (mStand) mStand->reload(true); }
void sleep(int years) { if (mStand) mStand->sleep(years); }
void setAbsoluteAge(double arg);
/// start the management program again (initialize the stand)
void reset();
public:
explicit StandObj(QObject *parent = 0): QObject(parent), mStand(0) {}
// system stuff
void setStand(FMStand* stand) { mStand = stand; }
bool trace() const;
void setTrace(bool do_trace);
// properties of the forest
double basalArea() const { if (mStand)return mStand->basalArea(); throwError("basalArea"); return -1.;}
double height() const { if (mStand)return mStand->height(); throwError("height"); return -1.;}
double topHeight() const { if (mStand)return mStand->topHeight(); throwError("topHeight"); return -1.;}
double age() const {if (mStand)return mStand->age(); throwError("age"); return -1.;}
double absoluteAge() const {if (mStand)return mStand->absoluteAge(); throwError("absoluteAge"); return -1.; }
double volume() const {if (mStand) return mStand->volume(); throwError("volume"); return -1.; }
int id() const { if (mStand) return mStand->id(); throwError("id"); return -1; }
int nspecies() const {if (mStand) return mStand->nspecies(); throwError("id"); return -1;}
double area() const {if (mStand) return mStand->area(); throwError("area"); return -1;}
int timeSinceLastExecution() const;
QString lastActivity() const;
double rotationLength() const;
QString speciesComposition() const;
QString thinningIntensity() const;
private:
void throwError(QString msg) const;
FMStand *mStand;
};
/** @brief The UnitObj class is the Javascript object known as 'unit' in JS and represents
* a management unit.
*/
class UnitObj: public QObject
{
Q_OBJECT
Q_PROPERTY (QString harvestMode READ harvestMode)
Q_PROPERTY(QString speciesComposition READ speciesComposition )
Q_PROPERTY(double U READ U )
Q_PROPERTY(QString thinningIntensity READ thinningIntensity )
// performance indicators
Q_PROPERTY(double MAIChange READ MAIChange )
Q_PROPERTY(double MAILevel READ MAILevel )
Q_PROPERTY(double landscapeMAI READ landscapeMAI )
Q_PROPERTY(double mortalityChange READ mortalityChange )
Q_PROPERTY(double mortalityLevel READ mortalityLevel )
Q_PROPERTY(double regenerationChange READ regenerationChange )
Q_PROPERTY(double regenerationLevel READ regenerationLevel )
public slots:
/// main function to provide agent decisions to the engine
bool agentUpdate(QString what, QString how, QString when);
public:
explicit UnitObj(QObject *parent = 0): QObject(parent) {}
void setStand(const FMStand* stand) { mStand = stand; }
QString harvestMode() const;
QString speciesComposition() const;
double U() const;
QString thinningIntensity() const;
// performance indicators
double MAIChange() const;
double MAILevel() const;
double landscapeMAI() const;
double mortalityChange() const;
double mortalityLevel() const;
double regenerationChange() const;
double regenerationLevel() const;
private:
const FMStand *mStand;
};
/** @brief The SimulationObj encapsulates the 'simulation' object in JS. The 'simulation' object
* is used for global scenarios (e.g., changes in timber price).
*/
class SimulationObj: public QObject
{
Q_OBJECT
Q_PROPERTY (double timberPriceIndex READ timberPriceIndex)
public:
explicit SimulationObj(QObject *parent = 0): QObject(parent) {}
double timberPriceIndex() const { return 1.010101; } // dummy
private:
};
/** @brief The STPObj encapsulates the 'stp' object in JS. The 'stp' object
* is provides a link to the currently active stand treatment programme.
*/
class STPObj: public QObject
{
Q_OBJECT
Q_PROPERTY (QString name READ name)
Q_PROPERTY (QJSValue options READ options)
public:
void setSTP(FMStand *stand);
explicit STPObj(QObject *parent = 0): QObject(parent) { mSTP = 0;}
QJSValue options() { return mOptions; }
QString name();
private:
FMSTP *mSTP;
QJSValue mOptions; ///< options of the current STP
};
/**
* @brief The ActivityObj class encapsulates the 'activity' object in JS. The 'activity'
* can be used to fine-tune the management activities (e.g., set the enable/disable flags).
*/
class ActivityObj : public QObject
{
Q_OBJECT
Q_PROPERTY (bool enabled READ enabled WRITE setEnabled)
Q_PROPERTY(bool active READ active WRITE setActive)
Q_PROPERTY(bool finalHarvest READ finalHarvest WRITE setFinalHarvest)
Q_PROPERTY(bool scheduled READ scheduled WRITE setScheduled)
Q_PROPERTY(QString name READ name)
public:
explicit ActivityObj(QObject *parent = 0): QObject(parent) { mActivityIndex=-1; mStand=0; mActivity=0; }
// used to construct a link to a given activty (with an index that could be not the currently active index!)
ActivityObj(FMStand *stand, Activity *act, int index ): QObject(0) { mActivityIndex=index; mStand=stand; mActivity=act; }
/// default-case: set a forest stand as the context.
void setStand(FMStand *stand) { mStand = stand; mActivity=0; mActivityIndex=-1;}
/// set an activity context (without a stand) to access base properties of activities
void setActivity(Activity *act) { mStand = 0; mActivity=act; mActivityIndex=-1;}
/// set an activity that is not the current activity of the stand
void setActivityIndex(const int index) { mActivityIndex = index; }
// properties
QString name() const;
bool enabled() const;
void setEnabled(bool do_enable);
bool active() const { return flags().active(); }
void setActive(bool activate) { flags().setActive(activate);}
bool finalHarvest() const { return flags().isFinalHarvest(); }
void setFinalHarvest(bool isfinal) { flags().setFinalHarvest(isfinal);}
bool scheduled() const { return flags().isScheduled(); }
void setScheduled(bool issched) { flags().setIsScheduled(issched);}
public slots:
private:
ActivityFlags &flags() const; // get (depending on the linked objects) the right flags
static ActivityFlags mEmptyFlags;
int mActivityIndex; // link to base activity
Activity *mActivity; // pointer
FMStand *mStand; // and to the forest stand....
};
/**
* @brief The SchedulerObj class is accessible via 'scheduler' in Javascript.
*/
class SchedulerObj : public QObject
{
Q_OBJECT
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled)
Q_PROPERTY(double harvestIntensity READ harvestIntensity WRITE setHarvestIntensity)
Q_PROPERTY(double useSustainableHarvest READ useSustainableHarvest WRITE setUseSustainableHarvest)
Q_PROPERTY(double maxHarvestLevel READ maxHarvestLevel WRITE setMaxHarvestLevel)
public slots:
void dump() const; ///< write log to console
public:
explicit SchedulerObj(QObject *parent = 0): QObject(parent) {mStand=0; }
void setStand(FMStand *stand) { mStand = stand;}
bool enabled();
void setEnabled(bool is_enabled);
double harvestIntensity();
void setHarvestIntensity(double new_intensity);
double useSustainableHarvest();
void setUseSustainableHarvest(double new_level);
double maxHarvestLevel();
void setMaxHarvestLevel(double new_harvest_level);
private:
FMStand *mStand; // link to the forest stand
};
} // namespace
#endif // FOMESCRIPT_H