function [gene_data,...
discret_data,...
bound_data,...
ode_data,...
phys_data,...
fish] = bht_translation(filename)
% BHT_TRANSLATION
%
% Turn the data of the DAT-File into MATLAB structure array variables.
%
% Syntax
%
% [gene_data,discret_data,bound_data,ode_data,phys_data,fish] =
% BHT_TRANSLATION(filename)
%
% Description
%
% The function is ran by BHT_DATA_COMPILE. It reads the DAT-File
% filename, extracts the data and sets up fields of the output
% structure array variables gene_data,discret_data, bound_data,
% ode_data, phys_data and fish after prealocating them. Not all of the
% fields of these variables are set up by BHT_TRANSLATION. Actually,
% this function does not perform any computation. Computations on data
% (center of mass, boundaries' mesh...) are done by the functions
% BHT_BOUNDARIES_INIT and BHT_SOLIDS_DATA_INIT also ran by
% BHT_DATA_COMPILE.
%
% Output variables
%
% The following fields are set up by BHT_TRANSLATION (we refer to the
% List of output variables for a description).
%
% * Field(s) of gene_data: pb_type, collisions, alpha, epsilon,
% array_fishes_solids, base_filename
% * Field(s) of discret_data: mesh_size
% * Field(s) of bound_data: mfilename, settings, color
% * Field(s) of ode_data: Tmax, dT, initial_positions,
% initial_velocities
% * Field(s) of phys_data: rhof, rhos
% * Field(s) of fish: father, label, body, density, hinge_coord,
% local_hinge, color
%
% See also BHT_DATA_COMPILE, BHT_BOUNDARIES_INIT, BHT_SOLIDS_DATA_INIT,
% BHT_G_KINEMATICS, BHT_G_CONTROLS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% BIOHYDRODYNAMICS MATLAB TOOLBOX %
% %
% A. MUNNIER and B. PINCON %
% %
% alexandre.munnier@iecn.u-nancy.fr bruno.pincon@iecn.u-nancy.fr %
% http://www.iecn.u-nancy.fr/~munnier http://www.iecn.u-nancy.fr/~pincon %
% %
% INSTITUT ELIE CARTAN, NANCY 1 %
% http://www.iecn.u-nancy.fr/ %
% %
% INRIA Lorraine, Projet CORIDA %
% http://www.iecn.u-nancy.fr/~corida/ %
% %
% %
% %
% August 15th 2008 %
% %
% GNU GPL v3 licence %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%##########################################################################
% Set default values. These values will replaced missing optional values
default_meshsize = 0.1;
default_fluid_density = 1;
default_collisions = 0;
default_color = [0.9 0.9 1];
default_colormap = 'autumn';
default_pb_type = 0;
%-------------------------------------
if default_pb_type == 0
default_pb_type_name = 'exterior';
else
default_pb_type_name = 'interior';
end
%-------------------------------------
if default_collisions == 0
default_collisions_name = 'not allowed';
else
default_collisions_name = 'allowed';
end
%##########################################################################
% PREALLOCATION OF VARIABLES
%---------------------------
gene_data = struct('base_filename',' ',...
'pb_type',[],...
'collisions',[],...
'alpha',[],...
'epsilon',[],...
'nb_fishes',[],...
'nb_solids',[],...
'array_fishes_solids',[],...
'nb_boundaries',[]);
bound_data = struct('mfilename',{},...
'settings',{},...
'nbr_modes',{},...
'nbr_points',{},...
't',{},...
'dt',{},...
'X',{},...
'dl',{},...
'Nn',{},...
'N',{},...
'K',{},...
'flux',{},...
'fflux',{},...
'color',{});
ode_data = struct('Tmax',[],...
'dT',[],...
'initial_positions',[],...
'initial_velocities',[]);
phys_data = struct('rhof',[],...
'rhos',[],...
'Ms',[],...
'solids_area',[],...
'fishes_mass',[]);
discret_data = struct('mesh_size',[],...
'last_line',[]);
%-------------------------------------------
% 'solide' is a local struct array variable.
solide = struct('label',{},...
'father',{},...
'num_father',{},...
'mfilename',{},...
'settings',{},...
'hinge_coord',{},...
'local_hinge',{},...
'density',{},...
'color',{});
%##########################################################################
% DATA READING
%--------------------------------------------------------------------------
% Read data from the data file and compil its in a large string 'bigstr'
%--------------------------------------------------------------------------
bigstr = textread(filename, '%s', 'whitespace', '');
bigstr = bigstr{1};
%##########################################################################
% DATA EXTRACTION
%--------------------------------------------------------------------------
% Data extraction from the big string 'bigstr' and storage into output
% variables
%
%==========================================================================
% Extraction of 'mesh_size'
%--------------------------
mesh_size = regexpi(bigstr,'mesh\s*size\s*=\s*(\S*)', 'tokens');
if isempty(mesh_size)
warning('FluidStruct:Meshmiss',['mesh size is missing.\n',...
'Variable automatically set to mesh_size = ',...
num2str(default_meshsize)]);
mesh_size = default_meshsize;
else
mesh_size = str2num(mesh_size{1}{1}); %#ok<ST2NM>
disp(['mesh_size = ',num2str(mesh_size)]);
end
%++++++++++++++++++++++++++++++++++
discret_data.mesh_size = mesh_size;
%++++++++++++++++++++++++++++++++++
%==========================================================================
% Extraction of fluid's density
%------------------------------
fluid_density = regexpi(bigstr,'fluid\s*density\s*=\s*(\S*)',...
'tokens');
if isempty(fluid_density)
fluid_density = 1;
warning('FluidStruct:densityMiss',['Fluid density is missing.\n ',...
'Variable automatically set to fluid_density = ',...
num2str(default_fluid_density)]);
else
fluid_density = str2num(fluid_density{1}{1}); %#ok<ST2NM>
disp(['fluid_density = ',num2str(fluid_density)]);
end
%++++++++++++++++++++++++++++++
phys_data.rhof = fluid_density;
%++++++++++++++++++++++++++++++
%==========================================================================
% Extraction of fluid's boundaries' data (boundaries not shared with solids)
% and creation of the struct array local variable 'boundaries_ext'
%----------------------------------------------------------------
tok = regexpi(bigstr,'boundary\s*=\s*{(.*?)}', 'tokens');
nb_bound_ext = numel(tok);
disp(['Number of exterior boundaries found : ',num2str(nb_bound_ext)]);
%----------------------------------------------------------
%Prealocation of struct array local variable 'boundary_ext'
%----------------------------------------------------------
boundaries_ext = struct('mfilename',{},...
'settings',{},...
'color',{});
%==========================================================================
% Loop on boundaries not shared with solids
%==========================================================================
for k = 1:nb_bound_ext
% =====================================================================
% Extraction of boundary's file name
%-----------------------------------
rien = regexpi(tok{k}{1},'mfilename\s*=\s*(\w*)\s*','tokens');
if isempty(rien)
error(['Filename for exterior boundary ',num2str(k),...
' is missing. Add a field ''mfilename = ...'' to DAT-Filename.']);
end
%++++++++++++++++++++++++++++++++++++++++
boundaries_ext(k).mfilename = rien{1}{1};
%++++++++++++++++++++++++++++++++++++++++
% ====================================================================
% Extraction of boudary's settings
%-----------------------------------
rien = regexpi(tok{k}{1},'settings\s*=\s*\[(.*?)\]\s*','tokens');
if ~isempty(rien)
boundaries_ext(k).settings = str2num(rien{1}{1}); %#ok<ST2NM>
else
boundaries_ext(k).settings = [];
end
% ====================================================================
% Extraction of boudary fill color
%---------------------------------
rien = regexpi(tok{k}{1},'color\s*=\s*\[(.*?)\]\s*','tokens');
if ~isempty(rien)
boundaries_ext(k).color = str2num(rien{1}{1}); %#ok<ST2NM>
else
boundaries_ext(k).color = default_color;
end
end
%==========================================================================
% Extraction of pb type (0 = exterior, 1 = interior)
%---------------------------------------------------
pb_type = regexpi(bigstr,'problem\s*type\s*=\s*(\d)', 'tokens');
if isempty(pb_type)
warning('FluidStruct:PbTypMiss',['Problem type (exterior/interior) is missing.\n ',...
'Variable automatically set to pb_type = ',num2str(default_pb_type),...
'(',default_pb_type_name,').']);
pb_type = default_pb_type;
elseif strcmpi(pb_type{1}{1},'exterior') || strcmpi(pb_type{1}{1},'ext')
pb_type = 0;
disp('Problem type : exterior');
else
pb_type = 1;
disp('Problem type : interior');
end
%++++++++++++++++++++++++++++
gene_data.pb_type = pb_type;
%++++++++++++++++++++++++++++
%==========================================================================
% Extraction of 'collisions' (=1 if collisions are allowed =0 otherwise)
%-----------------------------------------------------------------------
collisions = regexpi(bigstr,'collisions\s*=\s*(\w*)\s', 'tokens');
if isempty(collisions)
warning('FluidStruct:CollMiss',['Whether collisions are allowed or not, not specified.\n ',...
'Variable automatically set to collisions = ',num2str(default_collisions),' (', ...
default_collisions_name,').']);
collisions = default_collisions;
else
collisions = collisions{1}{1};
collisions = (strcmpi(collisions,'yes') | strcmpi(collisions,'y'));
if collisions
collisions_name = 'allowed';
else
collisions_name = 'not allowed';
end
disp(['Collisions = ',num2str(collisions),' (',collisions_name,')']);
end
%++++++++++++++++++++++++++++++++++
gene_data.collisions = collisions;
%++++++++++++++++++++++++++++++++++
% =========================================================================
% Extraction of collisions' parameters (only when collisions are allowed)
%------------------------------------------------------------------------
if collisions
epsilon = regexpi(bigstr,'epsilon\s*=\s*(\S*)', 'tokens');
alpha = regexpi(bigstr,'alpha\s*=\s*(\S*)', 'tokens');
if isempty(epsilon) || isempty(alpha)
error(['Collisions allowed but parameter epsilon or/and alpha is missing.',...
'Add a field ''epsilon = ...'' or/and ''alpha = ...'' to DAT-File.'])
else
epsilon = str2num(epsilon{1}{1}); %#ok<ST2NM>
alpha = str2num(alpha{1}{1}); %#ok<ST2NM>
if isempty(epsilon) || isempty(alpha) || isnan(epsilon) || isnan(alpha)
error(['Collisions allowed but parameter epsilon or/and alpha is missing.',...
'Add a field ''epsilon = ...'' or/and ''alpha = ...'' to DAT-File.'])
end
%++++++++++++++++++++++++++++
gene_data.alpha = alpha;
gene_data.epsilon = epsilon;
%++++++++++++++++++++++++++++
end
end
%==========================================================================
% Extraction of simulation's time
%--------------------------------
Tmax = regexpi(bigstr,'max\s*time\s*=\s*(\S*)', 'tokens');
if isempty(Tmax)
error('Simulation time is missing. Add a field ''max time ='' to DAT-File.')
end
Tmax = str2num(Tmax{1}{1}); %#ok<ST2NM>
%++++++++++++++++++++++
ode_data.Tmax = Tmax;
%++++++++++++++++++++++
disp(['Simulation''s time = ',num2str(Tmax)]);
%==========================================================================
% Extraction of time step
%------------------------
dT = regexpi(bigstr,'time\s*step\s*=\s*(\S*)', 'tokens');
if isempty(dT)
error('Time step is missing. Add a field ''time step = ...'' to DAT-File.')
end
dT = str2num(dT{1}{1}); %#ok<ST2NM>
%++++++++++++++++++
ode_data.dT = dT;
%++++++++++++++++++
disp(['Time step = ',num2str(dT)]);
%==========================================================================
% Extraction of fishes's data
%==========================================================================
% Preallocation of variables
%---------------------------
%++++++++++++++++++++++++++++++++
ode_data.initial_positions = [];
ode_data.initial_velocities = [];
%++++++++++++++++++++++++++++++++
%==========================================================================
% Extraction of fishes's data and storage into a cell array variable 'tok'
%-------------------------------------------------------------------------
tok = regexp(bigstr,'fish\s*=\s*{(.*?})\s*}', 'tokens');
nb_fish = numel(tok);
if nb_fish == 0
error('No fish neither solid found. Add a field ''fish = {...}'' to DAT-File.')
end
%++++++++++++++++++++++++++++++
gene_data.nb_fishes = nb_fish;
%++++++++++++++++++++++++++++++
disp(['Number of fish(es) found : ',num2str(nb_fish)]);
%==========================================================================
% Preallocation of output cell array variable 'fish' and local cell array
% variable 'fish_colormap'
%-------------------------
fish = cell(1,nb_fish);
fish_colormap = cell(1,nb_fish);
%==========================================================================
% Main loop (on fishes)
%==========================================================================
for i = 1:nb_fish
%======================================================================
% extraction of data of the ith fish
%======================================================================
%======================================================================
% Extraction of initial position
%-------------------------------
rien = regexpi(tok{i}{1},'initial\s*position\s*=\s*\[(.*?)\]','tokens');
if isempty(rien)
error(['Initial position of fish or solid ',num2str(i),...
' is missing. Add a field ''initial position = ...'' to DAT-File.']);
end
rien = str2num(rien{1}{1}); %#ok<ST2NM>
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ode_data.initial_positions = vertcat(ode_data.initial_positions,...
reshape(rien,3,1));
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%======================================================================
% Extraction of initial velocity
%-------------------------------
rien = regexpi(tok{i}{1},'initial\s*velocity\s*=\s*\[(.*?)\]','tokens');
if isempty(rien)
error(['Initial velocity of fish or solid ',num2str(i),...
' is missing. Add a field ''initial velocity = ...'' to DAT-File.']);
end
rien = str2num(rien{1}{1}); %#ok<ST2NM>
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ode_data.initial_velocities = vertcat(ode_data.initial_velocities,...
reshape(rien,3,1));
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%======================================================================
% Extraction of the number of links in the ith fish
%--------------------------------------------------
stok = regexp(tok{i}{1},'link\s*=\s*{(.*?)}', 'tokens');
nb_solids = numel(stok);
if nb_solids == 0
error(['Fish ',num2str(i),' is empty (no solid found). Add a field ''link = ...'' to DAT-File.'])
end
%+++++++++++++++++++++++++++++++++++++++++++
gene_data.array_fishes_solids(i) = nb_solids;
%+++++++++++++++++++++++++++++++++++++++++++
%======================================================================
% Extraction of the colormap for the ith fish
%--------------------------------------------
rien = regexpi(tok{i}{1},'colormap\s*=\s*(\w*)\s*','tokens');
fish_colormap{i} = feval(default_colormap,nb_solids+1);
if ~isempty(rien)
fish_colormap{i} = feval(rien{1}{1},nb_solids+1);
end
%======================================================================
% Internal loop (on solids composing the ith fish)
%======================================================================
for k = 1:nb_solids
solid = stok{k}{1};
% =================================================================
% Extraction of label
%--------------------
rien = regexpi(solid,'label\s*=\s*([a-zA-Z]\w*)','tokens');
if isempty(rien)
error(['One solid in fish ',num2str(i),' has no label.',...
' Add a field ''label = ...'' to DAT-File.']);
end
%+++++++++++++++++++++++++++
solide(k).label = rien{1}{1};
%+++++++++++++++++++++++++++
% =================================================================
% Extraction of father's label (label of the link the current
% solid is attached to)
%----------------------
rien = regexpi(solid,'father\s*=\s*(\w*)','tokens');
if ~isempty(rien)
solide(k).father = rien{1}{1};
end
% =================================================================
% Extraction of the file name for the function that parameterize
% the solid
%--------------------
rien = regexpi(solid,'mfilename\s*=\s*(\w*)','tokens');
if isempty(rien)
error(['One solid in fish ',num2str(i),' has no M-File name specified.',...
'Add a field ''mfilename = ...'' to DAT-File.']);
end
%+++++++++++++++++++++++++++
solide(k).mfilename = rien{1}{1};
%+++++++++++++++++++++++++++
% =================================================================
% Extraction of boundary's settings
%------------------------------------------------------------
rien = regexpi(solid,'settings\s*=\s*\[(.*?)\]','tokens');
if ~isempty(rien)
%++++++++++++++++++++++++++++++++++++++++++
solide(k).settings = str2num(rien{1}{1}); %#ok<ST2NM>
%++++++++++++++++++++++++++++++++++++++++++
else
%+++++++++++++++++++++++++
solide(k).settings = [];
%+++++++++++++++++++++++++
end
% =================================================================
% Extraction of the solid's density
%----------------------------------
rien = regexpi(solid,'density\s*=\s*(\d*(?:\.?\d*))','tokens');
if isempty(rien)
warning('FluidStruct:SolidDensityMiss',['One solid in fish ',...
num2str(i),' has no density specified.\n ',...
'Density automaticaly set to fluid density (= ',...
num2str(fluid_density),').']);
%+++++++++++++++++++++++++++++++++
solide(k).density = fluid_density;
%+++++++++++++++++++++++++++++++++
else
%+++++++++++++++++++++++++++++++++++++++
solide(k).density = str2num(rien{1}{1}); %#ok<ST2NM>
%+++++++++++++++++++++++++++++++++++++++
end
% =================================================================
% Extraction of the hinge coordinates (in the father's frame)
%------------------------------------------------------------
rien = regexpi(solid,'hinge\s*coord\s*=\s*\[(.*?)\]','tokens');
if ~isempty(rien)
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++
solide(k).hinge_coord = reshape(str2num(rien{1}{1}),2,1); %#ok<ST2NM>
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++
end
% =================================================================
% Extraction of the hinge coordinates (in the current solid's
% frame)
%----------
rien = regexpi(solid,'hinge\s*local\s*coord\s*=\s*\[(.*?)\]','tokens');
if ~isempty(rien)
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++
solide(k).local_hinge = reshape(str2num(rien{1}{1}),2,1); %#ok<ST2NM>
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++
end
% =================================================================
% Extraction of the solid's color (RGB formalism)
%------------------------------------------------
rien = regexpi(solid,'color\s*=\s*\[(.*?)\]','tokens');
if ~isempty(rien)
%++++++++++++++++++++++++++++++++++++++++++++++++++
solide(k).color = reshape(str2num(rien{1}{1}),1,3); %#ok<ST2NM>
%++++++++++++++++++++++++++++++++++++++++++++++++++
else
%++++++++++++++++++++
solide(k).color = [];
%++++++++++++++++++++
end
end
%======================================================================
% Storage into the output cell array variable 'fish'
%---------------------------------------------------
%++++++++++++++++
fish{i} = solide;
%++++++++++++++++
end
%##########################################################################
% Data postprocessing
%--------------------------------------------------------------------------
% Checking if solids in the same fish have distinct names
%--------------------------------------------------------
for j = 1:nb_fish
SA = fish{j};
nb_solids = numel(SA);
if nb_solids > 1
for k = 1:nb_solids-1;
for p = k+1:nb_solids;
if strcmpi(SA(k).label,SA(p).label)
error(['Two or more solids have the same label in fish ',...
num2double(j)]);
end
end
end
end
end
%==========================================================================
% Changing solids's order ; placing solid 'father' before its children ;
% Giving each solid a number and the corresponding father's number
%-----------------------------------------------------------------
for j = 1:nb_fish
SA = fish{j};
nb_solids = numel(SA);
for k = 1:nb_solids
for p = 1:nb_solids
if strcmpi(SA(k).label,SA(p).father)
fils = SA(p);
father = SA(k);
SA(min([k,p])) = father;
SA(max([k,p])) = fils;
%++++++++++++++++++++++++++++++++++++++
SA(max([k,p])).num_father = min([k,p]);
%++++++++++++++++++++++++++++++++++++++
end
if strcmpi(SA(p).label,SA(k).father)
fils = SA(k);
father = SA(p);
SA(min([k,p])) = father;
SA(max([k,p])) = fils;
%++++++++++++++++++++++++++++++++++++++
SA(max([k,p])).num_father = min([k,p]);
%++++++++++++++++++++++++++++++++++++++
end
end
end
%++++++++++++
fish{j} = SA;
%++++++++++++
end
%==========================================================================
% Collecting of all the boundaries's filename, settings, density and
% color in the struct array 'boundaries'
%--------------------------------------------------------------------------
% Processing first the solids
%----------------------------
iter = 0;
for j = 1:nb_fish
SA = fish{j};
nb_solids = numel(SA);
for k = 1:nb_solids
iter = iter + 1;
%++++++++++++++++++++++++++++++++++++++++++++++
bound_data(iter).mfilename = SA(k).mfilename;
bound_data(iter).settings = SA(k).settings;
%++++++++++++++++++++++++++++++++++++++++++++++
if ~isempty(SA(k).color)
%++++++++++++++++++++++++++++++++++++
bound_data(iter).color = SA(k).color;
%++++++++++++++++++++++++++++++++++++
else
%++++++++++++++++++++++++++++++++++++++++++++++
bound_data(iter).color = fish_colormap{j}(k,:);
%++++++++++++++++++++++++++++++++++++++++++++++
end
%++++++++++++++++++++++++++++++++++++
phys_data.rhos(iter) = SA(k).density;
%++++++++++++++++++++++++++++++++++++
end
end
%-----------------
% number of solids
%+++++++++++++++++++++++++++
gene_data.nb_solids = iter;
%+++++++++++++++++++++++++++
disp(['Total number of solids: ',num2str(iter)]);
%--------------------------------------------------------------------------
% Processing now the boundaries not shared with solids
%-----------------------------------------------------
if nb_bound_ext > 0
for k = 1:nb_bound_ext;
iter = iter + 1;
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
bound_data(iter).mfilename = boundaries_ext(k).mfilename;
bound_data(iter).settings = boundaries_ext(k).settings;
bound_data(iter).color = boundaries_ext(k).color;
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
end
end
%+++++++++++++++++++++++++++++++
gene_data.nb_boundaries = iter;
%+++++++++++++++++++++++++++++++
disp(['Total number of boundaries: ',num2str(iter)]);
%==========================================================================
% Checking if each solid (but the first one) has a father
%---------------------------------------------------------
for j = 1:nb_fish
SA = fish{j};
nb_solids = numel(SA);
if nb_solids > 1
for k = nb_solids:-1:2
test_father = 0;
for p = 1:k-1
test_father = test_father + strcmpi(SA(k).father,SA(p).label);
end
if ~test_father
error(['One solid has no father in fish ',num2str(j)])
end
end
end
end
%==========================================================================
% Checking if each solid (but the first one) has hinges
%------------------------------------------------------
for j = 1:nb_fish
SA = fish{j};
nb_solids = numel(SA);
if nb_solids > 1
for k = 2:nb_solids
if isempty(SA(k).hinge_coord) || isempty(SA(k).local_hinge)
error(['One solid in fish ',num2str(j),...
' has no hinge coordinates specified. Add a field ''hinge coord = ...'' to DAT-File']);
end
end
end
end
%##########################################################################
% Saving data
%------------
base_filename = regexp(filename,'(\w*).\w*', 'tokens');
base_filename = base_filename{1}{1};
%++++++++++++++++++++++++++++++++++++++++
gene_data.base_filename = base_filename;
%++++++++++++++++++++++++++++++++++++++++
end