Subversion Repositories public iLand

Rev

Rev 1220 | 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 ACTIVITY_H
#define ACTIVITY_H
#include <QJSValue>
#include <QVector>
#include <QMap>

class Expression; // forward

namespace ABE {


class FMStand;
class FMSTP;


class Schedule {
public:
    // setup and life cycle
    Schedule()  {}
    Schedule(QJSValue &js_value) { clear(); setup(js_value); }
    void clear() { tmin=tmax=topt=-1; tminrel=tmaxrel=toptrel=-1.; force_execution=false; repeat_interval=-1; repeat=false; absolute=false; }
    void setup(const QJSValue &js_value);
    QString dump() const;
    // functions
    /// value() evaluates the schedule for the given 'stand'.
    /// return 0..1 (0: no fit, 1: perfect time).
    /// Special value -1: expired (i.e. current time past the maximum schedule time).
    double value(const FMStand *stand, const int specific_year=-1);
    /// gives (fixed) earliest possible execution time
    double minValue(const double U=100.) const;
    /// returns the latest possible execution time
    double maxValue(const double U=100.) const;
    /// returns the "optimal" year, i.e. the first year when prob. to execute is highest.
    double optimalValue(const double U=100.) const;
    // some stuffs
    int tmin; int tmax; int topt;
    double tminrel; double tmaxrel; double toptrel;
    bool force_execution;
    // repeating
    int repeat_interval;
    bool repeat;
    bool absolute;
};

class Events {
public:
    Events() {}
    /// clear the list of events
    void clear();
    /// setup events from the javascript object
    void setup(QJSValue &js_value, QStringList event_names);
    /// execute javascript event /if registered) in the context of the forest stand 'stand'.
    QJSValue run(const QString event, FMStand *stand, QJSValueList *params=0);
    /// returns true, if the event 'event' is available.
    bool hasEvent(const QString &event) const;
    QString dump(); ///< prints some debug info
private:
    QJSValue mInstance; ///< object holding the events
    QMap<QString, QJSValue> mEvents; ///< list of event names and javascript functions
};

/** DynamicExpression encapsulates an "expression" that can be either a iLand expression, a constant or a javascript function.
*/

struct DynamicExpression {
    DynamicExpression(): filter_type(ftInvalid), expr(0) {}
    ~DynamicExpression();
    void setup(const QJSValue &js_value);
    bool evaluate(FMStand *stand) const;
    bool isValid() const { return filter_type!=ftInvalid;}
    QString dump() const;
private:
    enum { ftInvalid, ftExpression, ftJavascript} filter_type;
    Expression *expr;
    QJSValue func;
};

class Constraints {
public:
    Constraints() {}
    void setup(QJSValue &js_value); ///< setup from javascript
    double evaluate(FMStand *stand); ///< run the constraints
    QStringList dump(); ///< prints some debug info
private:
    QList<DynamicExpression> mConstraints;
};

class Activity; //forward
/** Activity meta data (enabled, active, ...) that need to be stored
    per stand. */

class ActivityFlags
{
public:
    ActivityFlags(): mActivity(0), mFlags(0) {}
    ActivityFlags(Activity *act): mActivity(act), mFlags(0) {}
    Activity *activity() const {return mActivity; }

    bool active() const {return flag(Active); }
    bool enabled() const {return flag(Enabled);}
    bool isRepeating() const {return flag(Repeater);}
    bool isPending() const {return flag(Pending); }
    bool isForcedNext() const {return flag(ExecuteNext); }
    bool isFinalHarvest() const {return flag(FinalHarvest); }
    bool isExecuteImmediate() const {return flag(ExecuteImmediate); }
    bool isScheduled() const {return flag(IsScheduled);}
    bool isDoSimulate() const {return flag(DoSimulate);}
    bool isSalvage() const {return flag(IsSalvage);}


    void setActive(const bool active) { setFlag(Active, active); }
    void setEnabled(const bool enabled) { setFlag(Enabled, enabled); }
    void setIsRepeating(const bool repeat) { setFlag(Repeater, repeat); }
    void setIsPending(const bool pending) { setFlag(Pending, pending); }
    void setForceNext(const bool isnext) { setFlag(ExecuteNext, isnext); }
    void setFinalHarvest(const bool isfinal) { setFlag(FinalHarvest, isfinal); }
    void setExecuteImmediate(const bool doexec) { setFlag(ExecuteImmediate, doexec);}
    void setIsScheduled(const bool doschedule) {setFlag(IsScheduled, doschedule); }
    void setDoSimulate(const bool dosimulate) {setFlag(DoSimulate, dosimulate); }
    void setIsSalvage(const bool issalvage) {setFlag(IsSalvage, issalvage); }

private:
    /// (binary coded)  flags
    enum Flags { Active=1,  // if false, the activity has already been executed
                 Enabled=2,  // if false, the activity can not be executed
                 Repeater=4, // if true, the activity is executed
                 ExecuteNext=8, // this activity should be executed next (kind of "goto"
                 ExecuteImmediate=16, // should be executed immediately by the scheduler (e.g. required sanitary cuttings)
                 Pending=32,  // the activity is currently in the scheduling algorithm
                 FinalHarvest=64,  // the management of the activity is a "endnutzung" (compared to "vornutzung")
                 IsScheduled=128, // the execution time of the activity is scheduled by the Scheduler component
                 DoSimulate=256,  // the default operation mode of harvests (simulate or not)
                 IsSalvage=512   // the activity is triggered by tree mortality events
                 };
    bool flag(const ActivityFlags::Flags flag) const { return mFlags & flag; }
    void setFlag(const ActivityFlags::Flags flag, const bool value) { if (value) mFlags |= flag; else mFlags &= (flag ^ 0xffffff );}
    Activity *mActivity; ///< link to activity
    int mFlags;
};



/// Activity is the base class for management activities
class Activity
{
public:
    // life cycle
    Activity(const FMSTP *parent);
    virtual ~Activity();
    /// Activity factory - create activities for given 'type'
    static Activity *createActivity(const QString &type, FMSTP *stp);

    // properties
    enum Phase { Invalid, Tending, Thinning, Regeneration, All };
    const FMSTP *program() const { return mProgram; }
    virtual QString type() const;
    QString name() const {return mName; } ///< name of the activity as provided by JS
    int index() const { return mIndex; } ///< index of the activity within the STP
    /// get earlist possible scheduled year (relative to rotation begin)
    int earlistSchedule(const double U=100.) const {return mSchedule.minValue(U); }
    /// get latest possible scheduled year (relative to rotation begin)
    int latestSchedule(const double U=100.) const { return mSchedule.maxValue(U); }
    /// get optimal scheduled year (relative to rotation begin)
    int optimalSchedule(const double U=100.) const { return mSchedule.optimalValue(U); }
    bool isRepeatingActivity() const { return mSchedule.repeat; }
    // main actions
    /// setup of the activity (events, schedule, constraints). additional setup in derived classes.
    virtual void setup(QJSValue value);
    /// returns a value > 0 if the activity coult be scheduled now
    virtual double scheduleProbability(FMStand *stand, const int specific_year=-1);
    /// returns a probability for the activity to be executed (ie all constraints are fulfilled)
    /// return value is 0 if the activity can not be executed (maximum result is 1)
    virtual double execeuteProbability(FMStand *stand);
    /// executes the action (usually defined in derived classes) using the context of 'stand'.
    virtual bool execute(FMStand *stand);
    /// executes the evaluation of the forest stand.
    /// returns true, when the stand should enter the scheduler.
    virtual bool evaluate(FMStand *stand);
    /// function that evaluates "bound" dynamic expressions
    virtual void evaluateDyanamicExpressions(FMStand *stand);
    /// dumps some information for debugging
    virtual QStringList info();
protected:
    Schedule &schedule()  { return mSchedule; }
    Constraints &constraints()  { return mConstraints; }
    Events &events()  { return mEvents; }
    ActivityFlags &standFlags(FMStand *stand=0);
    ActivityFlags mBaseActivity; // base properties of the activity (that can be changed for each stand)
    static QStringList mAllowedProperties; // list of properties (e.g. 'schedule') that are parsed by the base activity
private:
    void setIndex(const int index) { mIndex = index; } // used during setup
    void setName(const QString &name) { mName = name; }
    int mIndex; ///< index of the activity within the STP
    QString mName; ///< the name of the activity;
    const FMSTP *mProgram; // link to the management programme the activity is part of
    Schedule mSchedule; // timing of activity
    Constraints mConstraints; // constraining factors
    Events mEvents; // action handlers such as "onExecute"
    DynamicExpression mEnabledIf; // enabledIf property (dynamically evaluated)
    friend class FMSTP; // allow access of STP class to internals
    friend class FMStand; // allow access of the activity class (e.g for events)
    friend class ActivityObj; // allow access to scripting function
};

} // namespace

Q_DECLARE_TYPEINFO(ABE::ActivityFlags, Q_PRIMITIVE_TYPE); // declare as POD structure to allow more efficient copying

#endif // ACTIVITY_H