Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: add iterative solve choices/matrix analysis #17

Open
wants to merge 9 commits into
base: reference
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions analyze_matrix.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
function analyze_matrix(A)

fprintf('\n\nbegin matrix analysis\n');

% these tests disabled - they are slow, and none of the problem
% matrices tested are symmetric or positive definite

% 1: test for symmetry
is_sym = isequal(A,A');

if is_sym
fprintf("--symmetric--\n");
else
fprintf("--nonsymmetric--\n");
end


[~,flag] = chol(A, 'lower');

if flag == 0
fprintf("--symmetric positive definite--\n");
else
fprintf("--not symmetric positive definite--\n");
end


% 3: spectrum
[eigenvectors, eigenvalue_mat] = eig(A);
eigenvalues = diag(eigenvalue_mat);
figure
plot(eigenvalues,'o','MarkerSize',12);
saveas(gcf,'spectrum.png');


% 4: condition number of eigenvect mat
fprintf('eigen condition number: %d\n', cond(eigenvectors));

% 5: condition number of matrix
fprintf('matrix condition number: %d\n', cond(A));

% 6: sparsity %
fprintf('matrix density: %f\n', nnz(A)/numel(A));

% 7: sparsity pattern
spy(A);

fprintf('end matrix analysis\n\n');

end
1 change: 1 addition & 0 deletions apply_A.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
if opts.implicit
A = zeros(totalDOF,totalDOF); % Only filled if implicit
end
ALHS = 0;
if num_terms_LHS > 0
ALHS = zeros(totalDOF,totalDOF); % Only filled if non-identity LHS mass matrix
end
Expand Down
6 changes: 2 additions & 4 deletions asgard.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@
runtime_defaults

%% Reset any persistent variables
if opts.time_independent_A
clear time_advance
end

clear time_advance
figure(1000);
%% Check PDE
pde = check_pde(pde,opts);

Expand Down
68 changes: 68 additions & 0 deletions iterative_solve.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
function [x, iter, relres, relres_hist] = iterative_solve(pde, opts, A, b, tol, max_iter, restart, graph_residual, precond)
%iterative solve driver

% set options
if ~exist('restart','var')
restart = [];
else
if strcmpi(opts.solve_choice, 'BICGSTAB')
disp('non-restarting method')
end
end

if ~exist('tol','var') || isempty(tol)
tol = 1e-6; % matlab default
end

if ~exist('max_iter', 'var') || isempty(max_iter)
max_iter = size(A, 1);
end

% set up preconditioner
if strcmpi(opts.preconditioner, 'JACOBI') %point jacobi
M = diag(diag(A));
elseif strcmpi(opts.preconditioner, 'BLK_JACOBI') % block jacobi
blk_n = pde.deg^size(pde.dimensions,1);
nblks = size(A,1) / blk_n;
kron_map = kron(eye(nblks), ones(blk_n, blk_n));
blk_list = A(kron_map ~= 0);
blocks = reshape(blk_list,blk_n,blk_n,size(A,1)/blk_n);
M = num2cell(blocks, [1,2]);
M = reshape(M, 1, size(M, 3));
M = blkdiag(M{:});
elseif strcmpi(opts.preconditioner, 'CUSTOM')
if ~exist('precond', 'var')
error('selected custom preconditioning, did not supply one');
end
M = precond; %custom preconditioner
else
M = [];
end

% do solve
tic;
if strcmpi(opts.solve_choice, 'GMRES')
[x,flag, relres, iter, relres_hist] = gmres(A, b, restart, tol, max_iter, M);
if flag == 0; fprintf('GMRES converged w iters\n'); disp(iter);
else; fprintf('GMRES failed with flag %d\n', flag); end
elseif strcmpi(opts.solve_choice, 'BICGSTAB')
[x,flag, relres, iter, relres_hist] = bicgstab(A, b, tol, max_iter, M);
if flag == 0; fprintf('BIGCGSTAB converged w iters\n'); disp(iter);
else; fprintf('BICGSTAB failed with flag %d\n', flag); end
else
error('solver choice not recongized!');
end
disp(['solve duration: ', num2str(toc), 's']);


% graph performance
if graph_residual
figure(2000);
semilogy(1:size(relres_hist,1),relres_hist/norm(b),'-o');
xlabel('Iteration number');
ylabel('Relative residual');

end

end

18 changes: 18 additions & 0 deletions runtime_defaults.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
default_adapt_threshold = 1e-1;
default_refinement_method = 1;
default_adapt_initial_condition = false;
default_solve_choice = 'DIRECT';
valid_solve_choices = {'DIRECT', 'GMRES', 'BICGSTAB'};
check_solve_choice = @(x) any(validatestring(x,valid_solve_choices));
default_do_analysis = false;
default_preconditioner_choice = 'JACOBI';
valid_preconditioner_choices = {'JACOBI', 'BLK_JACOBI', 'CUSTOM', 'NONE'};
check_preconditioner_choice = @(x) any(validatestring(x,valid_preconditioner_choices));


addRequired(input_parser, 'pde', @isstruct);
addParameter(input_parser,'lev',default_lev, @isnumeric);
Expand All @@ -46,6 +54,9 @@
addOptional(input_parser,'adapt_threshold',default_adapt_threshold, @isnumeric);
addOptional(input_parser,'refinement_method',default_refinement_method, @isnumeric);
addOptional(input_parser,'adapt_initial_condition',default_adapt_initial_condition,@islogical);
addOptional(input_parser,'analyze_matrix',default_do_analysis, @islogical);
addOptional(input_parser,'solve_choice',default_solve_choice, check_solve_choice);
addOptional(input_parser,'preconditioner',default_preconditioner_choice, check_preconditioner_choice);

if numel(varargin) == 0 && ~exist('pde','var')

Expand Down Expand Up @@ -135,6 +146,13 @@
opts.adapt_threshold = input_parser.Results.adapt_threshold;
opts.refinement_method = input_parser.Results.refinement_method;
opts.adapt_initial_condition = input_parser.Results.adapt_initial_condition;
opts.analyze_matrix = input_parser.Results.analyze_matrix;
opts.solve_choice = input_parser.Results.solve_choice;
opts.preconditioner = input_parser.Results.preconditioner;

if opts.analyze_matrix && ~opts.implicit
error('cannot analyze matrix if not build for implicit stepping');
end

if opts.adapt
opts.use_oldhash = false;
Expand Down
27 changes: 26 additions & 1 deletion time_advance.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
%% Backward Euler (first order implicit time advance)

function f1 = backward_euler(pde,opts,A_data,f0,t,dt,deg,hash_table,Vmax,Emax)
persistent analysis_done;
if isempty(analysis_done)
analysis_done = false;
end

s0 = source_vector(pde,opts,hash_table,t+dt);
bc0 = boundary_condition_vector(pde,opts,hash_table,t+dt);
Expand All @@ -104,15 +108,31 @@
b = f0 + dt*(s0 + bc0);
end

if opts.analyze_matrix && ~analysis_done
analyze_matrix(AA);
analysis_done = true;
end


if strcmpi(opts.solve_choice, 'DIRECT')
f1 = AA\b; % Solve at each timestep
else
restart = 200;
graph_residual=true;
f1 = iterative_solve(pde, opts, AA, b, [], [], restart, graph_residual);
end

f1 = AA\b; % Solve at each timestep

end


%% Crank Nicolson (second order implicit time advance)

function f1 = crank_nicolson(pde,opts,A_data,f0,t,dt,deg,hash_table,Vmax,Emax)
persistent analysis_done;
if isempty(analysis_done)
analysis_done = false;
end

s0 = source_vector(pde,opts,hash_table,t);
s1 = source_vector(pde,opts,hash_table,t+dt);
Expand Down Expand Up @@ -151,6 +171,11 @@

if ~opts.quiet; disp([' rcond(AA) : ', num2str(rcond(AA))]); end

if opts.analyze_matrix && ~analysis_done
analyze_matrix(AA);
analysis_done = true;
end

AA_inv = inv(AA);

% f1 = AA\b; % Solve at each timestep
Expand Down