Info

This question is closed. Reopen it to edit or answer.

Design of tool for visual exploration

1 view (last 30 days)
per isakson
per isakson on 19 Sep 2012
Closed: MATLAB Answer Bot on 20 Aug 2021
Questions
  1. I assume that there is no way to let an assignment, a=qty;, where qty is an instance of a value class, call some user code. (Something like subsref.) Am I correct?
  2. A value class to represent a time series will provide better perfomance and a more robust code than would a handle class. Am I correct?
  3. The design I outline below, does it look sound?
Background
Energy efficient operation of buildings. The building automation system, BAS, provides plenty of time series data: temperatures, power, control signals, etc. Building simulation programs provides similar time series. A building can deliver approximately 1GB per year of data - more in the future.
Some ten year ago I settled on a Matlab structure that contains several hundreds of the time series together with some metadata. Over the years I built a number of visual tools that use my data structure. These tools are used by experts in building operation. The full focus of the user shall be on the behavior of the building. Simple interface and fast response are both important. The tools have been surprisingly well received.
There is a shortcoming that is severe especially when exploring simulation results. Now, in a first step I compile one data structure and in a second step I do the visual exploration. What happens is that when studying a certain behavior in one building I want to compare to the behavior of a different building or simulation and that data are not in the current structure - that irks.
My goal is to make a visual tool, which provides an immense of time series data at the finger tips of the user.
So far
I have concluded based on tests that
  1. it is possible to read data from files on-the-fly and still deliver acceptable response times. A home-brewed system based on fwrite/fread+memmapfile(?), matfile, high level HDF5 and low level NetCDF4 are all possible alternatives. (Soon enough we will have fast solid-state-disks.)
  2. I shall trust Windows' file-cache and Matlabs copy-on-write (/lazy-copy).
  3. I shall try to limit Matlabs memory foot-print. The file cache makes good use of memory.
It is highly possible that several tools simultaneously use a certain time series. In this case it is crucial that there is only one copy of the underlying numerical array in Matlabs memory. Thus, each tool must not retrieve the data from the data file. When all tools have cleared their references to the time series it shall be cleared from the Matlab memory.
Deep under the hood Matlab has information on how variables refer to numerical arrays, but I use plain documented Matlab.
Now I'm experimenting with a little system to study allocation and release of memory. It consists of
  1. SharedQty - A singleton handle class, which keeps a register of QtyX instances in use.
  2. QtyX - A time series value class. Creation of QtyX instancies should only be done by SharedQty
  3. PhysicalMemoryInUse - function
  4. pass_QtyX_as_argument - function
I have ran several scripts like the one below to see how memory is allocated and released. So far it seems to work as expected.
mem(1) = PhysicalMemoryInUse();
q11 = SharedQty.getQty( 'Qty1001' ); % memory allocated
mem(2) = PhysicalMemoryInUse();
q21 = SharedQty.getQty( 'Qty1002' ); % memory allocated
mem(3) = PhysicalMemoryInUse();
mem(4) = pass_QtyX_as_argument( q11 );
mem(5) = pass_QtyX_as_argument( q21 );
q12 = copy( q11 );
mem(6) = PhysicalMemoryInUse();
q22 = copy( q21 );
mem(7) = PhysicalMemoryInUse();
clear( 'q12' )
mem(8) = PhysicalMemoryInUse();
clear( 'q22' )
mem(9) = PhysicalMemoryInUse();
clear( 'q11' ) % memory released
mem(10) = PhysicalMemoryInUse();
clear( 'q21' ) % memory released
mem(11) = PhysicalMemoryInUse();
.
--- listings ---
classdef ( Sealed ) SharedQty < handle
% Singleton pattern
properties ( Access = private )
next_id = 1;
QtyBuffer
end
methods ( Access = private )
function this = SharedQty()
end
end
methods ( Static = true, Access = public )
function id = unique_id()
this = SharedQty.Instance;
id = this.next_id;
this.next_id = this.next_id + 1;
end
function qty = getQty( name )
this = SharedQty.Instance;
if not( isempty( this.QtyBuffer ) )
[ ism, ixm ] = ismember( name, { this.QtyBuffer.DataName } );
else
ism = false;
end
if ism
qty = copy( this.QtyBuffer(ixm).Object );
else
qty = QtyX( name );
end
end
function register( qty )
this = SharedQty.Instance;
% The property, Cleanup, of the instance of QtyX, which is kept in
% SharedQty, shall not have a value. The property itself cannot be
% removed
qty.Cleanup = [];
if not( isempty( this.QtyBuffer ) )
[ ism, ixm ] = ismember( qty.DataName, {this.QtyBuffer.DataName} );
if ism
this.QtyBuffer(ixm).ID_list ...
= [ this.QtyBuffer(ixm).ID_list, qty.ID ];
else
this.QtyBuffer(end+1).ID_list = qty.ID;
this.QtyBuffer(end ).DataName = qty.DataName;
this.QtyBuffer(end ).Object = qty;
end
else
this.QtyBuffer.ID_list = qty.ID;
this.QtyBuffer.DataName = qty.DataName;
this.QtyBuffer.Object = qty;
end
end
function deregister( id, name )
this = SharedQty.Instance;
[ ism, loc ] = ismember( name, { this.QtyBuffer.DataName } );
if ism && sum(loc)==1
this.QtyBuffer(ism).ID_list ...
= setdiff( this.QtyBuffer(ism).ID_list, id );
if isempty( this.QtyBuffer( ism ).ID_list )
this.QtyBuffer( ism ) = [];
end
end
end
end
methods ( Static = true, Access = public )
function this = Instance()
persistent instance
if isempty( instance ) || not( isvalid( instance ) )
instance = SharedQty;
end
this = instance;
end
end
end
.
classdef QtyX
properties
val
Cleanup
ID
DataName
end
properties ( Constant = true )
Length = 1e8;
end
methods
function this = QtyX( name )
this.val = ones( this.Length, 1 ); % mimics file data
this.ID = SharedQty.unique_id;
this.DataName = name;
SharedQty.register( this );
this.Cleanup = onCleanup ...
( @() SharedQty.deregister( this.ID, this.DataName ) );
end
function qty = copy( this )
qty = this;
qty.ID = SharedQty.unique_id;
qty.Cleanup = onCleanup ...
( @() SharedQty.deregister( qty.ID, qty.DataName ) );
end
function qty = set_unique_ID( qty )
qty.ID = SharedQty.unique_id;
qty.Cleanup = onCleanup ...
( @() SharedQty.deregister( qty.ID, qty.DataName ) );
end
end
end
.
function mem = PhysicalMemoryInUse()
pause( 0.5 )
[ ~, system_view ] = memory;
mem = system_view.PhysicalMemory.Total ...
- system_view.PhysicalMemory.Available ;
end
.
function mem = pass_QtyX_as_argument( qty )
qty = set_unique_ID( qty );
mem = PhysicalMemoryInUse();
variable_not_used( qty )
end

Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!