================================================= Commit Notes: Series Slots with Periodic Input Phil Weinstein -- Edit: 8-15-2012 ================================================= Series Slots with Periodic Input / Major Checkin Bug Number: n/a Release notes (y/n): n For Release Nums: 6.3 See Development Note Webpages: http://cadswes2.colorado.edu/~philw/2012/SeriesSlotPeriodicInputs/ ********************************************* *** CHANGE OUTLINE -- See DETAILS Below *** ********************************************* (1) SeriesSlots conditionally support a child "Periodic Input" Periodic Slot for providing Input values to the series. This is supported through virtual methods in the Slot class. This Periodic Slot defers to the SeriesSlot for display attributes, including user units. (2) The Open Slot Dialog for "Series Slots with Periodic Input" presents radio buttons for switching between two "Input Modes" (Series and Periodic). In Periodic Input Mode, the periodic slot is shown as a right-side panel. The Periodic Input data is directly editable. Changes to that data result in an "immediate" recomputation of the series data (slightly delayed for performance, using a QTimer). (3) "Series Slots with Periodic Input" are demonstrated with the "Pan Evaporation" Series Slots on three object types. They can also be created by the user on data objects. (4) Period/Interval configuration of the Periodic Input slot is accessed via a new "Configure Period" menu item under the View menu. (5) Some important optimizations have been implemented and tested with SeriesSlots having 20,000 timesteps. (6) When in Periodic Input Mode, importing and exporting (only) to/from the Periodic Slot is supported. When in Series Mode, those operations are supported on the Series Slot (as usual). (7) Input DMI operation to the "Series Slots with Periodic Input" which is in Periodic Input Mode should generate an error. The DMI code can use this Slot class predicate function to detect this invalid condition: bool dmiImportDisallowedForPeriodicInputMode() const; ************************ *** CHANGE DETAILS *** ************************ ---------------------------- EngrObjs/GroundWaterStor.cpp EngrObjs/Reach.cpp EngrObjs/Reservoir.cpp ---------------------------- The "panEvaporation" Series Slots on the following objects have been promoted to "Series Slots with Periodic Input" using this SeriesSlotProxy method: // slot specialization panEvaporation.setSupportPeriodicInput_setSeriesMode(); This demonstrates one of the three new SeriesSlotProxy methods which support this new functionality. See below. ----------------------- Q3GUI/OpenObjectDlg.hpp Q3GUI/OpenObjectDlg.cpp ----------------------- "Series Slots with Periodic Input" can be added to Data Objects. An "Add Series Slot with Periodic Input" item has been added to the "Add Slot" menu. QAction* _addAltInpSerSlotAction; void addAltInpSeriesSlot(); ------------ Sim/Slot.hpp Sim/Slot.cpp ------------ The slot class now provides a public interface for a Slot's "Alternate Input Mode" which implements the "with Periodic Input" feature for SeriesSlots. (See also SeriesSlot). Major new definitions and public methods: typedef enum { AltInpMode_Series = 0, AltInpMode_Periodic } AltInpMode; // For SeriesSlots using child Alternate Input Slots virtual bool altInpModeEna() const { return (false); } virtual AltInpMode altInpMode() const { return (AltInpMode_Series); } virtual PeriodicSlot* altInpPeriodicSlot() const { return (NULL); } Slot class predicate for preventing DMI Input operations from importing series data into "Series Slots with Periodic Input" when those slots are in "Periodic Input" mode: bool dmiImportDisallowedForPeriodicInputMode() const; ------------------------- Sim/SeriesSlot.hpp Sim/SeriesSlot.cpp Sim/SeriesSlot.AltInp.cpp -- NEW FILE ------------------------- Virtual methods declared in the Slot base class are defined in SeriesSlot to support "Series Slots with Periodic Input" as an "Alternate Input Mode". New data members: bool _altInpModeEna; AltInpMode _altInpMode; PeriodicSlot* _altInpPeriodicSlot; // ownership New methods: virtual bool altInpModeEna() const { return _altInpModeEna; } virtual AltInpMode altInpMode() const { return _altInpMode; } virtual PeriodicSlot* altInpPeriodicSlot() const { return _altInpPeriodicSlot; } void setAltInpModeEna (bool); void setAltInpMode (AltInpMode); void dropAltModeSlots(); Performance Fix in SeriesSlot::setValues (double* newValues ..) When called with 'changeSize' passed in as false, issue only a "value changed" callback instead of "series changed". The latter causes full recomputations of the layout of slot display tables. If only values are changed within the currently layed out timestep cells, a basic data update is much quicker. This is relevant for the computation of series values from a periodic slot. Additional functionality in SeriesSlot::dumpEnt (cwostream&): If "Alternate Input Mode" is enabled on the slot, a PeriodicInputChildSlot line (Tcl command) is generated identifying the slot as having Periodic Input and indicating the current "Input Mode": Series or Periodic. The full Periodic Slot is dumped ONLY IF the slot is active in Periodic Input Mode or if the Periodic Slot contains at least one defined (non-NaN) value. See handling of the PeriodicInputChildSlot command in Tcl function: seriesSlotCmd(). ------------------------ Sim/SeriesStructImpl.cpp ------------------------ Adjustment to method: void SeriesStructImpl::setValues (SeriesSlot *slot, double *newValues, int num, bool changesize, double newScale, const QString& newUnits, ValueState state) const; .. This method is typically used with the ValueState of OUTPUT_VALUE_STATE. Now, when some other ValueState is specified, OUTPUT_VALUE_STATE is still assigned for invalid (NaN) values in the provided 'double' array. This method is called from SeriesSlot::setValues(). See discussion above. ----------------- Sim/SlotProxy.hpp Sim/SlotProxy.cpp ----------------- Methods were added to support the promotion of Series Slots to "Series Slots with Periodic Input". One of these is demonstrated with the "Pan Evaporation" Series Slot on three engineering objects. (See above). // enable alternate input mode; set periodic input mode. void setSupportPeriodicInput_setSeriesMode(); void setSupportPeriodicInput_setPeriodicMode(); void clearSupportPeriodicInput(); ... the first two methods enable "with Periodic Input". The first also puts the slot into "Series Mode". The second puts the slot into "Periodic Input Mode". Also, upgrade of 'typeBits' and 'attributeBits' from 16-bits (short) to 32-bits (int), as had recently been done in the Slot class. ----------------- Sim/TableSlot.hpp Sim/TableSlot.cpp ----------------- Periodic Input (Periodic Slots) use the display attributes of their client (parent) Series Slot with Periodic Input. In the following numeric display attribute (e.g. unit) accessors, if the slot is an Alternate Input (Child) Slot, pull the attribute value from the parent (client) slot. const NumDisplayAttribs& localNumDisplayAttribs_prim (int col) const; unit_type primUnitType (int col /*=0*/) const; double getUsrScale (int col) const; QString getUsrUnits (int col) const; unit_type getUnitType (int col) const; QString getUnitTypeStr (int col) const; QString getStdUnits (int col) const; ScaledUnitPtr getScaledUsrUnitPtr (int col) const; QString getUsrFormat (int col) const; char getUsrFormatChar (int col) const; int getUsrPrecision (int col) const; New utility method: bool TableSlot::anyValidValues() const; -------------------- Sim/PeriodicSlot.hpp Sim/PeriodicSlot.cpp -------------------- PeriodicSlots used for a SeriesSlot's "Periodic Input" maintain a pointer to that client slot. // Alternate Input Slot Mode Support SeriesSlot* _altInputClientSeriesSlot; // not ownership Change to numeric display attribute accessors to make use of the TableSlot base class methods with special support for Alternate Input (Child) Slot operation (deferring to the parent, client slot). ------------------- Q3GUI/SlotQtDlg.hpp Q3GUI/SlotQtDlg.cpp ------------------- Major functional enhancements for the support of Series Slots with Periodic Input: (1) The Open Series Slot Dialog now recognizes the Series Slot being in an "Alternate Input Mode" -- the only of which that is currently supported is "Periodic Input Mode". These data members provide convenient access to this state information: PeriodicSlot* _altInpPerSlot; // alternate input periodic slot bool _periodicInputMode; (2) In place of the slot data table, there are now two slot data tables arranged horizontally. The right-side table currently used only for the Periodic Input (Periodic Slot). This is NOT USED for most applications of the SlotQtDlg class. QFrame* _dataTableRegionPanel; QFrame* _dataTableRegionLeft; // for main data table QFrame* _dataTableRegionRight; // for new periodic input table SlotDataTableView* _slotDataTableView; // already existed SlotDataTableModel* _slotDataTableModel; // already existed SlotDataTableView* _periodicInputDataView; SlotDataTableModel* _periodicInputDataModel; Note: The '_dataTableRegionRight' also has these controls which are now only for testing. They are hidden except if the environment variable, RW_SHOW_PER_INPUT_CALC_CONTROLS is defined with a non-zero value. QPushButton* _periodicInputRecalcBut; // 'reload' icon button QCheckBox* _periodicInputAutoCalcCheck; // checkbox QPushButton* _periodicInputConfigBut; // 'gear' icon button (3) Management of Radio Buttons for the "Input Mode" (Series or Periodic) are now managed in place of the a conditionally shown text line above the data table (which is used for the "column map entity name" for periodic slots having a numeric column header). QFrame* _tableCaptionFrame; QLabel* _colMapEntityDispLabel; // existing QLabel* _inputModeTitleLabel; QRadioButton* _inputModeSeriesRadio; QRadioButton* _inputModePeriodicRadio; (4) Switching from Series Mode to Periodic Input Mode generally results in overwriting (recomputing) of the series values. The user is presented with a confirmation dialog box to confirm this switch UNLESS the current series values exactly equal those that would be computed from the Periodic Input OR unless the series values are all NaN. bool confirmSwitchToPeriodicInputMode (int& diffCnt, int& nonNanCnt); (5) The open slot dialog (the SlotQtDlg class) is responsible for causing the recomputation of series data when the Periodic Input (Slot) changes. This is reasonable because this is the only place where the Periodic Input data can be modified. (There may be some minor exceptions to this in the future, e.g. DMI Support for Periodic Input -- that would also have to cause this recomputation). For "Series Slots with Periodic Input" a distinct callback handler is used for callbacks issued for the Periodic Input Slot. MethodCb* _altInpPerSlotCallback; int altInpPerSlotCbHandler (CallbackType, CallbackData*, void*); Periodic Input (Slot) value changes schedule a series recomputation using the same QTimer which is used to defer refreshing the main data table. See this method: void schedServiceSlotDataChange (bool forPerInp); // or Main table? // see deferred processing in serviceSlotDataChange(). bool _serviceSlotDataChange_forMainTable; bool _serviceSlotDataChange_forPerInpTable; (6) The SlotQtDlg menu actions which acted on selections within the data table used to be connected directly to SlotDataTableModel Qt slots. Now, in order to support operating on either the main SlotDataTableModel or the new one for Periodic Input, those Qt slots (having the same names) are now in the SlotQtDlg class. These new slots then call the corresponding slot in the active SlotDataTableModel -- generally the one in which the user most recently "clicked". Accordingly, the enabledness of those actions is determined from the "active" slot data table (main or periodic input). // Active Table Selection bool _activeDataTableIsPerInp; // Period Inp data table active? SlotDataTableView* _activeDataTableView; // switched ref to instance SlotDataTableModel* _activeDataTableModel; // switched ref to instance // ... related methods and flags void notifySlotDataTableSelected (SlotDataTableView*); void setSelectedSlotDataTable (SlotDataTableView*); bool _setSelectedSlotDataTable_inProgress; (7) Series Slots with Periodic Input now have these three configuration menu item: (a) Configure... (b) Configure Period... <<< NEW (c) Time Series Range... The "Configure Period..." shows an very abbreviated version of the Periodic Slot configuration dialog supporting only these two properties: (1) Period definition (2) Interval definition (irregular, or one of several regular options) (3) Data Interpolation: Interpolate or Lookup "Configure Period" action and handler: QAction* _configInpPerAction; // _viewMenu void configInpPerHandler(); (8) The slot data Import/Export functions are supported a little differently than other operations which could apply to either the main (series) data table or the periodic input data table. Instead of applying to the most recently "clicked" table, they apply to the EDITABLE table, which is a function of the Input Mode (set by radio buttons). In Series Mode, only the main (series) data table is relevant (and only that table is shown). Import and Export operations apply to that series data. In Periodic Input Mode, Import and Export operations apply to the Periodic Input (Periodic Slot) data. To avoid confusion about this, these opeartions are enabled only when the Periodic Input table is selected. ---------------------------- Q3GUI/SlotDataTableModel.hpp Q3GUI/SlotDataTableModel.cpp Q3GUI/SlotDataTableView.hpp -- very minor changes Q3GUI/SlotDataTableView.cpp -- very minor changes ---------------------------- The slot data table implementation classes (Qt4 QAbstactTableModel and QTableView) now conditionally support special behavior for the Periodic Input data table, indicated with a 'forAltInpPer' (alternate input, periodic) flag passed to the constructors. Since the properties of the table are very limited when it is used for Periodic Input, it was possible to implement a much more precise automatic width adjustment for this table. This new method is part of this geometry support: int singleColTableSlotWidth (const TableSlot*) const; A SIGNIFICANT SPEED OPTIMIZATION was implemented which effects especially long series tables. The vertical (row) QHeaderView had been using the "ResizeToContents" resize mode. This caused VERY UNREASONABLE geometry computations to occur within Qt which were effectively (apparently) exponentially related to the number of rows in the table. (Note that row dividers are implemented as very-narrow rows). This problem was resolved by turning off that automatic computation (using the "Fixed" resize mode), and programmatically performing the row resize only when rebuilding the table. (Currently this is done also when changing and servicing the "series display compression" feature, but wit this new insight and fix, the option of hiding and showing rows, rather than reassigning rows, may be a superior approach to the implementation of "series display compression". See these two methods: void vertHeaderSetResizeMode (const QString& calledFrom); void resizeViewRowsToContents (const QString& calledFrom); Developed for testing, a "Fill from Periodic Slot" operation was implemented which allows the user to fill the table's series data (i.e. if it is displaying series data) from a Periodic Slot picked by the user, using GUS. Note that the entire series slot is effected -- not just the selected cells. The "Fill from Periodic Slot" operation is hidden in this checkin, but can be made visible (under the Interpolate and Adjust Values operations) by changing this definition in SlotQtDlg.cpp: static const bool SHOW_FILL_FROM_PERIODIC_SLOT_OP (false); // Support for "Fill from Periodic Slot" operation. RootSelection _periodicSlotRootSelection; void initPeriodicSlotRootSelection (bool fullInit, unit_type); void fillFromPeriodic_handler(); ----------------------------- Q3GUI/PeriodicSlotCfg.hpp Q3GUI/PeriodicSlotCfg.cpp Q3GUI/PeriodicSlotCfg.qt.inc Q3GUI/PeriodicSlotCfg.qt.cpp Q3GUI/PeriodicSlotCfgDlgState.hpp Q3GUI/PeriodicSlotCfgListener.hpp Q3GUI/PeriodicSlotCfgWidgets.ui QtUtils/SlotIdPanel.cpp ----------------------------- (1) Enhancement: Added the 'SlotIdPanel'. This general panel is present in all the other Slot Configuration Dialogs, but was strangely missing from the Periodic Slot Configuration dialog. Also, some minor cleanup. (2) SlotIdPanel: For the "Periodic Input" Periodic Slot of a "Series Slot with Periodic Input"), the client (parent) slot name is shown, plus "(Periodic Input)". -------------------- Sim/SlotGUIUtils.hpp Sim/SlotGUIUtils.cpp -------------------- New utilities: bool singleScaledUnit (const QList&); okstat fillFromPeriodicSlot (SeriesSlot* targ, const PeriodicSlot* src); int diffFromPeriodicSlot (const SeriesSlot* targ, const PeriodicSlot* src, int& nonNanCnt); Enhancement to method: bool SlotGUIUtils::dataEditable (const Slot*) (1) New condition: SeriesSlots with Alternate Input Enabled and not in Series Mode are not editable ("read-only"). (2) Minor scenario slot logic fix: unlikely to have been actual problem. ----------------------- Sim/IconHandle.hpp Sim/IconHandle.cpp QtUtils/RwQPixmap16.hpp QtUtils/RwQPixmap16.cpp ----------------------- New icon for "Series Slot with Periodic Input" IconHandle::IconID SlotIcon_altInpSeriesSlot static const QPixmap& RwQPixmap16::altInpSeriesSlot(); --- (end) ---