Visage_data is a complex object that is capable of dealing with time varying data. It is possible to assign a reader object to the data that will read in data at requested time values. In addition, the data object can cache data to reduce disk I/O. In particular, the netCDF reader is capable of handling time varying data.
Other reader objects are possible as well, but require that the proper message passing protocol is followed. The reader must be able to respond to these messages:
time= set the time of the reader,
next_time? what is the next time value for the data,
time_steps? return all time steps available for the data,
read_data: given the time of the data, the name of the data requesting the read, and an alias for the data object (i.e., the name of the object in the file), read the data.
The data object completes the interaction by responding with the "allocate:" and "data?" messages, as described below.
time the current time for the data, between start_time and end_time.
start_time the starting time for the data. Only data greater than the start time and less than the end time (inclusive) will be processed.
end_time the ending time for the data. Only data greater than the start time and less than the end time (inclusive) will be processed.
reader the name of a reader object to obtain data.
interpolate flag to indicate whether interpolation of data is required. For example, when data is available at time=1.0 and time=2.0, if time=1.0 the tick! method will move to time=2.0 if interpolation is off (=0.0), or to time=(1.0 + 1/resolution) if interpolation is on.
time_variant flag to indicate whether the data is a function of time. By default, time_variant=0 (i.e., data is not a funtion of time).
resolution value indicating the resolution of the clock when tick! messages are received. If interpolate is on, then tick! messages cause the time to be incremented by 1/resolution.
data pointer value to current data at specified time.
size size of the data currently allocated.
cache_size value indicating the number of data steps to cache. That is, if cache_size > 1, then as the data receives tick! messages, it will store up to cache_size data pointers (rather than freeing and rereading the data).
cycle boolean that controls the behavior of the tick! message. If cycle=1, then when a tick! is received by the data, and the data is at its end time, it will move the time to the start time (i.e., the data will cycle). If cycle=0, the data will stay at the end time.
time? Get the current time.
start_time= value Set the start time to the specified value. If start_time > end_time, it will be set to the end time. If time < start_time, it will be set to the start time.
start_time? Get the current start time.
end_time= value Set the end time to the specified value. If end_time < start_time, it will be set to the start time. If time > end_time, it will be set to the end time.
end_time? Get the current end time.
tick! Cause the time to increment. If interpolation is on, the time increments by 1/resolution. If interpolation is off, the time moves to the time of the next avalable data.
no_steps? Get the total number of data steps available.
reader= reader_name Set the name of the data reader object. This object must be capable of the appropriate protocol as described earlier.
reader? Get the name of the reader object.
interpolate= value Set the interpolate to value. If =0, interpolate is off. If !=0, interpolate is on.
interpolate_on! Turn on data interpolation.
interpolate_off! Turn off data interpolation, i.e., use only data at time steps provided.
interpolate? Get the value of the interpolate flag.
time_variant= value Set the value of the time_variant instance variable to value. If =0, the data is time invariant. If !=0, the data is time variant.
time_variant_on! Set the data time variant.
time_variant_off!, time_invariant! Set the data to be time invariant.
time_variant? Get the value of the time variant flag.
resolution= value Set the resolution of the clock to the value given. When the object receives tick! messages, and interpolation is on, the clock will be incremented by 1/resolution.
resolution? Get the current clock resolution.
cycle= value Set the value of the cycle flag. value. If =0, cycling is off. If !=0, cycling is on.
cycle_on! Turn on data cycling.
cycle_off! Turn off data cycling.
cycle? Get the value of the cycle flag.
size? Get the current allocated size of the data.
cache_size= value Set the number of data steps to cache. Setting the cache_size > 1 for time varying data reduces I/O, especially if the data is being animated through time. Normally, cache_size=1, and the data is read every time.
cache_size? Get the size of the data cache.
data? Get the pointer to the data at the current time. Used only by class developers.
data=, data+ (d1,d2,...) Set/add data values. This method provides a script interface for creating data. It is the users responsibility to load in the data correctly - this depends upon the particulars of the data.
allocate: size Allocate data of length size. The actual data allocated is sizeof(float)*size.
release! Release the data (including any cached data) without destroying the object. Useful for conserving system memory.
free! Delete the object and free any memory allocated by the object.
alias= name set the name of the data object in a data file.
alias? get the name of the data object in a data file.
In the first example, a structured grid and associated data is created.
/* * Create structured grid */ structured_grid_set new: grid dimensions= (2,3,4); grid data=(0., 0., 0., 1., 0., 0., 0., 1., 0., 1., 1., 0., 0., 2., 0., 1., 2., 0.) data+(0., 0., 1., 1., 0., 1., 0., 1., 1., 1., 1., 1., 0., 2., 1., 1., 2., 1.) data+(0., 0., 2., 1., 0., 2., 0., 1., 2., 1., 1., 2., 0., 2., 2., 1., 2., 2.) data+(0., 0., 3., 1., 0., 3., 0., 1., 3., 1., 1., 3., 0., 2., 3., 1., 2., 3.) ; /* * Vector data */ visage_vector new: velocity; velocity data= (0., 0., 0., 1., 0., 0., 0., 2., 0., 0., 0., 3.) data+ (1., 0., 0., 1., 0., 0., 0., 2., 0., 0., 0., 3.) data+ (2., 0., 0., 1., 0., 0., 0., 2., 0., 0., 0., 3.) data+ (2., 0., 0., 1., 0., 0., 0., 2., 0., 0., 0., 3.) data+ (2., 0., 0., 1., 0., 0., 0., 2., 0., 0., 0., 3.) data+ (3., 0., 0., 1., 0., 0., 0., 2., 0., 0., 0., 3.) ; /* * Scalar data */ visage_scalar new: pressure; pressure data=(0., 0., 0., 1., 0., 0., 0., 2., 0., 0., 0., 3.) data+ (1., 1., 1., 2., 1., 1., 3., 2., 1., 1., 1., 3.)
; /* * Create a data set. Here the display classes are used. */ visage_data_set new: adata_set geometry= grid scalar_data= pressure vector_data= velocity ; /* * Now create a visual image */ /* * Create an outline */ display_outline new: an_outline data_in= adata_set generate_data! ; display_lines new: draw_outline data_in= an_outline ; actor new: outline_actor modeller=draw_outline ; /* * Create a geometry */ display_geometry new: a_geometry extent=(1,1,1,3,1,4) data_in= adata_set ; display_surface new: draw_surface data_in= a_geometry ; actor new: geometry_actor modeller=draw_surface ; /* * Create an iso-surface */ display_iso_surface new: iso value=2.0 data_in= adata_set ; display_surface new: draw_iso data_in= iso ; actor new: iso_actor modeller=draw_iso ; /* * Set up lights and stuff */
collection new: mydata members=([visage_data instances?]) compute_properties! ; vector new: bbox dimension=6; bbox = ([grid bbox?]); camera new: acamera position= (1,1,1) focal_point= ([grid center?]) x_range=([bbox @1 ?],[bbox @2 ?]) y_range=([bbox @3 ?],[bbox @4 ?]) z_range=([bbox @5 ?],[bbox @6 ?]) default! zoom: 1.4 on! ; light new: alight position= ([acamera position?]) on! ; /* * Create renderer. The environment variable LYMB_RENDERER should be * set appropriately (e.g., vogle_x11, starbase, phigs, etc.) */ logic new: _test; environment new: _env variable="LYMB_RENDERER"; _test = [_env defined?] false: "#Environment variable LYMB_RENDERER must be set." false: "parser exit!;" ; string new: current_renderer = [_env value?];
object# current_renderer new: main_renderer actors=([actor instances?]) lights=alight cameras=acamera ; /* * Draw the picture */ main_renderer render!;
In the second example, a netCDF reader is used to read transient data. The data of interest is a unstructured grid (time invariant) with data (time variant). The script animates the pressure data on a geometry.
/* * read in the data. Only want unstructured grid data */ cdf_reader new: areader file_prefix="test" selection="unstructured_grid"
read! ;
collection new: set_data members=([visage_data instances?]); set_data compute_properties!;
/* * set up some displays */ visage_outline new: outline;
visage_vector_field new: vec_fld extent=(1,2,1,3,1,4);
visage_geometry new: p1 extent=(1,2,1,3,1,1);
visage_cut_plane new: cp point=(.5,1,1) normal=(1,1,1);
visage_iso_surface new: is1 value=1.5;
test_set01 displays=(p1);
actor new: a color=(1,1,1) modeller=test;
camera new: c1 x_range=(0,1) y_range=(0.,2) z_range=(0.,3.) position=(1,1,1) default! on!;
light new: l1 position=(30,30,50) on!;
environment new: env variable="LYMB_RENDERER";
object # [env value?] new: aren actors=a lights=l1 cameras=c1;
scounter := scalar {=1.0}; pcounter := scalar {=1.0};
/* * Animate pressure data on displays */ scalar new: t0 = [object# [pressure reader?] start_time?] - 1; pressure start_time=t0;
pressure end_time=[object# [pressure reader?] end_time?]; pressure time=t0; cue new: ani_data resolution=1 duration=[pressure no_steps?] time=t0 tick_actions="pressure tick! modified!; pressure print:time;" end_actions="ani_data time=t0; pressure time=[pressure start_time?]; ani_data duration=[pressure no_steps?];" ; /* * Some other convenient cues */ cue new: move_x_plane resolution=1 duration=4 tick_actions="p1 extent=(1,2,1,3,pcounter,pcounter); pcounter + 1;" end_actions="move_x_plane time=-1; pcounter = 1;";
cue new: rotate resolution=1 duration=360 tick_actions="a rotate_x:1;" end_actions="rotate time=0;";
cue new: azimuth resolution=1 duration=360 tick_actions="c1 azimuth:5;";
scene new: ascene duration=1000 renderers=aren cues=(ani_data) start_actions="scounter = 1; pcounter = 1;";