├── LICENSE ├── PeriFast_Corrosion ├── boundary_conditions.m ├── dump_output.m ├── dump_output_Tecplot.m ├── initial_conditions.m ├── initial_gpu_arrays.m ├── inputs.m ├── kernel_functions.m ├── main.m ├── mat2tecplot.m ├── nodes_and_sets.m ├── postprocess.m ├── update_C.m ├── update_VC.m └── visualization.m ├── PeriFast_Dynamics ├── close_Matlab_video.m ├── constitutive.m ├── create_Matlab_video.m ├── dump_output.m ├── initial_gpu_arrays.m ├── inputs.m ├── main.m ├── nodes_and_sets.m ├── open_Matlab_video.m ├── postprocess.m ├── pre_constitutive.m ├── update_VC.m ├── update_tractions.m └── visualization.m └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 PeriFast 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PeriFast_Corrosion/boundary_conditions.m: -------------------------------------------------------------------------------- 1 | % Boundary condition type and value 2 | % BC type: 1 is Dirichlet BC, 2 is Neuman BC 3 | BC1_type = 1; % on top surface with normal vector = [0,0,1] 4 | BC2_type = 1; % on bottom surface with normal vector = {0,0,-1} 5 | BC3_type = 1; % on the side surface with normal vector = {1,0,0} 6 | BC4_type = 1; % on the side surface with normal vector = {-1,0,0} 7 | BC5_type = 1; % on the side surface with normal vector = {0,1,0} 8 | BC6_type = 1; % on the side surface with normal vector = {0,-1,0} 9 | BC_type = [BC1_type,BC2_type,BC3_type,BC4_type,BC5_type,BC6_type]; 10 | 11 | BC1_value = 0; % on top surface with normal vector = [0,0,1] 12 | BC2_value = 0; % on bottom surface with normal vector = {0,0,-1} 13 | BC3_value = 0; % on the side surface with normal vector = {1,0,0} 14 | BC4_value = 0; % on the side surface with normal vector = {-1,0,0} 15 | BC5_value = 0; % on the side surface with normal vector = {0,1,0} 16 | BC6_value = 0; % on the side surface with normal vector = {0,-1,0} 17 | BC_value = [BC1_value,BC2_value,BC3_value,BC4_value,BC5_value,BC6_value]; 18 | 19 | % Apply nonlocal Boundary Conditions with fictitious nodes method: 20 | % Force all fictitious nodes outside physical domain has C=0 21 | C_w = zeros(Nx,Ny,Nz); 22 | % apply boundary condition on top surface with normal vector = [0,0,1] 23 | gBCa = (z_max - delta < Z & Z < z_max); 24 | n1 = find(gBCa(1,1,:)); 25 | 26 | % apply boundary condition on bottom surface with normal vector = [0,0,-1] 27 | gBCb = (z_min < Z & Z < z_min + delta + dz); 28 | n2 = find(gBCb(1,1,:)); 29 | 30 | % apply boundary condition on side surface with normal vector = [1,0,0] 31 | gBCc = (x_max - delta < X & X < x_max); 32 | n3 = find(gBCc(1,:,1)); 33 | 34 | % apply boundary condition on side surface with normal vector = [-1,0,0] 35 | gBCd = (x_min < X & X < x_min + delta + dx); 36 | n4 = find(gBCd(1,:,1)); 37 | 38 | % apply boundary condition on side surface with normal vector = [0,1,0] 39 | gBCe = (y_max - delta < Y & Y < y_max); 40 | n5 = find(gBCe(:,1,1)); 41 | 42 | % apply boundary condition on side surface with normal vector = [0,-1,0] 43 | gBCf = (y_min < Y & Y < y_min + delta + dy); 44 | n6 = find(gBCf(:,1,1)); 45 | 46 | boundary_condition_check(BC_type); 47 | C = chi.*C0 + (1 - chi).*C_w; 48 | function boundary_condition_check(BC_type) 49 | for i = 1:length(BC_type) 50 | if(BC_type(i) ~=1 && BC_type(i)~=2) 51 | error('The BC type no.%d is not supported',i); 52 | end 53 | end 54 | end -------------------------------------------------------------------------------- /PeriFast_Corrosion/dump_output.m: -------------------------------------------------------------------------------- 1 | function [Output,j] = dump_output(Output,j,C,chi_l,t,run_in_gpu) 2 | 3 | % user can add any desired quantity to the "Output" varibale 4 | if(run_in_gpu == 1) 5 | Output(j).C = gather(C); 6 | Output(j).chi_l = gather(chi_l); 7 | Output(j).t = t; 8 | else 9 | Output(j).C = C; 10 | Output(j).chi_l = chi_l; 11 | Output(j).t = t; 12 | end 13 | end -------------------------------------------------------------------------------- /PeriFast_Corrosion/dump_output_Tecplot.m: -------------------------------------------------------------------------------- 1 | function [tdata] = dump_output_Tecplot(tdata,X,Y,Z,C,run_in_gpu,tec_step) 2 | 3 | if(run_in_gpu == 1) 4 | tdata.cubes(tec_step).x=gather(X); 5 | tdata.cubes(tec_step).y=gather(Y); 6 | tdata.cubes(tec_step).z=gather(Z); 7 | tdata.cubes(tec_step).v(1,:,:,:)=gather(C); 8 | else 9 | tdata.cubes(tec_step).x=X; 10 | tdata.cubes(tec_step).y=Y; 11 | tdata.cubes(tec_step).z=Z; 12 | tdata.cubes(tec_step).v(1,:,:,:)=C; 13 | end 14 | end 15 | 16 | -------------------------------------------------------------------------------- /PeriFast_Corrosion/initial_conditions.m: -------------------------------------------------------------------------------- 1 | % Initial condition and mask functions 2 | % Discretized initial condition u(x,0): 3 | C0 = zeros(Nx,Ny,Nz); 4 | C0(chi_N == 1) = C_solid; %Big N concentration equal to C_solid 5 | 6 | % Generate initial spherical pits, only for pitting corrosion 7 | if(corrosion_type == 2) 8 | total_pits_no = 20; % total number of initial pits 9 | for i = 1:total_pits_no 10 | % randomly generate pits center coordinates, under uniform distribution 11 | pit_x = (-1+2*rand)*x_max; % x location from -75um to 75um 12 | pit_y = (-1+2*rand)*y_max; % y location from -60um to 60um 13 | pit_z = 18e-6 + 5e-6*rand; % z coordinate of pit center, from 18um to 23um 14 | % randomly generate pits radius, from 2 to 4 um, under uniform distribution 15 | pit_r = 2e-6 + rand*2e-6; %the initial pit radius, 2 to 4 um 16 | C0((X-pit_x).^2+(Y-pit_y).^2+(Z-pit_z).^2 <= pit_r^2) = 0.9*C_sat; %initialize the pits that filled with solution 17 | end 18 | C0(chi_N == 0) = 0; 19 | end 20 | 21 | % Construct Mask function (chi_l) for liquid domain: 22 | chi_l = zeros(Nx,Ny,Nz); 23 | chi_l_pit = zeros(Nx,Ny,Nz); 24 | chi_l (C0 < C_sat) = 1; %find liquid nodes 25 | chi_l_pit(chi_l==1 & chi_N==1) = 1; %find the liquid nodes inside pits 26 | % Construct Mask function for salt layer 27 | chi_salt = zeros(Nx,Ny,Nz); 28 | % Construct Mask function (chi_s) for solid domain 29 | chi_s = 1 - chi_l; 30 | -------------------------------------------------------------------------------- /PeriFast_Corrosion/initial_gpu_arrays.m: -------------------------------------------------------------------------------- 1 | delta = gpuArray(delta); 2 | X = gpuArray(X);Y = gpuArray(Y);Z = gpuArray(Z); 3 | Nx = gpuArray(Nx); Ny = gpuArray(Ny); Nz = gpuArray(Nz); 4 | Lx_T = gpuArray(Lx_T); Ly_T = gpuArray(Ly_T); Lz_T = gpuArray(Lz_T); 5 | 6 | muS_diff_hat = gpuArray(muS_diff_hat); muS_corr_hat = gpuArray(muS_corr_hat); 7 | 8 | n1 = gpuArray(n1); n2 = gpuArray(n2); n3 = gpuArray(n3); n4 = gpuArray(n4); 9 | n5 = gpuArray(n5); n6 = gpuArray(n6); 10 | BC_type = gpuArray(BC_type); BC_value = gpuArray(BC_value); 11 | 12 | C = gpuArray(C); C_w = gpuArray(C_w); 13 | chi = gpuArray(chi); chi_l = gpuArray(chi_l); chi_N = gpuArray(chi_N); 14 | chi_s = gpuArray(chi_s); chi_l_pit = gpuArray(chi_l_pit); chi_salt = gpuArray(chi_salt); -------------------------------------------------------------------------------- /PeriFast_Corrosion/inputs.m: -------------------------------------------------------------------------------- 1 | % Physical inputs for pitting corrosion problems 2 | corrosion_type = 1; %0 represents diffusion-control uniform corrosion 3 | %1 represents activation-control uniform corrosion, 4 | %2 represents pitting corrosion 5 | if(corrosion_type == 0 || corrosion_type == 1) 6 | %for uniform corrosion, Cu plate in NaCl solution 7 | K = 1297e-12; % diffusion coefficient of ion in the solution, unit in m^2/s 8 | cur_i = 1.45e3; % initial corrosion current density, unit in A/m^2 9 | n = 2;% average charge number of SS 304, no unit 10 | C_sat = 5000; % saturation concentration, unit in mol/m^3 11 | C_solid = 141000; % solid concentration, unit in mol/m^3 12 | elseif(corrosion_type == 2) 13 | %for pitting corrosion, 304 stainless steel in NaCl solution 14 | K = 860e-12; % diffusion coefficient of ion in the solution, unit in m^2/s 15 | cur_i = 5.1e3; % initial corrosion current density, unit in A/m^2 16 | n = 2.19;% average charge number of SS 304, no unit 17 | C_sat = 4600; % saturation concentration, unit in mol/m^3 18 | C_solid = 142900; % solid concentration, unit in mol/m^3 19 | end 20 | 21 | F = 96485.33; % Faraday's constant, unit in C/mol 22 | q = cur_i/(n*F); % dissolution flux 23 | 24 | t_max = 300; % corrosion duration time, unit in s 25 | dt = 0.459; % time step (should satisfy the stability condition,see https://doi.org/10.1016/j.cma.2020.113633) 26 | 27 | %visualization parameters 28 | is_plot_in_Matlab = 0; % if want to plot at certain time and generate a video, set to 1 29 | is_output_to_Tecplot = 0; % if want to write data to Tecplot at certain time, set to 1 30 | freq_output = 30;%data dump frequence 31 | freq_plot = 30; %plot frequence 32 | if(freq_output == 0) 33 | t_output_interval = nan; 34 | else 35 | t_output_interval = t_max/freq_output; %time interval of write data 36 | end 37 | t_output_target = t_output_interval; 38 | if(freq_plot == 0) 39 | t_plot_interval = nan; 40 | else 41 | t_plot_interval = t_max/freq_plot; %time interval of plotting in MATLAB 42 | end 43 | t_plot_target = t_plot_interval; 44 | 45 | has_salt_layer = 0; %if consider salt layer effect, set to 1 46 | 47 | run_in_gpu = 0; %if want to run in gpu, set to 1 48 | 49 | input_check(corrosion_type, K, cur_i, n, F, C_sat, C_solid, t_max, freq_output, freq_plot); 50 | 51 | function input_check(corrosion_type, K, cur_i, n, F, C_sat, C_solid, t_max, freq_output, freq_plot) 52 | if(corrosion_type ~= 0 && corrosion_type ~= 1 && corrosion_type ~=2) 53 | error('Corrosion_type is wrong'); 54 | end 55 | if(K <= 0) 56 | error('Diffusion coefficient K must be a positive number'); 57 | end 58 | if(cur_i <= 0) 59 | error('Current density cur_i must be a positive number'); 60 | end 61 | if(n <= 0) 62 | error('Average charge number n must be a positive number'); 63 | end 64 | if(F ~= 96485.33) 65 | error('Faraday constant is a fixed value, do not change it'); 66 | end 67 | if(C_sat <= 0) 68 | error('Saturation concentration must be a positive number'); 69 | end 70 | if(C_solid <= 0) 71 | error('Solid concentration must be a positive number'); 72 | end 73 | if(t_max <= 0) 74 | error('Corrosion duration time must be a positive number'); 75 | end 76 | if(freq_output <=0) 77 | warning('No data will be dumped. Set freq_output to a positive number'); 78 | end 79 | if(freq_plot <=0) 80 | warning('No visualization will be plot. Set freq_plot to a positive number'); 81 | end 82 | end -------------------------------------------------------------------------------- /PeriFast_Corrosion/kernel_functions.m: -------------------------------------------------------------------------------- 1 | % Kernel functions used in corrosion: 2 | % the center of box 3 | x_c = x_min_T + Lx_T/2; 4 | y_c = y_min_T + Ly_T/2; 5 | z_c = z_min_T + Lz_T/2; 6 | % Kernel function for the diffusion in 3D: 7 | kernel_diff = @(x1,x2,x3) 9*K/(2*pi*delta^3) * 1./(x1.^2+x2.^2+x3.^2) .*(sqrt(x1.^2 + x2.^2 + x3.^2) <= delta); 8 | % Kernel function for corrosion in 3D: 9 | kernel_corr = @(x1,x2,x3) 3*q/(pi*delta^3) * 1./(sqrt(x1.^2+x2.^2+x3.^2)) .*(sqrt(x1.^2 + x2.^2 + x3.^2) <= delta); 10 | 11 | % Descritized kernel diffusion and corrosion 12 | mu_diff = kernel_diff(X - x_c, Y - y_c, Z - z_c); %kernel for diffusion in liquid 13 | mu_diff(X==x_c & Y==y_c & Z==z_c) = 0; % zero out the singularity 14 | beta_diff = sum(sum(sum(mu_diff.*(dx*dy*dz)))); 15 | muS_diff_hat = fftn(fftshift(mu_diff)); % adjust kernel functions on the periodic box T 16 | 17 | mu_corr = kernel_corr(X - x_c, Y - y_c, Z - z_c); %kernel for corrosion (solid to liquid) 18 | mu_corr(X==x_c & Y==y_c & Z==z_c) = 0; % zero out the singularity 19 | beta_corr = sum(sum(sum(mu_corr.*(dx*dy*dz)))); 20 | muS_corr_hat = fftn(fftshift(mu_corr)); 21 | 22 | stability_check(dt,beta_diff,beta_corr,t_max,corrosion_type, C_sat); 23 | % Mutiplication function to compute convolution integrals in Fourier Space 24 | convolveInFourier_diff = @(m) muS_diff_hat.*m*dx*dy*dz; 25 | convolveInFourier_corr = @(m) muS_corr_hat.*m*dx*dy*dz; 26 | 27 | function stability_check(dt,beta_diff,beta_corr,t_max,corrosion_type, C_sat) 28 | if(dt > 1/beta_diff && (corrosion_type == 0 || corrosion_type == 2)) %for corrosion types that consider diffusion 29 | error('dt does not meet the stability condition. Please set dt less than %d, see https://doi.org/10.1016/j.cma.2020.113633',1/beta_diff); 30 | end 31 | 32 | if(dt > C_sat/beta_corr && corrosion_type == 1) %for activation-control corrosion that do not consider diffusion 33 | error('dt does not meet the stability condition. Please set dt less than %d, see https://doi.org/10.1016/j.cma.2020.113633',C_sat/beta_corr); 34 | end 35 | 36 | if(dt < 0) 37 | error('dt must be positive'); 38 | end 39 | if(dt > t_max) 40 | error('dt can not large than the total time'); 41 | end 42 | end -------------------------------------------------------------------------------- /PeriFast_Corrosion/main.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % ________ __________________ _________________________ ________________ % 3 | % ___ __ \___ ____/___ __ \____ _/___ ____/___ |__ ___/___ __/ % 4 | % __ /_/ /__ __/ __ /_/ / __ / __ /_ __ /| |_____ \ __ / % 5 | % _ ____/ _ /___ _ _, _/ __/ / _ __/ _ ___ |____/ / _ / % 6 | % /_/ /_____/ /_/ |_| /___/ /_/ /_/ |_|/____/ /_/ % 7 | % % 8 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9 | % This code solves 3D corrosion problems (uniform 10 | % corrosion and pitting corrosion with multiple growing/merging pits) with peridynamic 11 | % models discretized using the Fast Convolution-Based Method (FCBM) 12 | % Detailed description of the code can be found in 13 | % 'PeriFast/Corrosion: a 3D pseudo-spectral peridynamic code for corrosion' 14 | % by: Longzhen Wang, Dr. Siavash Jafarzadeh, Dr. Florin Bobaru 15 | % see https://doi.org/10.21203/rs.3.rs-2046856/v1 16 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17 | clear; clc; close all; 18 | inputs; 19 | nodes_and_sets; 20 | initial_conditions; 21 | kernel_functions; 22 | boundary_conditions; 23 | % initialize output to tecplot file 24 | if (is_output_to_Tecplot == 1) 25 | tdata=[]; 26 | tdata.Nvar=4; 27 | tdata.varnames={'x','y','z','C'}; 28 | tdata.cubes(1).x=X; 29 | tdata.cubes(1).y=Y; 30 | tdata.cubes(1).z=Z; 31 | tdata.cubes(1).v(1,:,:,:)=C; 32 | tec_step = 1; 33 | end 34 | %generate output movie 35 | if (is_plot_in_Matlab == 1) 36 | writerObj=VideoWriter('bigN_corrosion'); 37 | open(writerObj); 38 | end 39 | % Time integration (Forward Euler): 40 | time_step = 1;% time step counter 41 | ks = 1;% snapshot counter 42 | total_time_step = round(t_max/dt); 43 | Output = struct;% struct variable to record output data 44 | if(run_in_gpu == 1) 45 | initial_gpu_arrays; 46 | end 47 | tic 48 | for t = dt:dt:t_max 49 | fprintf('time step: %d out of %i\n',time_step,total_time_step); 50 | % update the volume constraints 51 | C_w = update_VC(C_w,C,Nx,Ny,Nz,n1,n2,n3,n4,n5,n6,X,Y,Z,Lx_T,Ly_T,Lz_T,delta,BC_type,BC_value); 52 | % update the concentration C 53 | [C,chi_l,chi_s] = update_C(corrosion_type,dt,C,C_w,C_sat,chi_l,chi_N,chi,Nx,Ny,Nz,convolveInFourier_diff,convolveInFourier_corr,has_salt_layer); 54 | % Dump output (snapshots) 55 | if (abs(t-t_output_target) <= dt) 56 | % Dump data in the struct variable: Output 57 | fprintf('time step: %d out of %i\n',time_step,total_time_step); 58 | fprintf('...dumping output at %d\n', t); 59 | [Output,ks] = dump_output(Output,ks,C,chi_l,t,run_in_gpu); 60 | 61 | if (is_output_to_Tecplot == 1) 62 | % output data to tecplot 63 | fprintf('...dumping output to Tecplot...\n'); 64 | tec_step = tec_step + 1; 65 | tdata = dump_output_Tecplot(tdata,X,Y,Z,C,run_in_gpu,tec_step); 66 | end 67 | t_output_target = t_output_target + t_output_interval; 68 | ks = ks + 1; 69 | end 70 | if(abs(t-t_plot_target) <= dt) 71 | % Visualization (snapshots) 72 | if (is_plot_in_Matlab == 1) 73 | fprintf('time step: %d out of %i\n',time_step,total_time_step); 74 | fprintf('...plotting...\n'); 75 | visualization(X,Y,Z,C,Ldx,dx,Ldy,dy,Ldz,dz,t,C_sat,writerObj); 76 | end 77 | t_plot_target = t_plot_target + t_plot_interval; 78 | end 79 | time_step = time_step + 1; 80 | end 81 | toc 82 | % computation is finished, save the results 83 | if (is_plot_in_Matlab) 84 | close(writerObj); 85 | end 86 | if (is_output_to_Tecplot) 87 | mat2tecplot(tdata,'UNL_N_corrosion.plt'); 88 | end 89 | fprintf('...saving results to file...\n'); 90 | save('Results.mat','Output','X','Y','Z','Ldx','Ldy','Ldz','dx','dy','dz','C_sat','t','chi_N','chi','-v7.3') 91 | fprintf('...simulation done...\n'); -------------------------------------------------------------------------------- /PeriFast_Corrosion/nodes_and_sets.m: -------------------------------------------------------------------------------- 1 | % The big N and surrounding liquid domain dimensions 2 | % big N solid is in a 150*120*40 um box 3 | % the liquid domain has a 2 horizon size thickness 4 | delta = 4e-6; % horizon size, unit in m 5 | Ldx = 150e-6+2*delta; % physical domain length in x direction 6 | Ldy = 120e-6+2*delta; % physical domain length in y direction 7 | Ldz = 40e-6+2*delta; % physical domain length in z direction 8 | x_min = -Ldx/2; 9 | x_max = Ldx/2; 10 | y_min = -Ldy/2; 11 | y_max = Ldy/2; 12 | z_min = -Ldz/2; 13 | z_max = Ldz/2; 14 | % One periodic Domain (T) 15 | % extend 1 horizon size at each end, in order to avoid wrap-up 16 | % and use ficitious node method to apply boundary conditions 17 | extension = 1.0*delta; 18 | x_min_T = x_min - extension; 19 | x_max_T = x_max + extension; 20 | y_min_T = y_min - extension; 21 | y_max_T = y_max + extension; 22 | z_min_T = z_min - extension; 23 | z_max_T = z_max + extension; 24 | % the period box dimension 25 | Lx_T = x_max_T - x_min_T; 26 | Ly_T = y_max_T - y_min_T; 27 | Lz_T = z_max_T - z_min_T; 28 | 29 | % Discretize the domain 30 | Nx = 2^7; % resolution in x (Best for FFT to use a power of 2) 31 | Ny = 2^7; % resolution in y 32 | Nz = 2^6; % resolution in z 33 | dx = Lx_T/Nx; % grid size in x 34 | dy = Ly_T/Ny; % grid size in y 35 | dz = Lz_T/Nz; % grid size in z 36 | x = x_min_T + (0:(Nx-1))*dx; 37 | y = y_min_T + (0:(Ny-1))*dy; 38 | z = z_min_T + (0:(Nz-1))*dz; 39 | [X,Y,Z] = meshgrid(x,y,z); 40 | m = [delta/dx, delta/dy, delta/dz];% m value along x, y, z directions 41 | discretization_check(delta,Ldx,Ldy,Ldz,extension,Nx,Ny,Nz,m); 42 | % Mask functions: 43 | % Construct Mask function (chi) to distinguish the ficititious nodes 44 | chi = ones (Nx, Ny, Nz); 45 | chi (X x_max) = 0; 46 | chi (Y y_max) = 0; 47 | chi (Z z_max) = 0; 48 | % create the geometry of the big N, the dimensions can be found in 49 | %'PeriFast/Corrosion: a 3D pseudo-spectral peridynamic code for corrosion' 50 | chi_N = ones(Nx,Ny,Nz); 51 | chi_N(X<-65e-6 & (Y<35e-6 & Y>-35e-6)) = 0; 52 | chi_N(X>65e-6 & (Y<35e-6 & Y>-35e-6)) = 0; 53 | chi_N((X<15e-6 & X>-25e-6) & Y<-7/4*X-33.75e-6) = 0; 54 | chi_N((X<25e-6 & X>-15e-6) & Y>-7/4*X+33.75e-6) = 0; 55 | chi_N((X<-15e-6 & X>-25e-6) & (Y<-35e-6 & Y>-60e-6)) = 1; 56 | chi_N((X<25e-6 & X>15e-6) & (Y>35e-6 & Y<60e-6)) = 1; 57 | chi_N(X>75e-6 | X<-75e-6) = 0; 58 | chi_N(Y>60e-6 | Y<-60e-6) = 0; 59 | chi_N(Z>20e-6 | Z<-20e-6) = 0; 60 | 61 | function discretization_check(delta,Ldx,Ldy,Ldz,extension,Nx,Ny,Nz,m) 62 | %check horizon size 63 | if(delta<=0) 64 | error('Delta must be a positive number'); 65 | end 66 | if(Ldx<=0) 67 | error('Physical domain length along x has to be positive'); 68 | end 69 | if(Ldy<=0) 70 | error('Physical domain length along y has to be positive'); 71 | end 72 | if(Ldz<=0) 73 | error('Physical domain length along z has to be positive'); 74 | end 75 | if(delta >= Ldx) 76 | warning('delta is larger than physical domain length along x, choose a smaller horizon'); 77 | end 78 | if(delta >= Ldy) 79 | warning('delta is larger than physical domain length along y, choose a smaller horizon'); 80 | end 81 | if(delta >= Ldz) 82 | warning('delta is larger than physical domain length along z, choose a smaller horizon'); 83 | end 84 | if(extension < delta) 85 | error('To apply fictitious node method, the extension has to be at least delta'); 86 | end 87 | if(Nx<=0) 88 | error('Resolution in x has to be positive'); 89 | end 90 | if(Ny<=0) 91 | error('Resolution in y has to be positive'); 92 | end 93 | if(Nz<=0) 94 | error('Resolution in z has to be positive'); 95 | end 96 | if(m(1)< 3) 97 | warning('delta is less than three times discretization,finer discretization along x is recommended'); 98 | end 99 | if(m(2)< 3) 100 | warning('delta is less than three times discretization,finer discretization along y is recommended'); 101 | end 102 | if(m(3)< 3) 103 | warning('delta is less than three times discretization,finer discretization along z is recommended'); 104 | end 105 | end 106 | 107 | -------------------------------------------------------------------------------- /PeriFast_Corrosion/postprocess.m: -------------------------------------------------------------------------------- 1 | %user can use this script to postprocess the stored matlab data 2 | load('Results.mat'); 3 | output_size = size(Output,2); 4 | writerObj=VideoWriter('bigN_corrosion'); 5 | open(writerObj); 6 | for i = 1:output_size 7 | visualization(X,Y,Z,Output(i).C,Ldx,dx,Ldy,dy,Ldz,dz,Output(i).t,C_sat,writerObj); 8 | end 9 | close(writerObj); 10 | fprintf('...post processing finished...\n'); -------------------------------------------------------------------------------- /PeriFast_Corrosion/update_C.m: -------------------------------------------------------------------------------- 1 | function [C,chi_l,chi_s] = update_C(corrosion_type,dt,C,C_w,C_sat,chi_l,chi_N,chi,Nx,Ny,Nz,convolveInFourier_diff,convolveInFourier_corr,has_salt_layer) 2 | if(corrosion_type == 0) 3 | [C,chi_l,chi_s] = diffusion_control_uniform_corrosion_time_integration(dt,C,C_w,C_sat,chi_l,chi,Nx,Ny,Nz,convolveInFourier_diff,convolveInFourier_corr,has_salt_layer); 4 | elseif(corrosion_type ==1) 5 | [C,chi_l,chi_s] = activation_control_uniform_corrosion_time_integration(dt,C,C_w,C_sat,chi_l,chi,convolveInFourier_corr); 6 | elseif(corrosion_type == 2) 7 | [C,chi_l,chi_s] = pitting_corrosion_time_integration(dt,C,C_w,C_sat,chi_l,chi_N,chi,Nx,Ny,Nz,convolveInFourier_diff,convolveInFourier_corr,has_salt_layer); 8 | else 9 | error('Corrosion_type is wrong'); 10 | end 11 | end 12 | 13 | function [C,chi_l,chi_s] = pitting_corrosion_time_integration(dt,C,C_w,C_sat,chi_l,chi_N,chi,Nx,Ny,Nz,convolveInFourier_diff,convolveInFourier_corr,has_salt_layer) 14 | % Update mask functions for liquid domain, salt layer, and solid domain: 15 | chi_l (C < C_sat) = 1; %find liquid node 16 | chi_l_pit = zeros(Nx,Ny,Nz); 17 | chi_l_pit(chi_l==1 & chi_N==1) = 1; 18 | chi_salt = zeros(Nx,Ny,Nz); 19 | if(has_salt_layer==1) 20 | chi_salt(C >= C_sat & chi_l_pit==1) = 1; 21 | end 22 | chi_s = 1 - chi_l; 23 | 24 | C = chi.*(C + dt*((chi_l).*ifftn(convolveInFourier_diff(fftn(C.*(chi_l))),'symmetric') -... 25 | ((chi_l).*C).*ifftn(convolveInFourier_diff(fftn(chi_l)),'symmetric') + ... 26 | (chi_l_pit-chi_salt).*ifftn(convolveInFourier_corr(fftn(chi_s)),'symmetric') -... 27 | chi_s.*ifftn(convolveInFourier_corr(fftn(chi_l_pit-chi_salt)),'symmetric')))+ (1 - chi).*C_w; 28 | 29 | end 30 | 31 | function [C,chi_l,chi_s] = diffusion_control_uniform_corrosion_time_integration(dt,C,C_w,C_sat,chi_l,chi,Nx,Ny,Nz,convolveInFourier_diff,convolveInFourier_corr,has_salt_layer) 32 | % Update mask functions for liquid domain, salt layer, and solid domain: 33 | chi_l (C < C_sat) = 1; %find liquid node 34 | chi_salt = zeros(Nx,Ny,Nz); 35 | if(has_salt_layer==1) 36 | chi_salt(C >= C_sat & chi_l==1) = 1; 37 | end 38 | chi_s = 1 - chi_l; 39 | 40 | C = chi.*(C + dt*((chi_l).*ifftn(convolveInFourier_diff(fftn(C.*(chi_l))),'symmetric') -... 41 | ((chi_l).*C).*ifftn(convolveInFourier_diff(fftn(chi_l)),'symmetric') + ... 42 | (chi_l-chi_salt).*ifftn(convolveInFourier_corr(fftn(chi_s)),'symmetric') -... 43 | chi_s.*ifftn(convolveInFourier_corr(fftn(chi_l-chi_salt)),'symmetric')))+ (1 - chi).*C_w; 44 | 45 | end 46 | 47 | function [C,chi_l,chi_s] = activation_control_uniform_corrosion_time_integration(dt,C,C_w,C_sat,chi_l,chi,convolveInFourier_corr) 48 | % Update mask functions for liquid domain and solid domain: 49 | chi_l (C < C_sat) = 1; %find liquid node 50 | 51 | chi_s = 1 - chi_l; 52 | 53 | C = chi.*(C + dt*((chi_l).*ifftn(convolveInFourier_corr(fftn(chi_s)),'symmetric') -... 54 | chi_s.*ifftn(convolveInFourier_corr(fftn(chi_l)),'symmetric')))+ (1 - chi).*C_w; 55 | 56 | C(chi_l==1) = 0; %set the liquid domain concentration to zero 57 | end -------------------------------------------------------------------------------- /PeriFast_Corrosion/update_VC.m: -------------------------------------------------------------------------------- 1 | function C_w = update_VC(C_w,C,Nx,Ny,Nz,n1,n2,n3,n4,n5,n6,X,Y,Z,Lx_T,Ly_T,Lz_T,delta,BC_type,BC_value) 2 | % Update volume constraints C_w(x,t) according to the given local boundary conditions: 3 | C_w(:,:,Nz - size(n1,1) + 1:Nz)=assemble_BC(BC_type(1),BC_value(1),Z(:,:,Nz - size(n1,1) + 1:Nz)-(Lz_T/2 - delta),C(:,:,n1(end):-1:n1(1))); 4 | C_w(:,:,1:size(n2,1)) = assemble_BC(BC_type(2),BC_value(2),Z(:,:,1:size(n2,1))-(-Lz_T/2 + delta),C(:,:,n2(end):-1:n2(1))); 5 | C_w(:, Nx - size(n3,2)+1:Nx,:) = assemble_BC(BC_type(3),BC_value(3),X(:, Nx - size(n3,2) + 1:Nx,:)-(Lx_T/2-delta),C(:,n3(end):-1:n3(1),:)); 6 | C_w(:,1:size(n4,2),:) = assemble_BC(BC_type(4),BC_value(4),X(:,1:size(n4,2),:)-(-Lx_T/2 + delta),C(:,n4(end):-1:n4(1),:)); 7 | C_w(Ny - size(n5,1) + 1:Ny,:,:) = assemble_BC(BC_type(5),BC_value(5),Y(Ny - size(n5,1) + 1:Ny,:,:)-(Ly_T/2 - delta), C(n5(end):-1:n5(1),:,:)) ; 8 | C_w(1:size(n6,1),:,:) = assemble_BC(BC_type(6),BC_value(6),Y(1:size(n6,1),:,:)-(-Ly_T/2 + delta),C(n6(end):-1:n6(1),:,:)); 9 | end 10 | function volume_constraint = assemble_BC(BC_type,BC_value,distance_from_boundary,concentration_inside_boundary) 11 | %based on fictitious node method 12 | if(BC_type == 1) 13 | volume_constraint = 2*BC_value - concentration_inside_boundary; 14 | elseif(BC_type == 2) 15 | volume_constraint = 2*BC_value*distance_from_boundary + concentration_inside_boundary; 16 | else 17 | error('This BC type is not supported'); 18 | end 19 | end -------------------------------------------------------------------------------- /PeriFast_Corrosion/visualization.m: -------------------------------------------------------------------------------- 1 | function visualization (X,Y,Z,C,Ldx,dx,Ldy,dy,Ldz,dz,t,C_sat,writerObj) 2 | % plot the result, create a isosurface 3 | % the user could add any other plots freely 4 | 5 | clf 6 | isosurface(X,Y,Z,C,C_sat) 7 | axis equal 8 | xlabel('X') 9 | ylabel('Y') 10 | zlabel('Z') 11 | xlim([-Ldx/2+dx,Ldx/2-dx]) 12 | ylim([-Ldy/2+dy,Ldy/2-dy]) 13 | zlim([-Ldz/2+dz,Ldz/2-dz]) 14 | title ( sprintf ('t =% 1.4f',t)); 15 | colorbar 16 | caxis([0 C_sat]) 17 | drawnow 18 | 19 | % take frame for movie generate 20 | frame = getframe(gcf); 21 | writeVideo(writerObj,frame); 22 | end -------------------------------------------------------------------------------- /PeriFast_Dynamics/close_Matlab_video.m: -------------------------------------------------------------------------------- 1 | % close videos 2 | num_of_outputs = size(outputs_var_for_visualization,2); 3 | 4 | for i = 1:num_of_outputs 5 | out_var = outputs_var_for_visualization(1,i); 6 | 7 | if out_var == 1 8 | 9 | close(u1_video); 10 | end 11 | if out_var == 2 12 | 13 | close(u2_video); 14 | end 15 | if out_var == 3 16 | 17 | close(u3_video); 18 | end 19 | if out_var == 4 20 | 21 | close(u_mag_video); 22 | end 23 | if out_var == 5 24 | 25 | close(v1_video); 26 | end 27 | if out_var == 6 28 | 29 | close(v2_video); 30 | 31 | end 32 | if out_var == 7 33 | 34 | close(v3_video); 35 | end 36 | 37 | if out_var == 8 38 | 39 | close(v_mag_video); 40 | end 41 | if out_var == 9 42 | 43 | close(W_video); 44 | 45 | end 46 | if out_var == 10 47 | 48 | close(d_video); 49 | 50 | end 51 | if out_var == 11 52 | 53 | close(lambda_video); 54 | end 55 | 56 | 57 | end 58 | -------------------------------------------------------------------------------- /PeriFast_Dynamics/constitutive.m: -------------------------------------------------------------------------------- 1 | function [L1, L2, L3, W, history_var] = ... 2 | constitutive(props,u1,u2,u3,history_var,delta,constit_invar,chiB,dv, Nx,Ny,Nz, run_in_gpu) 3 | % This function takes the displacement field, history-dependent variables 4 | % such as the old damage parameter, the material properties (defined in 5 | % inputs.m), discretization info (defined in nodes_and_sets.m), and the 6 | % invariant terms in the constitutive response (from pre_constitutive.m) 7 | % as inputs, and returns the internal force density, strain energy density, 8 | % and updated history-dependnet variables(e.g. damage) as outputs 9 | 10 | mat_type = props(1); % material model 11 | 12 | 13 | % bond_based PD model 14 | if mat_type == 0 15 | % re-assign transformed adjusted kernels 16 | C11s_hat = constit_invar.C11s_hat; C12s_hat = constit_invar.C12s_hat; 17 | C13s_hat = constit_invar.C13s_hat; C22s_hat = constit_invar.C22s_hat; 18 | C23s_hat = constit_invar.C23s_hat; C33s_hat = constit_invar.C33s_hat; 19 | C21s_hat = C12s_hat; C31s_hat = C13s_hat; C32s_hat = C23s_hat; 20 | 21 | % compute repeated terms 22 | lambda = history_var.lambda; 23 | chiB_lambda = chiB.*lambda; 24 | chiB_lambda_hat = fftn(chiB_lambda); 25 | chiB_lambda_u1_hat = fftn(chiB_lambda.*u1); 26 | chiB_lambda_u2_hat = fftn(chiB_lambda.*u2); 27 | chiB_lambda_u3_hat = fftn(chiB_lambda.*u3); 28 | 29 | chiB_lambda_u1u1_hat = fftn(chiB_lambda.*u1.*u1); 30 | chiB_lambda_u1u2_hat = fftn(chiB_lambda.*u1.*u2); 31 | chiB_lambda_u1u3_hat = fftn(chiB_lambda.*u1.*u3); 32 | chiB_lambda_u2u2_hat = fftn(chiB_lambda.*u2.*u2); 33 | chiB_lambda_u2u3_hat = fftn(chiB_lambda.*u2.*u3); 34 | chiB_lambda_u3u3_hat = fftn(chiB_lambda.*u3.*u3); 35 | 36 | % compute internal force density (Li) 37 | L1 = dv*(chiB_lambda.*(ifftn(C11s_hat.*chiB_lambda_u1_hat + ... 38 | C12s_hat.*chiB_lambda_u2_hat + C13s_hat.*chiB_lambda_u3_hat))-... 39 | ifftn(C11s_hat.*chiB_lambda_hat).*chiB_lambda.*u1 - ... 40 | ifftn(C12s_hat.*chiB_lambda_hat).*chiB_lambda.*u2 - ... 41 | ifftn(C13s_hat.*chiB_lambda_hat).*chiB_lambda.*u3); 42 | 43 | L2 = dv*(chiB_lambda.*(ifftn(C21s_hat.*chiB_lambda_u1_hat +... 44 | C22s_hat.*chiB_lambda_u2_hat + C23s_hat.*chiB_lambda_u3_hat))-... 45 | ifftn(C21s_hat.*chiB_lambda_hat).*chiB_lambda.*u1 -... 46 | ifftn(C22s_hat.*chiB_lambda_hat).*chiB_lambda.*u2 -... 47 | ifftn(C23s_hat.*chiB_lambda_hat).*chiB_lambda.*u3); 48 | 49 | L3 = dv*(chiB_lambda.*(ifftn(C31s_hat.*chiB_lambda_u1_hat +... 50 | C32s_hat.*chiB_lambda_u2_hat + C33s_hat.*chiB_lambda_u3_hat))-... 51 | ifftn(C31s_hat.*chiB_lambda_hat).*chiB_lambda.*u1 -... 52 | ifftn(C32s_hat.*chiB_lambda_hat).*chiB_lambda.*u2 -... 53 | ifftn(C33s_hat.*chiB_lambda_hat).*chiB_lambda.*u3); 54 | 55 | %%% strain enegry density (W) 56 | 57 | % compute W 58 | W = 0.25*dv*chiB_lambda.*(ifftn(C11s_hat.*chiB_lambda_u1u1_hat + ... 59 | 2*C12s_hat.*chiB_lambda_u1u2_hat + 2*C13s_hat.*chiB_lambda_u1u3_hat +... 60 | C22s_hat.*chiB_lambda_u2u2_hat + 2* C23s_hat.*chiB_lambda_u2u3_hat +... 61 | C33s_hat.*chiB_lambda_u3u3_hat) - ... 62 | 2*(ifftn(C11s_hat.*chiB_lambda_u1_hat).*u1 +... 63 | ifftn(C12s_hat.*chiB_lambda_u1_hat).*u2 +... 64 | ifftn(C13s_hat.*chiB_lambda_u1_hat).*u3 +... 65 | ifftn(C21s_hat.*chiB_lambda_u2_hat).*u1 +... 66 | ifftn(C22s_hat.*chiB_lambda_u2_hat).*u2+... 67 | ifftn(C23s_hat.*chiB_lambda_u2_hat).*u3 +... 68 | ifftn(C31s_hat.*chiB_lambda_u3_hat).*u1 +... 69 | ifftn(C32s_hat.*chiB_lambda_u3_hat).*u2 +... 70 | ifftn(C33s_hat.*chiB_lambda_u3_hat).*u3 ) +... 71 | ifftn(C11s_hat.*chiB_lambda_hat).*u1.*u1 + ... 72 | 2*(ifftn(C12s_hat.*chiB_lambda_hat).*u1.*u2) +... 73 | 2*(ifftn(C13s_hat.*chiB_lambda_hat).*u1.*u3) +... 74 | ifftn(C22s_hat.*chiB_lambda_hat).*u2.*u2 +... 75 | 2*(ifftn(C23s_hat.*chiB_lambda_hat).*u2.*u3) +... 76 | ifftn(C33s_hat.*chiB_lambda_hat).*u3.*u3 ); 77 | %%% update lambda according to the damage model 78 | G0 = props(3); 79 | lambda( W >= G0/(2*delta) ) = 0; 80 | history_var.lambda = lambda; 81 | 82 | %%% update damage index 83 | omega0s_hat = constit_invar.omega0s_hat; 84 | chiB_hat = fftn(chiB); 85 | numerator = chiB_lambda.*ifftn(chiB_lambda_hat.*omega0s_hat); 86 | denominator = chiB.*ifftn(chiB_hat.*omega0s_hat); 87 | denominator(denominator == 0) = 1; %avoid division by zero 88 | 89 | history_var.damage = 1 - numerator./denominator; 90 | end 91 | 92 | % state_based PD model 93 | if mat_type == 1 94 | % re-assign transformed adjusted kernels 95 | C11s_hat = constit_invar.C11s_hat; C12s_hat = constit_invar.C12s_hat; 96 | C13s_hat = constit_invar.C13s_hat; C22s_hat = constit_invar.C22s_hat; 97 | C23s_hat = constit_invar.C23s_hat; C33s_hat = constit_invar.C33s_hat; 98 | C21s_hat = C12s_hat; C31s_hat = C13s_hat; C32s_hat = C23s_hat; 99 | 100 | % compute repeated terms 101 | lambda = history_var.lambda; 102 | chiB_lambda = chiB.*lambda; 103 | chiB_lambda_hat = fftn(chiB_lambda); 104 | chiB_lambda_u1_hat = fftn(chiB_lambda.*u1); 105 | chiB_lambda_u2_hat = fftn(chiB_lambda.*u2); 106 | chiB_lambda_u3_hat = fftn(chiB_lambda.*u3); 107 | 108 | chiB_lambda_u1u1_hat = fftn(chiB_lambda.*u1.*u1); 109 | chiB_lambda_u1u2_hat = fftn(chiB_lambda.*u1.*u2); 110 | chiB_lambda_u1u3_hat = fftn(chiB_lambda.*u1.*u3); 111 | chiB_lambda_u2u2_hat = fftn(chiB_lambda.*u2.*u2); 112 | chiB_lambda_u2u3_hat = fftn(chiB_lambda.*u2.*u3); 113 | chiB_lambda_u3u3_hat = fftn(chiB_lambda.*u3.*u3); 114 | 115 | % re-assign transformed adjusted kernels 116 | A1s_hat = constit_invar.A1s_hat; 117 | A2s_hat = constit_invar.A2s_hat; 118 | A3s_hat = constit_invar.A3s_hat; 119 | m_kernels_hat = constit_invar.m_kernels_hat; 120 | 121 | m = chiB_lambda.*ifftn(chiB_lambda_hat.*m_kernels_hat,'symmetric')*dv; 122 | m(m == 0) = 1; % avoid division by zero outside the body where chi_B = 0 123 | 124 | E = props(4);% Young modulus 125 | nu = props (5);% Poisson ratio 126 | K = E/(3*(1 - 2*nu)); % bulk modulus 127 | G = E/(2*(1 + nu)); % shear modulus 128 | 129 | % PD dilatation 130 | theta = (3./m).*chiB_lambda.*(-ifftn(A1s_hat.*chiB_lambda_u1_hat +... 131 | A2s_hat.*chiB_lambda_u2_hat + A3s_hat.*chiB_lambda_u3_hat,'symmetric') + ... 132 | u1.*ifftn(A1s_hat.*chiB_lambda_hat,'symmetric') + ... 133 | u2.*ifftn(A2s_hat.*chiB_lambda_hat,'symmetric') + ... 134 | u3.*ifftn(A3s_hat.*chiB_lambda_hat,'symmetric'))*dv; 135 | 136 | chiB_lambda_theta_hat = fftn(chiB_lambda.*theta); 137 | 138 | % compute internal force density (Li) 139 | L1 = dv.*chiB_lambda.*(((3*K - 5*G)./m).*(-theta.*ifftn(A1s_hat.*chiB_lambda_hat,'symmetric') -... 140 | ifftn(A1s_hat.*chiB_lambda_theta_hat,'symmetric')) + ... 141 | (1./m).*(ifftn(C11s_hat.*chiB_lambda_u1_hat,'symmetric') +... 142 | ifftn(C12s_hat.*chiB_lambda_u2_hat,'symmetric') +... 143 | ifftn(C13s_hat.*chiB_lambda_u3_hat,'symmetric') - ... 144 | u1.*ifftn(C11s_hat.*chiB_lambda_hat,'symmetric') - ... 145 | u2.*ifftn(C12s_hat.*chiB_lambda_hat,'symmetric')- ... 146 | u3.*ifftn(C13s_hat.*chiB_lambda_hat,'symmetric'))); 147 | 148 | L2 = dv.*chiB_lambda.*(((3*K - 5*G)./m).*(-theta.*ifftn(A2s_hat.*chiB_lambda_hat,'symmetric') -... 149 | ifftn(A2s_hat.*chiB_lambda_theta_hat,'symmetric')) + ... 150 | (1./m).*(ifftn(C21s_hat.*chiB_lambda_u1_hat,'symmetric') +... 151 | ifftn(C22s_hat.*chiB_lambda_u2_hat,'symmetric') + ... 152 | ifftn(C23s_hat.*chiB_lambda_u3_hat,'symmetric') - ... 153 | u1.*ifftn(C21s_hat.*chiB_lambda_hat,'symmetric') - ... 154 | u2.*ifftn(C22s_hat.*chiB_lambda_hat,'symmetric')- ... 155 | u3.*ifftn(C23s_hat.*chiB_lambda_hat,'symmetric'))); 156 | 157 | L3 = dv.*chiB_lambda.*(((3*K - 5*G)./m).*(-theta.*ifftn(A3s_hat.*chiB_lambda_hat,'symmetric') -... 158 | ifftn(A3s_hat.*chiB_lambda_theta_hat,'symmetric')) + ... 159 | (1./m).*(ifftn(C31s_hat.*chiB_lambda_u1_hat,'symmetric') +... 160 | ifftn(C32s_hat.*chiB_lambda_u2_hat,'symmetric') + ... 161 | ifftn(C33s_hat.*chiB_lambda_u3_hat,'symmetric') - ... 162 | u1.*ifftn(C31s_hat.*chiB_lambda_hat,'symmetric') -... 163 | u2.*ifftn(C32s_hat.*chiB_lambda_hat,'symmetric')- ... 164 | u3.*ifftn(C33s_hat.*chiB_lambda_hat,'symmetric'))); 165 | 166 | %%% strain enegry density (W) 167 | 168 | % compute W 169 | W = 0.5*(dv*chiB_lambda.*(1./(2*m)).*(ifftn(C11s_hat.*chiB_lambda_u1u1_hat + ... 170 | 2*C12s_hat.*chiB_lambda_u1u2_hat + 2*C13s_hat.*chiB_lambda_u1u3_hat +... 171 | C22s_hat.*chiB_lambda_u2u2_hat + 2* C23s_hat.*chiB_lambda_u2u3_hat +... 172 | C33s_hat.*chiB_lambda_u3u3_hat) - ... 173 | 2*(ifftn(C11s_hat.*chiB_lambda_u1_hat).*u1 +... 174 | ifftn(C12s_hat.*chiB_lambda_u1_hat).*u2 +... 175 | ifftn(C13s_hat.*chiB_lambda_u1_hat).*u3 +... 176 | ifftn(C21s_hat.*chiB_lambda_u2_hat).*u1 +... 177 | ifftn(C22s_hat.*chiB_lambda_u2_hat).*u2+... 178 | ifftn(C23s_hat.*chiB_lambda_u2_hat).*u3 +... 179 | ifftn(C31s_hat.*chiB_lambda_u3_hat).*u1 +... 180 | ifftn(C32s_hat.*chiB_lambda_u3_hat).*u2 +... 181 | ifftn(C33s_hat.*chiB_lambda_u3_hat).*u3 ) +... 182 | ifftn(C11s_hat.*chiB_lambda_hat).*u1.*u1 + ... 183 | 2*(ifftn(C12s_hat.*chiB_lambda_hat).*u1.*u2) +... 184 | 2*(ifftn(C13s_hat.*chiB_lambda_hat).*u1.*u3) +... 185 | ifftn(C22s_hat.*chiB_lambda_hat).*u2.*u2 +... 186 | 2*(ifftn(C23s_hat.*chiB_lambda_hat).*u2.*u3) +... 187 | ifftn(C33s_hat.*chiB_lambda_hat).*u3.*u3 ) + (K - 5*G/3).*theta.^2); 188 | 189 | %%% update lambda according to the damage model 190 | G0 = props(3); 191 | lambda( W >= G0/(2*delta) ) = 0; 192 | history_var.lambda = lambda; 193 | 194 | %%% update damage index 195 | omega0s_hat = constit_invar.omega0s_hat; 196 | chiB_hat = fftn(chiB); 197 | numerator = chiB_lambda.*ifftn(chiB_lambda_hat.*omega0s_hat); 198 | denominator = chiB.*ifftn(chiB_hat.*omega0s_hat); 199 | denominator(denominator == 0) = 1; %avoid division by zero 200 | 201 | history_var.damage = 1 - numerator./denominator; 202 | 203 | end 204 | 205 | % corresspondence PD model 206 | if mat_type == 2 207 | % re-assign transformed adjusted kernels 208 | C11s_hat = constit_invar.C11s_hat; C12s_hat = constit_invar.C12s_hat; 209 | C13s_hat = constit_invar.C13s_hat; C22s_hat = constit_invar.C22s_hat; 210 | C23s_hat = constit_invar.C23s_hat; C33s_hat = constit_invar.C33s_hat; 211 | 212 | % compute repeated terms 213 | lambda = history_var.lambda; 214 | chiB_lambda = chiB.*lambda; 215 | chiB_lambda_hat = fftn(chiB_lambda); 216 | chiB_lambda_u1_hat = fftn(chiB_lambda.*u1); 217 | chiB_lambda_u2_hat = fftn(chiB_lambda.*u2); 218 | chiB_lambda_u3_hat = fftn(chiB_lambda.*u3); 219 | 220 | % re-assign transformed adjusted kernels 221 | A1s_hat = constit_invar.A1s_hat; A2s_hat = constit_invar.A2s_hat;A3s_hat = constit_invar.A3s_hat; 222 | omega0s_hat = constit_invar.omega0s_hat; 223 | chiB_lambda_A1s_hat_invfft = ifftn(chiB_lambda_hat.*A1s_hat,'symmetric'); 224 | chiB_lambda_A2s_hat_invfft = ifftn(chiB_lambda_hat.*A2s_hat,'symmetric'); 225 | chiB_lambda_A3s_hat_invfft = ifftn(chiB_lambda_hat.*A3s_hat,'symmetric'); 226 | 227 | % related to stabilizer (in Silling 2017) 228 | omega_stab = chiB_lambda.*ifftn(chiB_lambda_hat.*omega0s_hat,'symmetric')*dv; 229 | E = props(4);% Young modulus 230 | nu = props (5);% Poisson ratio 231 | K = E/(3*(1 - 2*nu)); % bulk modulus 232 | G = E/(2*(1 + nu)); % shear modulus 233 | const = 0.5*dv*18*K/(pi*delta^5);% for stabilizer 234 | beta_stab = const./(omega_stab +(omega_stab==0));% for stabilizer 235 | 236 | % compute shape_tensor K 237 | K11_shape = chiB_lambda.*(ifftn(chiB_lambda_hat .* C11s_hat,'symmetric'))*dv; 238 | K12_shape = chiB_lambda.*(ifftn(chiB_lambda_hat .* C12s_hat,'symmetric'))*dv; 239 | K13_shape = chiB_lambda.*(ifftn(chiB_lambda_hat .* C13s_hat,'symmetric'))*dv; 240 | K22_shape = chiB_lambda.*(ifftn(chiB_lambda_hat .* C22s_hat,'symmetric'))*dv; 241 | K23_shape = chiB_lambda.*(ifftn(chiB_lambda_hat .* C23s_hat,'symmetric'))*dv; 242 | K33_shape = chiB_lambda.*(ifftn(chiB_lambda_hat .* C33s_hat,'symmetric'))*dv; 243 | 244 | % compute inverse shape_tensor 245 | 246 | if (history_var.t == 0)%if first time step, allocate memory for inverse K and compute K_inv: 247 | K11_shape_inv = zeros(Ny,Nx,Nz);K12_shape_inv = zeros(Ny,Nx,Nz);K13_shape_inv = zeros(Ny,Nx,Nz); 248 | K21_shape_inv = zeros(Ny,Nx,Nz);K22_shape_inv = zeros(Ny,Nx,Nz);K23_shape_inv = zeros(Ny,Nx,Nz); 249 | K31_shape_inv = zeros(Ny,Nx,Nz);K32_shape_inv = zeros(Ny,Nx,Nz);K33_shape_inv = zeros(Ny,Nx,Nz); 250 | K_update = ones(Ny,Nx,Nz);% to update K for all nodes if t=0 251 | %compute initial damage at t=0: 252 | chiB_hat = fftn(chiB); 253 | numerator = chiB_lambda.*ifftn(chiB_lambda_hat.*omega0s_hat); 254 | denominator = chiB.*ifftn(chiB_hat.*omega0s_hat); 255 | denominator(denominator == 0) = 1; %avoid division by zero 256 | history_var.damage = 1 - numerator./denominator; 257 | 258 | 259 | else % use K_inv values from previous step 260 | K11_shape_inv = history_var.K_inv11; 261 | K12_shape_inv = history_var.K_inv12; 262 | K13_shape_inv = history_var.K_inv13; 263 | K21_shape_inv = history_var.K_inv12; 264 | K22_shape_inv = history_var.K_inv22; 265 | K23_shape_inv = history_var.K_inv23; 266 | K31_shape_inv = history_var.K_inv13; 267 | K32_shape_inv = history_var.K_inv23; 268 | K33_shape_inv = history_var.K_inv33; 269 | K_update = history_var.K_update; 270 | end 271 | if run_in_gpu ==1 272 | %gather K-shapes for calculation of inv(k) 273 | K11_shape = gather(K11_shape); 274 | K12_shape = gather(K12_shape); 275 | K13_shape = gather(K13_shape); 276 | K22_shape = gather(K22_shape); 277 | K23_shape = gather(K23_shape); 278 | K33_shape = gather(K33_shape); 279 | K11_shape_inv = gather(K11_shape_inv); 280 | K12_shape_inv = gather(K12_shape_inv); 281 | K13_shape_inv = gather(K13_shape_inv); 282 | K21_shape_inv = gather(K21_shape_inv); 283 | K22_shape_inv = gather(K22_shape_inv); 284 | K23_shape_inv = gather(K23_shape_inv); 285 | K31_shape_inv = gather(K31_shape_inv); 286 | K32_shape_inv = gather(K32_shape_inv); 287 | K33_shape_inv = gather(K33_shape_inv); 288 | K_update = gather(K_update); 289 | end 290 | 291 | 292 | for qx = 1:Ny 293 | for qy = 1:Nx 294 | for qz = 1:Nz 295 | % only update K and K_inv, for nodes that lost bonds in previous step 296 | if K_update (qx,qy,qz) 297 | % K is symmetric 298 | K_shape =[K11_shape(qx,qy,qz) K12_shape(qx,qy,qz) K13_shape(qx,qy,qz);... 299 | K12_shape(qx,qy,qz) K22_shape(qx,qy,qz) K23_shape(qx,qy,qz);... 300 | K13_shape(qx,qy,qz) K23_shape(qx,qy,qz) K33_shape(qx,qy,qz)]; 301 | if (det(K_shape)<= 0) 302 | K_shape = eye(3); 303 | end 304 | K_shape_inv = chiB(qx,qy,qz)*(K_shape\eye(3)); 305 | K11_shape_inv (qx,qy,qz) = K_shape_inv(1,1); 306 | K12_shape_inv (qx,qy,qz) = K_shape_inv(1,2); 307 | K13_shape_inv (qx,qy,qz) = K_shape_inv(1,3); 308 | K21_shape_inv (qx,qy,qz) = K_shape_inv(2,1); 309 | K22_shape_inv (qx,qy,qz) = K_shape_inv(2,2); 310 | K23_shape_inv (qx,qy,qz) = K_shape_inv(2,3); 311 | K31_shape_inv (qx,qy,qz) = K_shape_inv(3,1); 312 | K32_shape_inv (qx,qy,qz) = K_shape_inv(3,2); 313 | K33_shape_inv (qx,qy,qz) = K_shape_inv(3,3); 314 | 315 | end 316 | end 317 | end 318 | end 319 | if run_in_gpu ==1 320 | %make gpuarray 321 | K11_shape_inv = gpuArray(K11_shape_inv); 322 | K12_shape_inv = gpuArray(K12_shape_inv); 323 | K13_shape_inv = gpuArray(K13_shape_inv); 324 | K21_shape_inv = gpuArray(K21_shape_inv); 325 | K22_shape_inv = gpuArray(K22_shape_inv); 326 | K23_shape_inv = gpuArray(K23_shape_inv); 327 | K31_shape_inv = gpuArray(K31_shape_inv); 328 | K32_shape_inv = gpuArray(K32_shape_inv); 329 | K33_shape_inv = gpuArray(K33_shape_inv); 330 | end 331 | 332 | % store K_inv for next time step: 333 | history_var.K_inv11 = K11_shape_inv; 334 | history_var.K_inv12 = K12_shape_inv; 335 | history_var.K_inv13 = K13_shape_inv; 336 | history_var.K_inv21 = K21_shape_inv; 337 | history_var.K_inv22 = K22_shape_inv; 338 | history_var.K_inv23 = K23_shape_inv; 339 | history_var.K_inv31 = K31_shape_inv; 340 | history_var.K_inv32 = K32_shape_inv; 341 | history_var.K_inv33 = K33_shape_inv; 342 | 343 | % compute derormation gradient (Fij) 344 | 345 | F11 = 1 + chiB_lambda.*((-ifftn(chiB_lambda_u1_hat.* A1s_hat,'symmetric') + ... 346 | u1.*chiB_lambda_A1s_hat_invfft).* K11_shape_inv + ... 347 | (-ifftn(chiB_lambda_u1_hat.* A2s_hat,'symmetric') + ... 348 | u1.*chiB_lambda_A2s_hat_invfft).* K21_shape_inv +... 349 | (-ifftn(chiB_lambda_u1_hat.* A3s_hat,'symmetric') + ... 350 | u1.*chiB_lambda_A3s_hat_invfft).* K31_shape_inv)*dv; 351 | 352 | F12 = chiB_lambda.*((-ifftn(chiB_lambda_u1_hat.* A1s_hat,'symmetric') + ... 353 | u1.*chiB_lambda_A1s_hat_invfft).* K12_shape_inv +... 354 | (-ifftn(chiB_lambda_u1_hat.* A2s_hat,'symmetric') + ... 355 | u1.*chiB_lambda_A2s_hat_invfft).* K22_shape_inv +... 356 | (-ifftn(chiB_lambda_u1_hat.* A3s_hat,'symmetric') + ... 357 | u1.*chiB_lambda_A3s_hat_invfft).* K32_shape_inv)*dv; 358 | 359 | F13 = chiB_lambda.*((-ifftn(chiB_lambda_u1_hat.* A1s_hat,'symmetric') + ... 360 | u1.*chiB_lambda_A1s_hat_invfft).* K13_shape_inv +... 361 | (-ifftn(chiB_lambda_u1_hat.* A2s_hat,'symmetric') + ... 362 | u1.*chiB_lambda_A2s_hat_invfft).* K23_shape_inv +... 363 | (-ifftn(chiB_lambda_u1_hat.* A3s_hat,'symmetric') + ... 364 | u1.*chiB_lambda_A3s_hat_invfft).* K33_shape_inv)*dv; 365 | 366 | F21 = chiB_lambda.*((-ifftn(chiB_lambda_u2_hat.* A1s_hat,'symmetric') + ... 367 | u2.*ifftn(A1s_hat.*chiB_lambda_hat,'symmetric')).* K11_shape_inv + ... 368 | (-ifftn(chiB_lambda_u2_hat.* A2s_hat,'symmetric') + ... 369 | u2.*ifftn(A2s_hat.*chiB_lambda_hat,'symmetric')).* K21_shape_inv + ... 370 | (-ifftn(chiB_lambda_u2_hat.* A3s_hat,'symmetric') + ... 371 | u2.*ifftn(A3s_hat.*chiB_lambda_hat,'symmetric')).* K31_shape_inv)*dv; 372 | 373 | F22 = 1 + chiB_lambda.*((-ifftn(chiB_lambda_u2_hat.* A1s_hat,'symmetric') + ... 374 | u2.*chiB_lambda_A1s_hat_invfft).* K12_shape_inv +... 375 | (-ifftn(chiB_lambda_u2_hat.* A2s_hat,'symmetric') + ... 376 | u2.*chiB_lambda_A2s_hat_invfft).* K22_shape_inv+... 377 | (-ifftn(chiB_lambda_u2_hat.* A3s_hat,'symmetric') + ... 378 | u2.*chiB_lambda_A3s_hat_invfft).* K32_shape_inv )*dv; 379 | 380 | 381 | F23 = chiB_lambda.*((-ifftn(chiB_lambda_u2_hat.* A1s_hat,'symmetric') + ... 382 | u2.*chiB_lambda_A1s_hat_invfft).* K13_shape_inv+... 383 | (-ifftn(chiB_lambda_u2_hat.* A2s_hat,'symmetric') + ... 384 | u2.*chiB_lambda_A2s_hat_invfft).* K23_shape_inv +... 385 | (-ifftn(chiB_lambda_u2_hat.* A3s_hat,'symmetric') + ... 386 | u2.*chiB_lambda_A3s_hat_invfft).* K33_shape_inv)*dv; 387 | 388 | 389 | F31 = chiB_lambda.*((-ifftn(chiB_lambda_u3_hat.* A1s_hat,'symmetric') + ... 390 | u3.*chiB_lambda_A1s_hat_invfft).* K11_shape_inv + ... 391 | (-ifftn(chiB_lambda_u3_hat.* A2s_hat,'symmetric') + ... 392 | u3.*chiB_lambda_A2s_hat_invfft).* K21_shape_inv + ... 393 | (-ifftn(chiB_lambda_u3_hat.* A3s_hat,'symmetric') + ... 394 | u3.*chiB_lambda_A3s_hat_invfft).* K31_shape_inv)*dv; 395 | 396 | 397 | F32 = chiB_lambda.*((-ifftn(chiB_lambda_u3_hat.* A1s_hat,'symmetric') + ... 398 | u3.*chiB_lambda_A1s_hat_invfft).* K12_shape_inv + ... 399 | (-ifftn(chiB_lambda_u3_hat.* A2s_hat,'symmetric') + ... 400 | u3.*chiB_lambda_A2s_hat_invfft).* K22_shape_inv +... 401 | (-ifftn(chiB_lambda_u3_hat.* A3s_hat,'symmetric') + ... 402 | u3.*chiB_lambda_A3s_hat_invfft).* K32_shape_inv)*dv; 403 | 404 | 405 | F33 = 1+ chiB_lambda.*((-ifftn(chiB_lambda_u3_hat.* A1s_hat,'symmetric') + ... 406 | u3.*chiB_lambda_A1s_hat_invfft).* K13_shape_inv +... 407 | (-ifftn(chiB_lambda_u3_hat.* A2s_hat,'symmetric') + ... 408 | u3.*chiB_lambda_A2s_hat_invfft).* K23_shape_inv +... 409 | (-ifftn(chiB_lambda_u3_hat.* A3s_hat,'symmetric') + ... 410 | u3.*chiB_lambda_A3s_hat_invfft).* K33_shape_inv)*dv; 411 | 412 | % compute Green strain tensor 413 | green_strain11 = 0.5.*(F11.*F11 + F21.*F21 + F31.*F31 - 1); 414 | green_strain12 = 0.5.*(F11.*F12 + F21.*F22 + F31.*F32 - 0); 415 | green_strain13 = 0.5.*(F11.*F13 + F21.*F23 + F31.*F33 - 0); 416 | green_strain21 = green_strain12; 417 | green_strain22 = 0.5.*(F12.*F12 + F22.*F22 + F32.*F32 - 1); 418 | green_strain23 = 0.5.*(F12.*F13 + F22.*F23 + F32.*F33 - 0); 419 | green_strain31 = green_strain13; 420 | green_strain32 = green_strain23 ; 421 | green_strain33 = 0.5.*(F13.*F13 + F23.*F23 + F33.*F33 - 1); 422 | 423 | % compute second Piola-Kirchhoff stress tensor, Saint Venant-Kirchhoff model 424 | elast_const = K - 2*G/3; 425 | sPK11 = 2*G.*green_strain11 + elast_const.*(green_strain11 + green_strain22 + green_strain33) ; 426 | sPK12 = 2*G.*green_strain12 ; 427 | sPK13 = 2*G.*green_strain13 ; 428 | sPK21 = sPK12 ; 429 | sPK22 = 2*G.*green_strain22 + elast_const.*(green_strain11 +green_strain22 + green_strain33) ; 430 | sPK23 = 2*G.*green_strain23 ; 431 | sPK31 = sPK13 ; 432 | sPK32 = sPK23 ; 433 | sPK33 = 2*G.*green_strain33 + elast_const.*(green_strain11 + green_strain22 + green_strain33) ; 434 | 435 | % compute first Piola-Kirchhoff stress tensor form seecond 436 | % Piola-Kirchhoff PK = F.sPK 437 | PK11 = F11.*sPK11 + F12.*sPK21 +F13.*sPK31; 438 | PK12 = F11.*sPK12 + F12.*sPK22 +F13.*sPK32; 439 | PK13 = F11.*sPK13 + F12.*sPK23 +F13.*sPK33; 440 | 441 | PK21 = F21.*sPK11 + F22.*sPK21 +F23.*sPK31; 442 | PK22 = F21.*sPK12 + F22.*sPK22 +F23.*sPK32; 443 | PK23 = F21.*sPK13 + F22.*sPK23 +F23.*sPK33; 444 | 445 | PK31 = F31.*sPK11 + F32.*sPK21 +F33.*sPK31; 446 | PK32 = F31.*sPK12 + F32.*sPK22 +F33.*sPK32; 447 | PK33 = F31.*sPK13 + F32.*sPK23 +F33.*sPK33; 448 | 449 | % compute internal force density (Li) 450 | L1 = compute_Li(PK11,PK12,PK13, K11_shape_inv, K12_shape_inv, K13_shape_inv, K21_shape_inv,... 451 | K22_shape_inv, K23_shape_inv,K31_shape_inv,K32_shape_inv,K33_shape_inv,... 452 | A1s_hat, A2s_hat, A3s_hat, chiB_lambda,chiB_lambda_u1_hat,omega0s_hat,... 453 | chiB_lambda_hat,F11,F12,F13,A1s_hat,beta_stab,u1,dv, chiB_lambda_A1s_hat_invfft,... 454 | chiB_lambda_A2s_hat_invfft,chiB_lambda_A3s_hat_invfft); 455 | 456 | L2 = compute_Li(PK21,PK22,PK23, K11_shape_inv, K12_shape_inv, K13_shape_inv, K21_shape_inv,... 457 | K22_shape_inv, K23_shape_inv,K31_shape_inv,K32_shape_inv,K33_shape_inv,... 458 | A1s_hat, A2s_hat, A3s_hat, chiB_lambda,chiB_lambda_u2_hat,omega0s_hat,... 459 | chiB_lambda_hat,F21,F22,F23,A2s_hat,beta_stab,u2,dv, chiB_lambda_A1s_hat_invfft,... 460 | chiB_lambda_A2s_hat_invfft,chiB_lambda_A3s_hat_invfft); 461 | 462 | L3 = compute_Li(PK31,PK32,PK33, K11_shape_inv, K12_shape_inv, K13_shape_inv, K21_shape_inv,... 463 | K22_shape_inv, K23_shape_inv,K31_shape_inv,K32_shape_inv,K33_shape_inv,... 464 | A1s_hat, A2s_hat, A3s_hat, chiB_lambda,chiB_lambda_u3_hat,omega0s_hat,... 465 | chiB_lambda_hat,F31,F32,F33,A3s_hat,beta_stab,u3,dv, chiB_lambda_A1s_hat_invfft,... 466 | chiB_lambda_A2s_hat_invfft,chiB_lambda_A3s_hat_invfft); 467 | 468 | %%% strain enegry density (W) 469 | % compute W 470 | W = 0.5*(sPK11.*green_strain11 + sPK12.*green_strain12 + sPK13.*green_strain13 +... 471 | sPK21.*green_strain21 + sPK22.*green_strain22 + sPK23.*green_strain23 + sPK31.*green_strain31 +... 472 | sPK32.*green_strain32 + sPK33.*green_strain33); 473 | 474 | %%% update lambda according to the damage model 475 | G0 = props(3); 476 | 477 | lambda( W >= G0/(2*delta) ) = 0; 478 | history_var.lambda = lambda; 479 | 480 | %%% update damage index 481 | 482 | chiB_hat = fftn(chiB); 483 | numerator = chiB_lambda.*ifftn(chiB_lambda_hat.*omega0s_hat); 484 | denominator = chiB.*ifftn(chiB_hat.*omega0s_hat); 485 | denominator(denominator == 0) = 1; %avoid division by zero 486 | 487 | damage_old = history_var.damage; 488 | damage = 1 - numerator./denominator; 489 | %logical varibale to lable nodes that need to have their K updated 490 | history_var.K_update = (abs(damage - damage_old) > 1e-6); 491 | history_var.damage = damage; 492 | 493 | end 494 | 495 | end 496 | 497 | 498 | 499 | function Li = compute_Li(PK1,PK2,PK3, K11_shape_inv, K12_shape_inv, K13_shape_inv, K21_shape_inv,... 500 | K22_shape_inv, K23_shape_inv,K31_shape_inv,K32_shape_inv,K33_shape_inv,... 501 | A1s_hat, A2s_hat, A3s_hat, chiB_lambda,chiB_lambda_u_hat,omega0s_hat,... 502 | chiB_lambda_hat,F1,F2,F3,As_hat,beta_stab,u,dv, chiB_lambda_A1s_hat_invfft,... 503 | chiB_lambda_A2s_hat_invfft,chiB_lambda_A3s_hat_invfft) 504 | 505 | % This function computes internal force density in i-direction for 506 | % PD-correspondence materials 507 | 508 | % Li1 to Li6 are main components of the force density: 509 | Li1=(PK1.*((K11_shape_inv.*chiB_lambda_A1s_hat_invfft)+... 510 | (K12_shape_inv.*chiB_lambda_A2s_hat_invfft) +... 511 | (K13_shape_inv.*chiB_lambda_A3s_hat_invfft))); 512 | 513 | Li2 = (PK2.*((K21_shape_inv.*chiB_lambda_A1s_hat_invfft)+... 514 | (K22_shape_inv.*chiB_lambda_A2s_hat_invfft) + ... 515 | (K23_shape_inv.*chiB_lambda_A3s_hat_invfft))); 516 | 517 | Li3 = (PK3.*((K31_shape_inv.*chiB_lambda_A1s_hat_invfft)+... 518 | (K32_shape_inv.*chiB_lambda_A2s_hat_invfft) +... 519 | (K33_shape_inv.*chiB_lambda_A3s_hat_invfft))); 520 | 521 | Li4 = ifftn(fftn(chiB_lambda.*(PK1.*... 522 | K11_shape_inv +PK2 .*K21_shape_inv + PK3.*K31_shape_inv))... 523 | .*A1s_hat,'symmetric'); 524 | 525 | Li5 = ifftn(fftn(chiB_lambda.*(PK1.*... 526 | K12_shape_inv +PK2 .*K22_shape_inv + PK3.*K32_shape_inv))... 527 | .*A2s_hat,'symmetric'); 528 | 529 | Li6 = ifftn(fftn(chiB_lambda.*(PK1.*... 530 | K13_shape_inv +PK2 .*K23_shape_inv + PK3.*K33_shape_inv))... 531 | .*A3s_hat,'symmetric'); 532 | 533 | % Li7 to Li9 are components of the stabilizer term 534 | Li7 = -2*ifftn(chiB_lambda_hat.* As_hat,'symmetric')... 535 | -2*u.*ifftn(chiB_lambda_hat.*omega0s_hat,'symmetric') + ... 536 | 2*ifftn(chiB_lambda_u_hat.*omega0s_hat,'symmetric'); 537 | Li8 = F1 .*ifftn(chiB_lambda_hat .* A1s_hat,'symmetric') + F2.*... 538 | ifftn(chiB_lambda_hat .* A2s_hat,'symmetric') + F3.*... 539 | ifftn(chiB_lambda_hat .* A3s_hat,'symmetric'); 540 | Li9 = ifftn(fftn(chiB_lambda.*F1).*A1s_hat, 'symmetric') +... 541 | ifftn(fftn(chiB_lambda.*F2).*A2s_hat, 'symmetric') +... 542 | ifftn(fftn(chiB_lambda.*F3).*A3s_hat, 'symmetric'); 543 | % assemble all components to find force density in i-direction (Li) 544 | Li = (-chiB_lambda.*(Li1 + Li2 + Li3 + Li4 + Li5 +Li6)+... 545 | chiB_lambda.*beta_stab.*(Li7 +Li8+ Li9))*dv; 546 | end 547 | 548 | -------------------------------------------------------------------------------- /PeriFast_Dynamics/create_Matlab_video.m: -------------------------------------------------------------------------------- 1 | % create videos from output data 2 | num_of_outputs = size(outputs_var_for_visualization,2); 3 | 4 | for i = 1:num_of_outputs 5 | out_var = outputs_var_for_visualization(1,i); 6 | 7 | if out_var == 1 8 | frame = getframe(figure(i)); 9 | writeVideo(u1_video,frame); 10 | end 11 | if out_var == 2 12 | frame = getframe(figure(i)); 13 | writeVideo(u2_video,frame); 14 | end 15 | if out_var == 3 16 | frame = getframe(figure(i)); 17 | writeVideo(u3_video,frame); 18 | end 19 | if out_var == 4 20 | frame = getframe(figure(i)); 21 | writeVideo(u_mag_video,frame); 22 | end 23 | if out_var == 5 24 | frame = getframe(figure(i)); 25 | writeVideo(v1_video,frame); 26 | end 27 | if out_var == 6 28 | frame = getframe(figure(i)); 29 | writeVideo(v2_video,frame); 30 | 31 | end 32 | if out_var == 7 33 | frame = getframe(figure(i)); 34 | writeVideo(v3_video,frame); 35 | end 36 | 37 | if out_var == 8 38 | frame = getframe(figure(i)); 39 | writeVideo(v_mag_video,frame); 40 | end 41 | if out_var == 9 42 | frame = getframe(figure(i)); 43 | writeVideo(W_video,frame); 44 | end 45 | if out_var == 10 46 | frame = getframe(figure(i)); 47 | writeVideo(d_video,frame); 48 | 49 | end 50 | if out_var == 11 51 | frame = getframe(figure(i)); 52 | writeVideo(lambda_video,frame); 53 | end 54 | 55 | 56 | end -------------------------------------------------------------------------------- /PeriFast_Dynamics/dump_output.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This module gets the snapshot number (ks), displacements and velocities 3 | % in x, y, and z directions, strain energy density, damage index, and lambda 4 | % as inputs, and stores them in a single “structure”-type MATLAB 5 | % variable named Output. if tecplot_output ==1 in inputs.m, the selected 6 | % outputs are saved in tecplot file. 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | % user can add any desired quantity to the "Output" varibale 10 | Output(ks).u1 = u1; % displacement in x-direction 11 | Output(ks).u2 = u2; % displacement in y-direction 12 | Output(ks).u3 = u3; % displacement in z-direction 13 | Output(ks).u_mag = sqrt(u1.^2 + u2.^2 + u3.^2); % discplement magnitude 14 | Output(ks).v1 = v1; % velocity in x-direction 15 | Output(ks).v2 = v2; % velocity in y-direction 16 | Output(ks).v3 = v3; % velocity in z-direction 17 | Output(ks).v_mag = sqrt(v1.^2 + v2.^2 + v3.^2); % velocity magnitude 18 | Output(ks).W = W; % strain energy density 19 | Output(ks).d = history_var.damage; % damage index 20 | Output(ks).lambda = history_var.lambda; % lambda 21 | 22 | if (run_in_gpu ==1) 23 | Output(ks).u1 = real(gather(Output(ks).u1)); 24 | Output(ks).u2 = real(gather(Output(ks).u2)); 25 | Output(ks).u3 = real(gather(Output(ks).u3)); 26 | Output(ks).u_mag = real(gather(Output(ks).u_mag)); 27 | Output(ks).v1 = real(gather(Output(ks).v1)); 28 | Output(ks).v2= real(gather(Output(ks).v2)); 29 | Output(ks).v3= real(gather(Output(ks).v3)); 30 | Output(ks).v_mag = real(gather(Output(ks).v_mag)); 31 | Output(ks).W = real(gather(Output(ks).W)); 32 | Output(ks).d = real(gather(Output(ks).d)); 33 | Output(ks).lambda = real(gather(Output(ks).lambda)); 34 | chiB = gather(chiB); 35 | end 36 | 37 | % if user wants to have output as tecplot file (tecplot_output ==1 in inputs.m) 38 | % create techplot for damage results 39 | if (tecplot_output == 1) 40 | chiB_lambda = chiB.*(Output(ks).lambda); 41 | plot_nodes = logical(chiB_lambda);% nodes that belong to the main body 42 | 43 | % output selection for plots 44 | u1_plot = Output(ks).u1(plot_nodes); % displacement in x- direction 45 | u2_plot = Output(ks).u2(plot_nodes); % displacement in y- direction 46 | u3_plot = Output(ks).u3(plot_nodes); % displacement in z- direction 47 | x_plot = X(plot_nodes); % coorniates of nodes in x-direction 48 | y_plot = Y(plot_nodes); % coorniates of nodes in y-direction 49 | z_plot = Z(plot_nodes); % coorniates of nodes in z-direction 50 | 51 | % nodal coordinates in current configurartion 52 | xcur_plot = x_plot + u1_plot; 53 | ycur_plot = y_plot + u2_plot; 54 | zcur_plot = z_plot + u3_plot; 55 | % create tecplot file for selected outputs 56 | damage_plot = Output(ks).d(plot_nodes); % damage index 57 | A=[xcur_plot(:)';ycur_plot(:)';zcur_plot(:)';damage_plot(:)']; 58 | fprintf(fileID1, '%14s\r\r\n','ZONE F=POINT'); 59 | fprintf(fileID1,'%12.8f %12.8f %12.8f %12.8f\r\n',A); 60 | end 61 | -------------------------------------------------------------------------------- /PeriFast_Dynamics/initial_gpu_arrays.m: -------------------------------------------------------------------------------- 1 | %make gpuarrays in order to run on gpu 2 | mat_type = props(1); 3 | chiB = gpuArray(chiB); 4 | chiOx = gpuArray(chiOx); 5 | chiOy = gpuArray(chiOy); 6 | chiOz = gpuArray(chiOz); 7 | chi_predam = gpuArray(chi_predam); 8 | lambda0 = gpuArray(lambda0); 9 | u1 = gpuArray(u1); u2= gpuArray(u2); u3 = gpuArray(u3); 10 | history_var.lambda = gpuArray(history_var.lambda); 11 | if (mat_type ==1 || mat_type ==2) 12 | constit_invar.A1s_hat = gpuArray(constit_invar.A1s_hat); 13 | constit_invar.A2s_hat = gpuArray(constit_invar.A2s_hat); 14 | constit_invar.A3s_hat = gpuArray(constit_invar.A3s_hat); 15 | end 16 | constit_invar.C11s_hat = gpuArray(constit_invar.C11s_hat); 17 | constit_invar.C12s_hat = gpuArray(constit_invar.C12s_hat); 18 | constit_invar.C13s_hat = gpuArray(constit_invar.C13s_hat); 19 | constit_invar.C22s_hat = gpuArray(constit_invar.C22s_hat); 20 | constit_invar.C23s_hat = gpuArray(constit_invar.C23s_hat); 21 | constit_invar.C33s_hat = gpuArray(constit_invar.C33s_hat); 22 | constit_invar.omega0s_hat = gpuArray(constit_invar.omega0s_hat); 23 | if (mat_type ==1) 24 | constit_invar.m_kernels_hat = gpuArray(constit_invar.m_kernels_hat); 25 | end 26 | L1 = gpuArray (L1); L2 = gpuArray (L2); L3 = gpuArray (L3); -------------------------------------------------------------------------------- /PeriFast_Dynamics/inputs.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % this module contains certain input data including material properties, 3 | % simulation time, time steps, initial and boundary conditions 4 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5 | 6 | % Physical inputs: 7 | props = [0; 2440; 3.8; 72e9; 0.25]; % material properties 8 | % props (1): mat_type (0:BB, 1: Linearized SB, 2: correspondence SB) 9 | % props (2): rho(density) , unit in kg/m^3 10 | % props (3): G0 (fracture energy release rate), unit in J/m^2 11 | % props (4): E (Young's modulus), unit in Pa 12 | % props (5): nu (Poisson ratio if not bond-based) 13 | 14 | t_max = 33e-6; % maximum time, unit in s 15 | % safty check for t_max 16 | if(t_max <= 0) 17 | error('t_max must be a positive number'); 18 | end 19 | dt = 5e-8; % time step (should satisfy the stability condition), unit in s 20 | %safty check for dt 21 | if(dt > t_max) 22 | error('dt can not large than the total time'); 23 | end 24 | 25 | number_of_data_dump = 100; % % number of data dumps 26 | number_of_visualization_frames = 30; % number of frames for visualization,this number should be less than number of data dump 27 | 28 | run_in_gpu = 0; % run in gpu:1, do not run in gpu:0; 29 | 30 | % output parameters 31 | 32 | tecplot_output = 0 ; % provide tecplot file :1, Do not provide tecplot file:0 33 | 34 | % visualization parameter 35 | visualization_during_analysis = 0 ; % Matlab plot/animate output during analysis:1, Do not plot/animate:0 36 | % user can choose outputs for vizualization 37 | outputs_var_for_visualization = [10]; % want to visualize d from outputs 38 | %the outputs defined in this version is: 39 | % 1: u1, 2: u2, 3: u3, 4: u_mag 40 | % 5: v1, 6: v2, 7: v3, 8: v_mag 41 | % 9: W, 10: d, 11: lambda 42 | % user can add extra output for visualization by first defining in 43 | % dump_output.m and modify the visualization.m,open_Matlab_video.m, create_Matlab_video.m and close_Matlab_video.m 44 | 45 | 46 | %%% Body force density functions: 47 | Fb(1).func = @(x,y,z,t)0; 48 | Fb(2).func = @(x,y,z,t)0; 49 | Fb(3).func = @(x,y,z,t)0; 50 | 51 | %%% Initial condition functions: 52 | IC_u(1).func = @(x,y,z)0; 53 | IC_u(2).func = @(x,y,z)0; 54 | IC_u(3).func = @(x,y,z)0; 55 | IC_v(1).func = @(x,y,z)0; 56 | IC_v(2).func = @(x,y,z)0; 57 | IC_v(3).func = @(x,y,z)0; 58 | 59 | 60 | %%% Boundary Conditions 61 | 62 | % tractions: 63 | % in x 64 | trac_x.No = 0;% number of tractions in x 65 | % in y 66 | trac_y.No = 2;% number of tractions in y 67 | trac_y(1).func = @(x,y,z,t) 4e6;% value (can be space/time dependent) 68 | trac_y(2).func = @(x,y,z,t) -4e6; % 69 | % in z 70 | trac_z.No = 0;% number of tractions in z 71 | 72 | % displacements 73 | % in x 74 | dispBC_x.No = 0;% number of tractions in x 75 | % in y 76 | dispBC_y.No = 0;% number of tractions in y 77 | % in z 78 | dispBC_z.No = 0;% number of tractions in z 79 | -------------------------------------------------------------------------------- /PeriFast_Dynamics/main.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % ________ __________________ _________________________ ________________ % 3 | % ___ __ \___ ____/___ __ \____ _/___ ____/___ |__ ___/___ __/ % 4 | % __ /_/ /__ __/ __ /_/ / __ / __ /_ __ /| |_____ \ __ / % 5 | % _ ____/ _ /___ _ _, _/ __/ / _ __/ _ ___ |____/ / _ / % 6 | % /_/ /_____/ /_/ |_| /___/ /_/ /_/ |_|/____/ /_/ % 7 | % % 8 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9 | 10 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11 | % This code solves 3D defromation and fracture problems with peridynamic(uniform) 12 | % models discretized using the Fast Convolution-Based Method (FCBM) 13 | % Detailed description of the code can be found in: 14 | % 'PeriFast/Dynamics: a MATLAB code for explicit fast convolution-based 15 | % peridynamic analysis of deformation and fracture' 16 | % By: Siavash Jafarzadeh, Farzaneh Mousavi and Florin Bobaru 17 | %see https://doi.org/10.21203/rs.3.rs-2019917/v1 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | 20 | clear; clc; 21 | % (For multithreaded computation, uncomment the command below, and give the 22 | % maximum number of computational threads you want to use in parentheses): 23 | LASTN = maxNumCompThreads(1); 24 | 25 | % Get inputs 26 | inputs; 27 | 28 | % Get nodes and sets 29 | [delta,Box_T,Nx,Ny,Nz,X,Y,Z,dv,chiB,chit_x,chit_y,chit_z,chiG_x,chiG_y,... 30 | chiG_z,chi_predam,chiOx,chiOy,chiOz,dy] = nodes_and_sets(props,dt); 31 | 32 | % Construct constitutive invariants 33 | constit_invar = pre_constitutive(props,delta,X,Y,Z,Box_T); 34 | 35 | % Assign initial conditions 36 | u1_0 = IC_u(1).func(X,Y,Z); 37 | u2_0 = IC_u(2).func(X,Y,Z); 38 | u3_0 = IC_u(3).func(X,Y,Z); 39 | v1_0 = IC_v(1).func(X,Y,Z); 40 | v2_0 = IC_v(2).func(X,Y,Z); 41 | v3_0 = IC_v(3).func(X,Y,Z); 42 | 43 | % Assign lambda0 (pre-damage) 44 | lambda0 = 1 - chi_predam; 45 | history_var.lambda = lambda0; 46 | 47 | % Compute initial internal forces, tractions, and body forces at t=0 48 | u1 = u1_0; u2 = u2_0; u3 = u3_0; 49 | v1 = v1_0; v2 = v2_0; v3 = v3_0; 50 | t = 0; history_var.t = t; 51 | update_tractions; 52 | Fbx = Fb(1).func(X,Y,Z,t); 53 | Fby = Fb(2).func(X,Y,Z,t); 54 | Fbz = Fb(3).func(X,Y,Z,t); 55 | [L1, L2, L3, W, history_var] = constitutive(props,u1,u2,u3,history_var,delta,... 56 | constit_invar,chiB,dv, Nx,Ny,Nz, run_in_gpu); 57 | rho = props(2); 58 | 59 | k = 1;% time step counter 60 | total_time_step = round(t_max/dt); 61 | snap = round(total_time_step/number_of_data_dump); % number of steps between snapshots for dumping output data 62 | snap_frame = round(total_time_step/number_of_visualization_frames); 63 | ks = 1;% snapshot counter 64 | Output = struct;% struct varibale to record output data 65 | 66 | %generate output movie 67 | if (visualization_during_analysis == 1) 68 | open_Matlab_video; 69 | end 70 | if (run_in_gpu==1) 71 | initial_gpu_arrays; 72 | end 73 | % open tecplot file if user chooses to save output as .plt file 74 | if (tecplot_output == 1) 75 | fileID1 = fopen('Results.plt','a'); 76 | fprintf(fileID1,'%6s %6s %6s %12s\r\n','x','y','z','damage'); 77 | end 78 | 79 | tic 80 | for t = dt:dt:t_max % t is the current time 81 | 82 | history_var.t = t; 83 | 84 | % Compute volume constraints 85 | update_VC; 86 | 87 | % Update u(x,y,z,t) 88 | u1 = chiOx.*(u1 + dt*(v1 + (dt/2/rho)*(L1 + btx + Fbx))) + wx; 89 | u2 = chiOy.*(u2 + dt*(v2 + (dt/2/rho)*(L2 + bty + Fby))) + wy; 90 | u3 = chiOz.*(u3 + dt*(v3 + (dt/2/rho)*(L3 + btz + Fbz))) + wz; 91 | 92 | % Store old values for velocity-verlet before updating 93 | L1_old = L1; btx_old = btx; Fbx_old = Fbx; 94 | L2_old = L2; bty_old = bty; Fby_old = Fby; 95 | L3_old = L3; btz_old = btz; Fbz_old = Fbz; 96 | 97 | % Update internal forces, damage, body forces, and BC 98 | 99 | [L1, L2, L3, W, history_var] = constitutive(props,u1,u2,u3,history_var,delta,... 100 | constit_invar,chiB,dv, Nx,Ny,Nz, run_in_gpu); 101 | 102 | update_tractions; 103 | 104 | Fbx = Fb(1).func(X,Y,Z,t); 105 | Fby = Fb(2).func(X,Y,Z,t); 106 | Fbz = Fb(3).func(X,Y,Z,t); 107 | 108 | % update velocity 109 | v1 = chiOx.*(v1 + (dt/2/rho)*((L1_old + btx_old + Fbx_old)+... 110 | (L1 + btx + Fbx))); 111 | v2 = chiOy.*(v2 + (dt/2/rho)*((L2_old + bty_old + Fby_old)+... 112 | (L2 + bty + Fby))); 113 | v3 = chiOz.*(v3 + (dt/2/rho)*((L3_old + btz_old + Fbz_old)+... 114 | (L3 + btz + Fbz))); 115 | 116 | % Dump output (snapshots) 117 | if (mod(round(t/dt),snap) == 0 || t == t_max) 118 | fprintf('time step: %d out of %i\n',k,total_time_step); 119 | 120 | % Dump data in the struct variable: Output 121 | fprintf('...dumping output...\n'); 122 | dump_output; 123 | % Visualization (snapshots) 124 | if (visualization_during_analysis == 1 && (mod(round(t/dt), round(snap_frame/snap))==0 || t == t_max)) 125 | fprintf('...plotting...\n'); 126 | visualization; 127 | end 128 | 129 | ks = ks + 1; 130 | end 131 | 132 | k = k + 1; 133 | 134 | end 135 | toc 136 | fprintf('***** ANALYSIS COMPLETED *****\n'); 137 | 138 | % close the video in the case it creates movie from the snapshots during 139 | % analysis 140 | if ( visualization_during_analysis == 1) 141 | close_Matlab_video 142 | end 143 | 144 | % close tecplot file if it creates tecplot file 145 | if (tecplot_output == 1) 146 | fclose(fileID1); 147 | end 148 | 149 | % save outputs to Results.mat file: 150 | fprintf('...saving results to file...\n'); 151 | save('Results.mat','Output','X','Y','Z','t','chiB','outputs_var_for_visualization',... 152 | 'snap_frame','snap','dt','-v7.3') 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /PeriFast_Dynamics/nodes_and_sets.m: -------------------------------------------------------------------------------- 1 | function [delta,Box_T,Nx,Ny,Nz,X,Y,Z,dv,chiB,chit_x,chit_y,chit_z,... 2 | chiG_x,chiG_y,chiG_z,chi_predam,chiOx,chiOy,chiOz,dy]... 3 | = nodes_and_sets(props,dt) 4 | % this function contains the PD horizon and discrete geometrical data 5 | % including nodal coordinates and characteristic functions that define 6 | % various subdomains: the original body,constrained volumes, 7 | % pre-damaged regions, and subregions where tractions applied as body forces 8 | 9 | delta = 1.02e-3; % horizon size 10 | 11 | E = props(4); 12 | rho = props(2); 13 | beta= sqrt(rho*delta^2/(12*E)); 14 | 15 | % define enclosing box 16 | x_min = 0; x_max = 0.1; 17 | y_min = 0; y_max = 0.04; 18 | z_min = 0; z_max = 0.002; 19 | 20 | Ldx = x_max - x_min; % fitted_box - x dimension 21 | Ldy = y_max - y_min; % fitted_box - y dimension 22 | Ldz = z_max - z_min; % fitted_box - z dimension 23 | 24 | 25 | 26 | % define number of nodes in each direction 27 | Nx = 510; % resolution in x (Best for FFT to use a power of 2) 28 | Ny = 210; % resolution in y 29 | Nz = 20; % resolution in z 30 | % Nx = 256; % resolution in x (Best for FFT to use a power of 2) 31 | % Ny = 106; % resolution in y 32 | % Nz = 10; % resolution in z 33 | 34 | % Extend the fitted box to the periodic domain (T) by (m+1)dx on both sides 35 | extension = 2e-3; % extension must be larger than delta 36 | 37 | x_min_T = x_min; 38 | x_max_T = x_max + extension; 39 | y_min_T = y_min; 40 | y_max_T = y_max + extension; 41 | z_min_T = z_min; 42 | z_max_T = z_max + extension; 43 | 44 | % Box T dimensions 45 | Lx_T = x_max_T - x_min_T; 46 | Ly_T = y_max_T - y_min_T; 47 | Lz_T = z_max_T - z_min_T; 48 | 49 | % store box info for adjusting kernel functions 50 | Box_T.xmin = x_min_T; Box_T.xmax = x_max_T; Box_T.Lx = Lx_T; 51 | Box_T.ymin = y_min_T; Box_T.ymax = y_max_T; Box_T.Ly = Ly_T; 52 | Box_T.zmin = z_min_T; Box_T.zmax = z_max_T; Box_T.Lz = Lz_T; 53 | 54 | % grid spacing 55 | dx = Lx_T/Nx; 56 | dy = Ly_T/Ny; 57 | dz = Lz_T/Nz; 58 | 59 | Box_T.dx = dx; Box_T.dy = dy; Box_T.dz = dz; 60 | x = (x_min_T + (0:Nx - 1)*dx)'; 61 | y = (y_min_T + (0:Ny - 1)*dy)'; 62 | z = (z_min_T + (0:Nz - 1)*dz)'; 63 | [X,Y,Z] = meshgrid(x,y,z); 64 | dv = dx*dy*dz; 65 | 66 | % check discritization 67 | discretization_check(delta,Nx,Ny,Nz,dx,dy,dz,Ldx,Ldy,Ldz,beta,dt); 68 | 69 | % Construct Mask functions (ChiB): defines the body configuration 70 | chiB = double(X >= x_min & X <= x_max & Y >= y_min & Y <= y_max &... 71 | Z >= z_min & Z <= z_max); 72 | 73 | % boundary layers mask function for applying tractions:chib 74 | % in x 75 | chit_x.No = 0;% number of tractions in x 76 | % in y 77 | chit_y.No = 2;% number of tractions in y 78 | chit_y(1).set = double(chiB == 1 & Y > y_max - delta + dy/2 & Y < y_max + dy/2); 79 | chit_y(2).set = double(chiB == 1 & Y > y_min - dy/2 & Y < y_min + delta - dy/2); 80 | % in z 81 | chit_z.No = 0;% number of tractions in z 82 | 83 | 84 | % boundary layers mask function for applying displacements:chiG 85 | % in x 86 | chiG_x.No = 0;% number of tractions in x 87 | % in y 88 | chiG_y.No = 0;% number of tractions in y 89 | % in z 90 | chiG_z.No = 0;% number of tractions in z 91 | 92 | % pre-damage set : 93 | chi_predam = double(chiB == 1 & abs(Y - y_min - Ldy/2)<= (delta/2) &... 94 | X < x_min + Ldx/2); 95 | 96 | % assemble chi_gamma for boundaries 97 | chiGx = assemble_chi(chiG_x,Nx,Ny,Nz); 98 | chiGy = assemble_chi(chiG_y,Nx,Ny,Nz); 99 | chiGz = assemble_chi(chiG_z,Nx,Ny,Nz); 100 | chiOx = chiB - chiGx; 101 | chiOy = chiB - chiGy; 102 | chiOz = chiB - chiGz; 103 | 104 | end 105 | 106 | % function to assemble chi_gamma for volume contraints pretaining to each 107 | % coordinate direction 108 | function chi_total = assemble_chi (chi,Nx,Ny,Nz) 109 | chi_total = zeros(Ny,Nx,Nz); 110 | n = chi.No; 111 | for i = 1: n(1) 112 | chi_total = chi_total + chi(i).set; 113 | end 114 | end 115 | 116 | function discretization_check(delta,Nx, Ny,Nz,dx,dy,dz,Ldx,Ldy,Ldz,beta,dt) 117 | % safty check fo horizon size 118 | if(delta <= 0) 119 | error('delta must be a positive number'); 120 | end 121 | 122 | % safty check for physical domain size 123 | if(delta >= Ldx) 124 | warning('delta is larger than physical domain length in x direction, choose a smaller horizon'); 125 | end 126 | % safty check for number of nodes (need to be an even number in curent 127 | % version of code) 128 | if(mod(Nx,2)== 1 || mod(Ny,2)== 1 ||mod(Nz,2)==1) 129 | error('number of nodes are not even, try even numbers for Nx, Ny and Nz'); 130 | end 131 | if(delta >= Ldy) 132 | warning('delta is larger than physical domain length in y direction, choose a smaller horizon'); 133 | end 134 | if(delta >= Ldz) 135 | warning('delta is larger than physical domain length in z direction, choose a smaller horizon'); 136 | end 137 | % safty check for m-value factor 138 | if(delta/dx < 3 || delta/dy < 3 || delta/dz < 3) 139 | warning('m-value is less than 3, make discritization finer'); 140 | end 141 | if(delta/dx - floor(delta/dx) < 1e-6 || delta/dy - floor(delta/dy) < 1e-6 || delta/dz - floor(delta/dz) < 1e-6) 142 | error('m-value is integer, multiply delta by 1.02'); 143 | end 144 | 145 | if dt > beta 146 | warning('dt may not meet the stability condition. If user notice unstable results, set dt less than %d',beta); 147 | end 148 | end 149 | -------------------------------------------------------------------------------- /PeriFast_Dynamics/open_Matlab_video.m: -------------------------------------------------------------------------------- 1 | % open videos 2 | num_of_outputs = size(outputs_var_for_visualization,2); 3 | 4 | for i = 1:num_of_outputs 5 | out_var = outputs_var_for_visualization(1,i); 6 | outFilename = sprintf('out%d.mp4', i); 7 | if out_var == 1 8 | u1_video = VideoWriter(outFilename,'MPEG-4'); 9 | open(u1_video); 10 | end 11 | if out_var == 2 12 | u2_video = VideoWriter(outFilename,'MPEG-4'); 13 | open(u2_video); 14 | end 15 | if out_var == 3 16 | u3_video = VideoWriter(outFilename,'MPEG-4'); 17 | open(u3_video); 18 | end 19 | if out_var == 4 20 | u_mag_video = VideoWriter(outFilename,'MPEG-4'); 21 | open(u_mag_video); 22 | end 23 | if out_var == 5 24 | v1_video = VideoWriter(outFilename,'MPEG-4'); 25 | open(v1_video); 26 | end 27 | if out_var == 6 28 | v2_video = VideoWriter(outFilename,'MPEG-4'); 29 | open(v2_video); 30 | 31 | end 32 | if out_var == 7 33 | v3_video = VideoWriter(outFilename,'MPEG-4'); 34 | open(v3_video); 35 | end 36 | 37 | if out_var == 8 38 | v_mag = VideoWriter(outFilename,'MPEG-4'); 39 | open(v_mag); 40 | end 41 | if out_var == 9 42 | W_video = VideoWriter(outFilename,'MPEG-4'); 43 | open(W_video); 44 | 45 | end 46 | if out_var == 10 47 | d_video = VideoWriter(outFilename,'MPEG-4'); 48 | open(d_video); 49 | 50 | end 51 | if out_var == 11 52 | lambda_video = VideoWriter(outFilename,'MPEG-4'); 53 | open(lambda_video); 54 | end 55 | 56 | 57 | end 58 | -------------------------------------------------------------------------------- /PeriFast_Dynamics/postprocess.m: -------------------------------------------------------------------------------- 1 | %user can use this script to postprocess the stored matlab data 2 | load('Results.mat'); 3 | output_size = size(Output,2); 4 | open_Matlab_video; 5 | No_snapshots = output_size; 6 | for ks = 1:output_size 7 | if (mod(ks,round(snap_frame/snap))==0 || ks == output_size) 8 | visualization; 9 | end 10 | end 11 | close_Matlab_video -------------------------------------------------------------------------------- /PeriFast_Dynamics/pre_constitutive.m: -------------------------------------------------------------------------------- 1 | function constit_invar = pre_constitutive(props,delta,X,Y,Z,Box_T) 2 | % this function contains the time-invariant components of the PD constitutive 3 | % models 4 | 5 | mat_type = props(1); 6 | 7 | %%% Get box coordinates 8 | x_min_T = Box_T.xmin; Lx_T = Box_T.Lx; 9 | y_min_T = Box_T.ymin; Ly_T = Box_T.Ly; 10 | z_min_T = Box_T.zmin; Lz_T = Box_T.Lz; 11 | 12 | x_c = x_min_T + Lx_T/2; 13 | y_c = y_min_T + Ly_T/2; 14 | z_c = z_min_T + Lz_T/2; 15 | 16 | if mat_type == 0 % linearized bond-based micro-elastic solid 17 | 18 | E = props(4);% Young modulus 19 | const = 12*E/(pi*delta^4);% material constant (micromodulus) 20 | 21 | % define omega0 which is one in horizon and zero elsewhere 22 | omega0 = @(X,Y,Z) (sqrt(X.^2 + Y.^2 + Z.^2) <= delta); 23 | 24 | % adjust kernel functions on the periodic box T 25 | omega0s = fftshift(omega0(X - x_c, Y - y_c, Z - z_c)); 26 | % compute DFT 27 | constit_invar.omega0s_hat = fftn(omega0s); 28 | 29 | % define elements of tensor-state C: 30 | C11 = @(X,Y,Z) (const*X.*X./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0)).^(3/2)).*(sqrt(X.^2 + Y.^2 + Z.^2) <= delta); 31 | C12 = @(X,Y,Z) (const*X.*Y./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0)).^(3/2)).*(sqrt(X.^2 + Y.^2 + Z.^2) <= delta); 32 | C13 = @(X,Y,Z) (const*X.*Z./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0)).^(3/2)).*(sqrt(X.^2 + Y.^2 + Z.^2) <= delta); 33 | C22 = @(X,Y,Z) (const*Y.*Y./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0)).^(3/2)).*(sqrt(X.^2 + Y.^2 + Z.^2) <= delta); 34 | C23 = @(X,Y,Z) (const*Y.*Z./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0)).^(3/2)).*(sqrt(X.^2 + Y.^2 + Z.^2) <= delta); 35 | C33 = @(X,Y,Z) (const*Z.*Z./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0)).^(3/2)).*(sqrt(X.^2 + Y.^2 + Z.^2) <= delta); 36 | 37 | % adjust kernel functions on the periodic box T 38 | C11s = fftshift(C11(X - x_c, Y - y_c, Z - z_c)); 39 | C12s = fftshift(C12(X - x_c, Y - y_c, Z - z_c)); 40 | C13s = fftshift(C13(X - x_c, Y - y_c, Z - z_c)); 41 | C22s = fftshift(C22(X - x_c, Y - y_c, Z - z_c)); 42 | C23s = fftshift(C23(X - x_c, Y - y_c, Z - z_c)); 43 | C33s = fftshift(C33(X - x_c, Y - y_c, Z - z_c)); 44 | 45 | 46 | % compute DFT 47 | constit_invar.C11s_hat = fftn(C11s); constit_invar.C12s_hat = fftn(C12s); 48 | constit_invar.C13s_hat = fftn(C13s); constit_invar.C22s_hat = fftn(C22s); 49 | constit_invar.C23s_hat = fftn(C23s); constit_invar.C33s_hat = fftn(C33s); 50 | % C21,C31, and C32 are not needed due to symmetry 51 | 52 | 53 | end 54 | 55 | if mat_type == 1 % linearized state-based 56 | E = props(4);% Young modulus 57 | nu = props (5);% Poisson ratio 58 | G = E/(2*(1 + nu)); % shear modulus 59 | 60 | const = 30*G;% material constant 61 | %%% define omega0 which is the influnece function 62 | omega0 = @(X,Y,Z)(1./sqrt(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0)))... 63 | .*(sqrt(X.^2 + Y.^2 + Z.^2) <= delta & X.^2 + Y.^2 + Z.^2 ~= 0); 64 | 65 | % adjust kernel functions on the periodic box T 66 | omega0s = fftshift(omega0(X - x_c, Y - y_c, Z - z_c)); 67 | % compute DFT 68 | constit_invar.omega0s_hat = fftn(omega0s); 69 | % weighted volume (m) 70 | m_kernel = @(X,Y,Z) omega0(X,Y,Z).*(X.^2 + Y.^2 + Z.^2); 71 | % adjust weighted volume function on the periodic box T and compute DFT 72 | m_kernels = fftshift(m_kernel(X - x_c, Y - y_c, Z - z_c)); 73 | constit_invar.m_kernels_hat = fftn(m_kernels); 74 | 75 | %%% define vector-state A: 76 | 77 | A1 = @(X,Y,Z) omega0(X,Y,Z) .* X; 78 | A2 = @(X,Y,Z) omega0(X,Y,Z) .* Y; 79 | A3 = @(X,Y,Z) omega0(X,Y,Z) .* Z; 80 | % adjust kernel functions on the periodic box T 81 | A1s = fftshift(A1(X - x_c, Y - y_c, Z - z_c)); 82 | A2s = fftshift(A2(X - x_c, Y - y_c, Z - z_c)); 83 | A3s = fftshift(A3(X - x_c, Y - y_c, Z - z_c)); 84 | % compute DFT 85 | constit_invar.A1s_hat = fftn(A1s); constit_invar.A2s_hat = fftn(A2s); constit_invar.A3s_hat = fftn(A3s); 86 | 87 | %%% define tensor-state C: 88 | % functions 89 | C11 = @(X,Y,Z) (const*omega0(X,Y,Z).*X.*X./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0))); 90 | C12 = @(X,Y,Z) (const*omega0(X,Y,Z).*X.*Y./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0))); 91 | C13 = @(X,Y,Z) (const*omega0(X,Y,Z).*X.*Z./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0))); 92 | C22 = @(X,Y,Z) (const*omega0(X,Y,Z).*Y.*Y./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0))); 93 | C23 = @(X,Y,Z) (const*omega0(X,Y,Z).*Y.*Z./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0))); 94 | C33 = @(X,Y,Z) (const*omega0(X,Y,Z).*Z.*Z./(X.^2 + Y.^2 + Z.^2 + (X.^2 + Y.^2 + Z.^2 == 0))); 95 | 96 | % adjust kernel functions on the periodic box T 97 | C11s = fftshift(C11(X - x_c, Y - y_c, Z - z_c)); 98 | C12s = fftshift(C12(X - x_c, Y - y_c, Z - z_c)); 99 | C13s = fftshift(C13(X - x_c, Y - y_c, Z - z_c)); 100 | C22s = fftshift(C22(X - x_c, Y - y_c, Z - z_c)); 101 | C23s = fftshift(C23(X - x_c, Y - y_c, Z - z_c)); 102 | C33s = fftshift(C33(X - x_c, Y - y_c, Z - z_c)); 103 | % compute DFT 104 | constit_invar.C11s_hat = fftn(C11s); constit_invar.C12s_hat = fftn(C12s); 105 | constit_invar.C13s_hat = fftn(C13s); constit_invar.C22s_hat = fftn(C22s); 106 | constit_invar.C23s_hat = fftn(C23s); constit_invar.C33s_hat = fftn(C33s); 107 | % C21,C31, and C32 are not needed due to symmetry 108 | 109 | end 110 | 111 | if mat_type == 2 % PD-corresspondence model 112 | 113 | %%% define omega0 which is the influence function for this material 114 | omega0 = @(X,Y,Z)(1).*(sqrt(X.^2 + Y.^2 + Z.^2) <= delta & X.^2 + Y.^2 + Z.^2 ~= 0); 115 | % adjust kernel functions on the periodic box T 116 | omega0s = fftshift(omega0(X - x_c, Y - y_c, Z - z_c)); 117 | % compute DFT 118 | constit_invar.omega0s_hat = fftn(omega0s); 119 | 120 | %%% define vector-state A: 121 | A1 = @(X,Y,Z) omega0(X,Y,Z) .* X; 122 | A2 = @(X,Y,Z) omega0(X,Y,Z) .* Y; 123 | A3 = @(X,Y,Z) omega0(X,Y,Z) .* Z; 124 | 125 | % adjust kernel functions on the periodic box T 126 | A1s = fftshift(A1(X - x_c, Y - y_c, Z - z_c)); 127 | A2s = fftshift(A2(X - x_c, Y - y_c, Z - z_c)); 128 | A3s = fftshift(A3(X - x_c, Y - y_c, Z - z_c)); 129 | % compute DFT 130 | constit_invar.A1s_hat = fftn(A1s); constit_invar.A2s_hat = fftn(A2s); constit_invar.A3s_hat = fftn(A3s); 131 | 132 | %%% define tensor-state C: 133 | C11 = @(X,Y,Z) (omega0(X,Y,Z).*X.*X); 134 | C12 = @(X,Y,Z) (omega0(X,Y,Z).*X.*Y); 135 | C13 = @(X,Y,Z) (omega0(X,Y,Z).*X.*Z); 136 | C22 = @(X,Y,Z) (omega0(X,Y,Z).*Y.*Y); 137 | C23 = @(X,Y,Z) (omega0(X,Y,Z).*Y.*Z); 138 | C33 = @(X,Y,Z) (omega0(X,Y,Z).*Z.*Z); 139 | 140 | % adjust kernel functions on the periodic box T 141 | C11s = fftshift(C11(X - x_c, Y - y_c, Z - z_c)); 142 | C12s = fftshift(C12(X - x_c, Y - y_c, Z - z_c)); 143 | C13s = fftshift(C13(X - x_c, Y - y_c, Z - z_c)); 144 | C22s = fftshift(C22(X - x_c, Y - y_c, Z - z_c)); 145 | C23s = fftshift(C23(X - x_c, Y - y_c, Z - z_c)); 146 | C33s = fftshift(C33(X - x_c, Y - y_c, Z - z_c)); 147 | % compute DFT 148 | constit_invar.C11s_hat = fftn(C11s); constit_invar.C12s_hat = fftn(C12s); 149 | constit_invar.C13s_hat = fftn(C13s); constit_invar.C22s_hat = fftn(C22s); 150 | constit_invar.C23s_hat = fftn(C23s); constit_invar.C33s_hat = fftn(C33s); 151 | % C21,C31, and C32 are not needed due to symmetry 152 | 153 | end 154 | 155 | end 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /PeriFast_Dynamics/update_VC.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This module takes the displacement BCs as functions of space and time 3 | % and also their corresponding node sets, and returns assembeled volume 4 | % constraints 5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6 | 7 | % assemble volume constraints for each coordinate direction 8 | wx = assemble_BC(chiG_x,dispBC_x,Nx,Ny,Nz,X,Y,Z,t); 9 | wy = assemble_BC(chiG_y,dispBC_y,Nx,Ny,Nz,X,Y,Z,t); 10 | wz = assemble_BC(chiG_z,dispBC_z,Nx,Ny,Nz,X,Y,Z,t); 11 | 12 | 13 | % function for assembling w_i 14 | function combined_BC = assemble_BC(BC_sets,BC_values,Nx,Ny,Nz,X,Y,Z,t) 15 | combined_BC = zeros(Ny,Nx,Nz); 16 | n = BC_sets.No; 17 | for i = 1:n(1) 18 | combined_BC = combined_BC +... 19 | (BC_sets(i).set).*(BC_values(i).func(X,Y,Z,t)); 20 | end 21 | end -------------------------------------------------------------------------------- /PeriFast_Dynamics/update_tractions.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This module enforces traction BCs as body forces applied uniformly on 3 | % delta-thickness boundary layer 4 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5 | 6 | % Assemble body forces for each coordinate direction 7 | btx = assemble_BC(chit_x,trac_x,Nx,Ny,Nz,X,Y,Z,t)/delta; 8 | bty = assemble_BC(chit_y,trac_y,Nx,Ny,Nz,X,Y,Z,t)/delta; 9 | btz = assemble_BC(chit_z,trac_z,Nx,Ny,Nz,X,Y,Z,t)/delta; 10 | 11 | 12 | % function for assembling bt_i 13 | function combined_BC = assemble_BC(BC_sets,BC_values,Nx,Ny,Nz,X,Y,Z,t) 14 | combined_BC = zeros(Ny,Nx,Nz); 15 | n = BC_sets.No; 16 | for i = 1:n(1) 17 | combined_BC = combined_BC +... 18 | (BC_sets(i).set).*(BC_values(i).func(X,Y,Z,t)); 19 | end 20 | end -------------------------------------------------------------------------------- /PeriFast_Dynamics/visualization.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This module takes the outputs from dump_output.m, the snapshot number, 3 | % nodal coordinates, and the body node set, and uses them to visualize the 4 | % results 5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6 | 7 | % for plotting outputs 8 | 9 | chiB_lambda = chiB.*(Output(ks).lambda); % mask nodes outside the body or damaged nodes 10 | plot_nodes = logical(chiB_lambda);% nodes that belong to the main body 11 | x_plot = X(plot_nodes); % coorniates of nodes in x-direction 12 | y_plot = Y(plot_nodes); % coorniates of nodes in y-direction 13 | z_plot = Z(plot_nodes); % coorniates of nodes in z-direction 14 | 15 | u1_plot = Output(ks).u1(plot_nodes); % displacement in x- direction 16 | u2_plot = Output(ks).u2(plot_nodes); % displacement in y- direction 17 | u3_plot = Output(ks).u3(plot_nodes); % displacement in z- direction 18 | 19 | % nodal coordinates in current configurartion 20 | xcur_plot = x_plot + u1_plot; 21 | ycur_plot = y_plot + u2_plot; 22 | zcur_plot = z_plot + u3_plot; 23 | 24 | % output selection for plots 25 | % visualization_var.output1; 26 | % num_of_outputs = visualization_var.No; 27 | num_of_outputs= size(outputs_var_for_visualization,2); 28 | 29 | for i = 1:num_of_outputs 30 | figure(i); 31 | 32 | outFilename = sprintf('output%d', i); 33 | 34 | out_var = outputs_var_for_visualization(1,i); 35 | if out_var == 1 36 | output_plot = Output(ks).u1(plot_nodes); 37 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 38 | colormap jet 39 | axis equal; 40 | title ( sprintf ('u1 ,t = %1.2e sec',dt*ks*snap)); 41 | end 42 | if out_var == 2 43 | output_plot = Output(ks).u2(plot_nodes); 44 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 45 | colormap jet 46 | axis equal; 47 | title ( sprintf ('u2 ,t = %1.2e sec',dt*ks*snap)); 48 | end 49 | if out_var == 3 50 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 51 | colormap jet 52 | axis equal; 53 | output_plot = Output(ks).u3(plot_nodes); 54 | title ( sprintf ('u3 ,t = %1.2e sec',dt*ks*snap)); 55 | end 56 | if out_var == 4 57 | output_plot = Output(ks).u_mag(plot_nodes); 58 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 59 | colormap jet 60 | axis equal; 61 | title ( sprintf ('u_mag ,t = %1.2e sec',dt*ks*snap)); 62 | end 63 | if out_var == 5 64 | output_plot = Output(ks).v1(plot_nodes); 65 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 66 | colormap jet 67 | axis equal; 68 | caxis([-1 1]); 69 | title ( sprintf ('v1 ,t = %1.2e sec',dt*ks*snap)); 70 | end 71 | if out_var == 6 72 | output_plot = Output(ks).v2(plot_nodes); 73 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 74 | colormap jet 75 | axis equal; 76 | caxis([-3.5 3.5]) 77 | title ( sprintf ('v2 ,t = %1.2e sec',dt*ks*snap)); 78 | 79 | end 80 | if out_var == 7 81 | output_plot = Output(ks).v3(plot_nodes); 82 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 83 | colormap jet 84 | axis equal; 85 | title ( sprintf ('v3 ,t = %1.2e sec',dt*ks*snap)); 86 | end 87 | 88 | if out_var == 8 89 | output_plot = Output(ks).v_mag(plot_nodes); 90 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 91 | colormap jet 92 | axis equal; 93 | title ( sprintf ('v_mag ,t = %1.2e sec',dt*ks*snap)); 94 | end 95 | if out_var == 9 96 | output_plot = Output(ks).W(plot_nodes); scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 97 | colormap jet 98 | axis equal; 99 | caxis([0 1500]) 100 | title ( sprintf ('W ,t = %1.2e sec',dt*ks*snap)); 101 | 102 | end 103 | if out_var == 10 104 | output_plot = Output(ks).d(plot_nodes); 105 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 106 | colormap jet 107 | axis equal; 108 | caxis([0 1]); 109 | title ( sprintf ('damage ,t = %1.2e sec',dt*ks*snap)); 110 | 111 | end 112 | if out_var == 11 113 | output_plot = Output(ks).lambda(plot_nodes); 114 | scatter3(xcur_plot(:),ycur_plot(:),zcur_plot(:), 5,output_plot(:)); 115 | colormap jet 116 | axis equal; 117 | title ( sprintf ('lambda ,t = %1.2e sec',dt*ks*snap)); 118 | end 119 | colorbar; 120 | drawnow 121 | end 122 | 123 | % create movies from the frams (snapshots) 124 | create_Matlab_video; 125 | 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PeriFast 2 | 3 | ## PeriFast/Corrosion 4 | 5 | **PeriFast/Corrosion**, a MATLAB code that uses the fast convolution-based method (FCBM) for peridynamic (PD) models of corrosion damage.The code efficiently solves 3D uniform corrosion (in copper) and pitting corrosion (in stainless steel) problems with multiple growing and merging pits, set in a complicated shape sample. 6 | 7 | pitting corrosion example | uniform corrosion example 8 | :-: | :-: 9 |