Driver class
Contents
Description
This is a handle super-class for the definition of an analysis driver.
An analysis driver is the core of the simulation, being responsible to perform the time steps of the different types of analysis, and also the pre and pos processing tasks.
This super-class defines abstract methods that must be implemented in the derived sub-classes:
classdef Driver < handle
Constant values
properties (Constant = true, Access = public)
% Types of analysis
MECHANICAL = uint8(1);
THERMAL = uint8(2);
THERMO_MECHANICAL = uint8(3);
end
Public properties
properties (SetAccess = public, GetAccess = public)
% Problem data
name string = string.empty; % simulation name
type uint8 = uint8.empty; % flag for type of analysis
path_in string = string.empty; % path to input files folder
% Model components: handle to objects
mparts ModelPart = ModelPart.empty; % handles to objects of ModelPart class
particles Particle = Particle.empty; % handles to objects of Particle class
walls Wall = Wall.empty; % handles to objects of Wall class
interacts Interact = Interact.empty; % handles to objects of Interact class
solids Material = Material.empty; % handles to objects of Material_Solid subclass
fluid Material = Material.empty; % handles to object of Material_Fluid subclass
% Model components: total numbers
n_mparts uint32 = uint32.empty; % number of model parts
n_particles uint32 = uint32.empty; % number of particles
n_walls uint32 = uint32.empty; % number of walls
n_interacts uint32 = uint32.empty; % number of binary interactions
n_solids uint32 = uint32.empty; % number of solid materials
% Global properties
gravity double = double.empty; % vector of gravity components value
damp_trl double = double.empty; % damping for translational motion
damp_rot double = double.empty; % damping for rotational motion
fluid_vel double = double.empty; % interstitial fluid velocity vector
fluid_temp double = double.empty; % interstitial fluid temperature
% Model domain properties
alpha double = double.empty; % alpha radius
vol_domain double = double.empty; % total volume (unity depth) of the alpha-shape polygon of all particles
porosity double = double.empty; % average porosity (void ratio) of the alpha-shape polygon
por_freq double = double.empty; % average porosity update frequency (in steps) (double to accept NaN)
vor_freq double = double.empty; % voronoi diagram update frequency (in steps) (double to accept NaN)
vor_vtx double = double.empty; % vertices coordinates of voronoi diagram
vor_idx cell = cell.empty; % vertices indices of voronoi diagram cells
% Total particle properties
surf_particle double = double.empty; % total surface area of all particles
cross_particle double = double.empty; % total cross-sectional area of all particles
vol_particle double = double.empty; % total volume of all particles
mass_particle double = double.empty; % total mass of all particles
% Model limits
has_bbox logical = logical.empty; % flag for existing bbox
has_sink logical = logical.empty; % flag for existing sinks
bbox BBox = BBox.empty; % handle to object of BBox class
sink Sink = Sink.empty; % handles to objects of Sink class
% Paralelization
parallel logical = logical.empty; % flag for parallelization of simulation
workers uint16 = uint16.empty; % number of workers for parallelization
% Neighbours search
search Search = Search.empty; % handle to object of Search class
% Time integration
scheme_trl Scheme = Scheme.empty; % handle to object of Scheme class for translation integration
scheme_rot Scheme = Scheme.empty; % handle to object of Scheme class for rotation integration
scheme_temp Scheme = Scheme.empty; % handle to object of Scheme class for temperature integration
% Time advancing
auto_step logical = logical.empty; % flag for computing time step automatically
time_step double = double.empty; % time step value
max_time double = double.empty; % maximum simulation time
time double = double.empty; % current simulation time
step double = double.empty; % current simulation step (double to perform NaN operations in frequency checks)
% Elapsed time control (real analysis time)
start_time double = double.empty; % starting elapsed time for current analysis run
total_time double = double.empty; % total elapsed time for all analysis runs
% Output generation
path_out string = string.empty; % path to output folder
save_ws logical = logical.empty; % flag for saving workspace into a storage file
result Result = Result.empty; % handle to object of Result class
animations Animation = Animation.empty; % handles to objects of Animation class
graphs Graph = Graph.empty; % handles to objects of Graph class
print Print = Print.empty; % handle to object of Print class
% Output control
nprog double = double.empty; % progress print frequency (% of total time)
tprog double = double.empty; % next time for printing progress
nout double = double.empty; % number of outputs
tout double = double.empty; % next time for storing results
store logical = logical.empty; % flag for step to store results
end
Constructor method
methods
function this = Driver(type)
if (nargin > 0)
this.type = type;
end
end
end
Abstract methods: implemented in derived sub-classes
methods (Abstract)
%------------------------------------------------------------------
setDefaultProps(this);
%------------------------------------------------------------------
setParticleProps(this,particle);
%------------------------------------------------------------------
preProcess(this);
%------------------------------------------------------------------
process(this);
end
Public methods
methods
%------------------------------------------------------------------
function initTime(this)
this.start_time = 0;
this.time = 0;
this.step = 0;
end
%------------------------------------------------------------------
function initOutputVars(this)
this.nprog = this.nprog * this.max_time / 100; % convert to time per print
this.nout = this.max_time / this.nout; % convert to time per output
this.tprog = this.nprog;
this.tout = this.nout;
end
%------------------------------------------------------------------
function printProgress(this)
if (this.time >= this.tprog)
fprintf('\n%.1f%%: time %.3f, step %d',100*this.time/this.max_time,this.time,this.step);
this.tprog = this.tprog + this.nprog - 10e-15; % tollerance to deal with precision issues
end
end
%------------------------------------------------------------------
% Object must be called 'drv' here to load it from storage file.
function storeResults(drv)
if (drv.time >= drv.tout)
if (drv.save_ws)
drv.createOutFolder();
save(strcat(drv.path_out,drv.name));
drv.total_time = drv.start_time + toc;
end
if (~isempty(drv.print))
drv.print.execute(drv);
end
drv.tout = drv.tout + drv.nout - 10e-10; % tollerance to deal with precision issues
drv.result.updateIndex();
drv.store = true;
else
drv.store = false;
end
end
%------------------------------------------------------------------
function storeResultsFinal(this)
if (this.result.idx < length(this.result.times))
this.result.updateIndex();
this.result.storeTime(this);
this.result.storeAvgVelocity(this);
this.result.storeExtVelocity(this);
this.result.storeAvgAcceleration(this);
this.result.storeExtAcceleration(this);
this.result.storeAvgTemperature(this);
this.result.storeExtTemperature(this);
this.result.storeTotalHeatRate(this);
for i = 1:this.n_particles
p = this.particles(i);
this.result.storeParticleProp(p);
this.result.storeParticlePosition(p);
this.result.storeParticleTemperature(p);
this.result.storeParticleForce(p);
this.result.storeParticleVelocity(p);
this.result.storeParticleAcceleration(p);
this.result.storeParticleHeatRate(p);
end
for i = 1:this.n_walls
w = this.walls(i);
this.result.storeWallPosition(w);
this.result.storeWallTemperature(w);
end
if (~isempty(this.print))
this.print.execute(this);
end
end
end
%------------------------------------------------------------------
function setVoronoiDiagram(this)
% Assumption: walls are ignored
try
[this.vor_vtx,this.vor_idx] = voronoiDiagram(delaunayTriangulation([this.particles.coord]'));
catch
fprintf(2,'Could not build Voronoi diagram in step %d\n',this.step);
end
end
%------------------------------------------------------------------
function setGlobalVol(this)
% Assumption: in-plane projection area (unity depth)
vol = area(alphaShape([this.particles.coord]',this.alpha));
% Avoid null volume (aligned particles)
% Assumption: set total particle volume (area) when volume is null
if (vol ~= 0)
this.vol_domain = vol;
else
if (isempty(this.cross_particle))
this.cross_particle = sum([this.particles.cross]);
end
this.vol_domain = this.cross_particle;
end
end
%------------------------------------------------------------------
function setGlobalPorosity(this)
if (isempty(this.vol_domain))
this.setGlobalVol();
else
% Assumption: total volume of particles computed as the
% in-plane cross-sectional area (unity depth)
this.porosity = 1 - this.cross_particle/this.vol_domain;
end
end
%------------------------------------------------------------------
function setTotalParticlesProps(this)
this.surf_particle = sum([this.particles.surface]);
this.cross_particle = sum([this.particles.cross]);
this.vol_particle = sum([this.particles.volume]);
this.mass_particle = sum([this.particles.mass]);
end
%------------------------------------------------------------------
function do = removeParticle(this,p)
do = false;
% Remove particles not respecting bbox
if (this.has_bbox)
if (this.bbox.removeParticle(p,this.time))
do = true;
% Remove particle and its interactions
delete(p.interacts);
delete(p);
% Erase handles from global list of interactions
this.interacts(~isvalid(this.interacts)) = [];
this.n_interacts = length(this.interacts);
return;
end
end
% Remove particles not respecting sinks
if (this.has_sink)
for i = 1:length(this.sink)
if (this.sink(i).removeParticle(p,this.time))
do = true;
% Remove particle and its interactions
delete(p.interacts);
delete(p);
% Erase handles from global list of interactions
this.interacts(~isvalid(this.interacts)) = [];
this.n_interacts = length(this.interacts);
return;
end
end
end
end
%------------------------------------------------------------------
function erasePropsOfRemovedParticle(this)
% Erase handles from global list
this.particles(~isvalid(this.particles)) = [];
this.n_particles = length(this.particles);
% Erase handles from model parts
for i = 1:this.n_mparts
mp = this.mparts(i);
mp.particles(~isvalid(mp.particles)) = [];
mp.n_particles = length(mp.particles);
end
% Update total particles properties
this.setTotalParticlesProps();
% Attention:
% To avoid additional computational costs, references to the
% deleted particle from other particles (e.g. neighbohring
% lists) are not removed.
end
%------------------------------------------------------------------
function createOutFolder(this)
if (~exist(this.path_out,'dir') ~= 7) % 7 = ID for folders
warning off MATLAB:MKDIR:DirectoryExists
mkdir(this.path_out)
warning on MATLAB:MKDIR:DirectoryExists
end
end
%------------------------------------------------------------------
function posProcess(this)
if (isnan(this.result.times(1)))
fprintf('\nNo valid results to show.\n');
return;
end
% Create and write graphs
if (~isempty(this.graphs))
fprintf('\nCreating graphs...\n');
for i = 1:length(this.graphs)
this.graphs(i).execute(this);
end
end
% Create and show animations
if (~isempty(this.animations))
for i = 1:length(this.animations)
fprintf('\nCreating animation "%s"...',this.animations(i).anim_title);
this.animations(i).animate(this);
end
fprintf('\n');
for i = 1:length(this.animations)
this.animations(i).showAnimation();
end
fprintf('\n');
end
end
end
end