diff --git a/.gitignore b/.gitignore
index db01465..6caddde 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ Projects/1_LabData/1_Attenuation/not_used/
*.m~
*.idea
.vbr_test_data_dir
+*.zip
\ No newline at end of file
diff --git a/Projects/1_LabData/1_Attenuation/FitData_YT16.m b/Projects/1_LabData/1_Attenuation/FitData_YT16.m
index ea112bb..dcfb73b 100644
--- a/Projects/1_LabData/1_Attenuation/FitData_YT16.m
+++ b/Projects/1_LabData/1_Attenuation/FitData_YT16.m
@@ -18,6 +18,7 @@ function FitData_YT16()
path_to_top_level_vbr='../../../';
addpath(path_to_top_level_vbr)
vbr_init
+ addpath('./functions')
plot_visc();
plot_Q();
@@ -32,7 +33,6 @@ function plot_Q()
viscData = loadYT2016visc();
Qdata=loadYT2016Q();
- %figure('DefaultAxesFontSize',12,'PaperPosition',[0,0,6,2.5],'PaperPositionMode','manual')
fig=figure('Position', [10 10 600 300],'PaperPosition',[0,0,6,2.5],'PaperPositionMode','manual');
OutVBR=struct();
if viscData.has_data && Qdata.Qinv.has_data
@@ -63,7 +63,7 @@ function plot_Q()
[T_Cvisc,I]=sort(T_Cvisc); eta=eta(I);
% set this sample's viscosity parameters
- VBR.in.viscous.xfit_premelt=setBorneolParams();
+ VBR.in.viscous.xfit_premelt=setBorneolViscParams();
VBR.in.viscous.xfit_premelt.dg_um_r=dg;
VBR.in.viscous.xfit_premelt.Tr_K=T_Cvisc(1)+273;
VBR.in.viscous.xfit_premelt.eta_r=eta(1);
@@ -300,56 +300,3 @@ function plot_visc()
end
end
-function params = setBorneolParams()
- % set the general viscous parameters for borneol.
- % near-solidus and melt effects
- params.alpha=25;
- params.T_eta=0.94; % eqn 17,18- T at which homologous T for premelting.
- params.gamma=5;
- % flow law constants for YT2016
- params.Tr_K=23+273; % reference temp [K]
- params.Pr_Pa=0; % reference pressure [Pa]
- params.eta_r=7e13;% reference eta (eta at Tr_K, Pr_Pa)
- params.H=147*1e3; % activation energy [J/mol]
- params.V=0; % activation vol [m3/mol]
- params.R=8.314; % gas constant [J/mol/K]
- params.m=2.56; % grain size exponent
- params.dg_um_r=34.2 ; % eference grain size [um]
-end
-
-function [G,dGdT,dGdT_ave] = YT16_E(T_C)
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % [G,dGdT,dGdT_ave]= YT16_E(T_C)
- %
- % YT2016 Figure 6 caption polynomial fit of E vs T, T in degrees C
- %
- % parameters
- % ----------
- % T_C temperature in deg C, any size array
- %
- % output
- % ------
- % G modulus, GPa. same size as T_C
- % dGdT temperature derivative of G at T_C, same size as T_C. [GPa/C]
- % dGdT_ave average temp derivative over range of T_C given, scalar. [GPa/C].
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- a0=2.5943;
- a1=2.6911*1e-3;
- a2=-2.9636*1e-4;
- a3 =1.4932*1e-5;
- a4 =-2.9351*1e-7;
- a5 =1.8997*1e-9;
- a = [a5,a4,a3,a2,a1,a0];
-
- G=zeros(size(T_C));
- dGdT=zeros(size(T_C));
- for iTC=1:numel(T_C)
- Gpoly = polyval(a,T_C(iTC));
- dGdTpoly = polyval(a(1:end-1),T_C(iTC));
- G(iTC)=sum(Gpoly(:));
- dGdT(iTC)=sum(dGdTpoly(:));
- end
- dGdT_ave=mean(dGdT);
-
-end
diff --git a/Projects/1_LabData/1_Attenuation/FitData_YT24.m b/Projects/1_LabData/1_Attenuation/FitData_YT24.m
new file mode 100644
index 0000000..d0a9461
--- /dev/null
+++ b/Projects/1_LabData/1_Attenuation/FitData_YT24.m
@@ -0,0 +1,214 @@
+function VBRc_results = FitData_YT24()
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ % FitData_YT24()
+ %
+ % Plots viscosity, modulus, Qinv for borneol near and above the solidus
+ % temperature following premelting scaling of Yamauchi and Takei, 2024, JGR.
+ %
+ % Parameters
+ % ----------
+ % use_data
+ % if 1, will attempt to fetch data from zenondo
+ %
+ % Output
+ % ------
+ % figures to screen and to Projects/1_LabData/1_Attenuation/figures/
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ % put VBR in the path
+ vbr_path = getenv('vbrdir');
+ if isempty(vbr_path)
+ vbr_path='../../../';
+ end
+ addpath(vbr_path)
+ vbr_init
+
+ addpath('./functions')
+
+ % check on data, download if needed
+ full_data_dir = download_YT24('data');
+
+ % get VBRc result and plot along the way
+ VBRc_results = plot_fig7(full_data_dir);
+
+end
+
+
+function VBRc_results = plot_fig7(full_data_dir);
+
+ figure('Position', [10 10 500 600],'PaperPosition',[0,0,7,7*6/5],'PaperPositionMode','manual');
+ yheight = 0.4;
+ xpos = 0.1;
+ ypos = 0.1;
+ xwidth = 0.6;
+ ax_Q = axes('position', [xpos, ypos, xwidth, yheight]);
+ ax_E = axes('position', [xpos, ypos + yheight, xwidth, yheight]);
+ leg_pos = [xpos+xwidth+0.05, ypos, 0.2, yheight];
+
+
+ load(fullfile('data','YT16','table3.mat'));
+ visc_data.table3_H=table3_H.table3_H;
+
+ combined_data = YT24_load_fig7_combined_data(full_data_dir);
+
+ n_exps = numel(combined_data);
+
+ freq_range = logspace(-6,9,100);
+ Tsol = 43.0;
+
+ % get VBRc results
+ VBRc_results = struct();
+ for i_exp = 1:n_exps
+ data = combined_data(i_exp);
+
+ T = data.T; % celcius
+ dg = data.dg_um;
+ phi = data.phi;
+ rho = data.rho_kgm3;
+
+ VBR.in.elastic.methods_list={'anharmonic';};
+ VBR.in.viscous.methods_list={'xfit_premelt'};
+ VBR.in.anelastic.methods_list={'xfit_premelt'};
+ VBR.in.anelastic.xfit_premelt.include_direct_melt_effect = 1.0;
+ % VBR.in.anelastic.xfit_premelt.tau_pp=2*1e-5;
+ % plotting with correction for poro-elastic effect applied, so
+ % set effect to 0 here.
+ VBR.in.anelastic.xfit_premelt.poro_Lambda = 0.0;
+
+ % set viscous params
+ VBR.in.viscous.xfit_premelt=setBorneolViscParams(); % YT2016 values, sample 41
+ VBR.in.viscous.xfit_premelt.alpha = 32; % YT2024 actually fit this
+
+ % set anharmonic conditions
+ VBR.in.elastic.anharmonic=Params_Elastic('anharmonic');
+ % extract reference modulus (E_normed = E / E_u)
+ [Gu_o,dGdT,dGdT_ave]= YT16_E(T);
+ Gu_o = Gu_o * 1e9;
+
+ % Gu_o is for a given T, specify at elevated TP to skip anharmonic scaling
+ VBR.in.elastic.Gu_TP = Gu_o;
+ VBR.in.elastic.quiet = 1; % not bothering with K, avoid printing the poisson warning
+
+ % set experimental conditions
+ VBR.in.SV.T_K = T+273 ;
+ sz=size(VBR.in.SV.T_K);
+ VBR.in.SV.dg_um= dg .* ones(sz); %dg.* ones(sz);
+ VBR.in.SV.P_GPa = 1.0132e-04 .* ones(sz); % pressure [GPa]
+ VBR.in.SV.rho =rho .* ones(sz); % density [kg m^-3]
+ VBR.in.SV.sig_MPa = 1000 .* ones(sz)./1e6; % differential stress [MPa]
+ VBR.in.SV.Tsolidus_K = Tsol + 273 ;
+
+ VBR.in.SV.phi = phi * ones(sz); % melt fraction
+ VBR.in.SV.Ch2o_0=zeros(sz);
+
+ VBR.in.SV.f=freq_range;
+ [VBR_bysamp] = VBR_spine(VBR);
+ results.Qinv=VBR_bysamp.out.anelastic.xfit_premelt.Qinv;
+ results.E=VBR_bysamp.out.anelastic.xfit_premelt.M;
+ results.f = VBR.in.SV.f;
+ results.f_normed = VBR_bysamp.out.anelastic.xfit_premelt.f_norm;
+ results.E_normed = results.E / Gu_o;
+ results.T = T;
+ results.Tn = VBR.in.SV.T_K / VBR.in.SV.Tsolidus_K ;
+ results.VBR = VBR_bysamp;
+ VBRc_results(i_exp) = results;
+ end
+
+
+ for i_exp = 1:n_exps
+ if i_exp == 2
+ linesty = '--';
+ else
+ linesty = '-';
+ end
+ results = VBRc_results(i_exp);
+ rgb = vbr_categorical_color(i_exp);
+ Tnlab = num2str(results.Tn, 3+(results.Tn>=1));
+ axes(ax_E)
+ hold_if(i_exp)
+ semilogx(results.f_normed, results.E_normed ,'color', rgb, ...
+ 'linewidth', 1.5, 'linestyle', linesty)
+ axes(ax_Q)
+ hold_if(i_exp)
+ loglog(results.f_normed, results.Qinv , 'color', rgb, ...
+ 'linewidth', 1.5, 'displayname', Tnlab, 'linestyle', linesty)
+ end
+
+ % plot experimental results
+ delta_systematic = 0.031;
+
+ for i_exp = 1:n_exps
+ data = combined_data(i_exp);
+ dporo = data.dporo * data.phi;
+ mod_fac = 1 / ( 1 - delta_systematic) / (1 - dporo); % correction factor
+ rgb = vbr_categorical_color(i_exp);
+ if data.Tn >= 1
+ mrkr = 'o';
+ mrkr_sz = 5;
+ mkr_fc = 'w';
+ else
+ mrkr = '.';
+ mrkr_sz=15;
+ mkr_fc = rgb;
+ end
+ Tnlab = num2str(data.Tn, 3+(data.Tn>=1));
+ axes(ax_E)
+ hold_if(i_exp)
+ semilogx(data.f_normed, data.E_normed * mod_fac, mrkr, ...
+ 'markersize', mrkr_sz, 'color', rgb, 'displayname', Tnlab, ...
+ 'MarkerFaceColor', mkr_fc)
+ axes(ax_Q)
+ hold_if(i_exp)
+ loglog(data.f_normed, data.Qinv, mrkr, 'markersize', mrkr_sz, ....
+ 'color', rgb, 'displayname', Tnlab, 'MarkerFaceColor', mkr_fc)
+ end
+ axes(ax_Q)
+ leg = legend('Location', 'eastoutside', 'Orientation', 'vertical', ...
+ 'AutoUpdate','off','title','T_n','NumColumns',1);
+
+ axes(ax_E)
+ xticklabels([])
+ xlim([1e-2,1e9])
+ ylim([0,1.1])
+ xlabel('f / f_M')
+ ylabel("E/E_u")
+
+ axes(ax_Q)
+ xlim([1e-2,1e9])
+ ylim([1e-3,2])
+ xlabel('f / f_M')
+ ylabel("Q^-^1")
+
+ set(leg, 'Position', leg_pos)
+
+ saveas(gcf,'./figures/YT24_MQ.png')
+end
+
+
+
+
+function unzipped_data_dir = download_YT24(datadir)
+ % downloads, unzips data from zenodo
+
+ unzipped_data_dir = fullfile(datadir,'YT24');
+ if exist(datadir) ~= 7
+ mkdir(datadir)
+ mkdir(unzipped_data_dir)
+ end
+
+ YT24data_url = 'https://zenodo.org/api/records/10201689/files-archive';
+ zipfilename = '10201689.zip';
+
+ local_data = fullfile(unzipped_data_dir, zipfilename);
+ if exist(local_data) ~= 2
+ urlwrite(YT24data_url, zipfilename)
+ movefile(zipfilename, unzipped_data_dir)
+ unzip(local_data, unzipped_data_dir)
+ end
+end
+
+function hold_if(iterval)
+ if iterval > 1
+ hold all
+ end
+end
\ No newline at end of file
diff --git a/Projects/1_LabData/1_Attenuation/data/YT16/table3.mat b/Projects/1_LabData/1_Attenuation/data/YT16/table3.mat
new file mode 100644
index 0000000..a6ce9c3
Binary files /dev/null and b/Projects/1_LabData/1_Attenuation/data/YT16/table3.mat differ
diff --git a/Projects/1_LabData/1_Attenuation/data/YT24/readme.pdf b/Projects/1_LabData/1_Attenuation/data/YT24/readme.pdf
new file mode 100644
index 0000000..5e2526d
Binary files /dev/null and b/Projects/1_LabData/1_Attenuation/data/YT24/readme.pdf differ
diff --git a/Projects/1_LabData/1_Attenuation/functions/YT16_E.m b/Projects/1_LabData/1_Attenuation/functions/YT16_E.m
new file mode 100644
index 0000000..fac0f05
--- /dev/null
+++ b/Projects/1_LabData/1_Attenuation/functions/YT16_E.m
@@ -0,0 +1,36 @@
+function [G,dGdT,dGdT_ave] = YT16_E(T_C)
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ % [G,dGdT,dGdT_ave]= YT16_E(T_C)
+ %
+ % YT2016 Figure 6 caption polynomial fit of E vs T, T in degrees C
+ %
+ % parameters
+ % ----------
+ % T_C temperature in deg C, any size array
+ %
+ % output
+ % ------
+ % G modulus, GPa. same size as T_C
+ % dGdT temperature derivative of G at T_C, same size as T_C. [GPa/C]
+ % dGdT_ave average temp derivative over range of T_C given, scalar. [GPa/C].
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ a0=2.5943;
+ a1=2.6911*1e-3;
+ a2=-2.9636*1e-4;
+ a3 =1.4932*1e-5;
+ a4 =-2.9351*1e-7;
+ a5 =1.8997*1e-9;
+ a = [a5,a4,a3,a2,a1,a0];
+
+ G=zeros(size(T_C));
+ dGdT=zeros(size(T_C));
+ for iTC=1:numel(T_C)
+ Gpoly = polyval(a,T_C(iTC));
+ dGdTpoly = polyval(a(1:end-1),T_C(iTC));
+ G(iTC)=sum(Gpoly(:));
+ dGdT(iTC)=sum(dGdTpoly(:));
+ end
+ dGdT_ave=mean(dGdT);
+
+end
diff --git a/Projects/1_LabData/1_Attenuation/functions/YT24_load_fig7_combined_data.m b/Projects/1_LabData/1_Attenuation/functions/YT24_load_fig7_combined_data.m
new file mode 100644
index 0000000..43cc2f1
--- /dev/null
+++ b/Projects/1_LabData/1_Attenuation/functions/YT24_load_fig7_combined_data.m
@@ -0,0 +1,107 @@
+function combined_data_final = YT24_load_fig7_combined_data(full_data_dir)
+
+ combined_data = struct();
+ % pull all data for sample 41 first T cycle
+ sample_id= 41;
+ [current_run, sample_info] = load_sample_data(sample_id, full_data_dir);
+
+ start_end = sample_info.first_Tcycle_index_start_stop;
+ i_Tstart = start_end(1);
+ i_Tend = start_end(2);
+
+ i_data = 1;
+ Tsol = 43;
+ Tvals = [];
+ for iT = i_Tstart: i_Tend
+ combined_data(i_data) = extract_single_experiment(current_run, sample_info, iT, Tsol, sample_id);
+ Tvals = [Tvals, combined_data(i_data).Tn];
+ i_data = i_data + 1;
+ end
+
+ for sample_id = 42:8:50 % 42, 50
+ [current_run, sample_info] = load_sample_data(sample_id, full_data_dir);
+ start_end = sample_info.first_Tcycle_index_start_stop;
+ i_Tstart = start_end(1);
+ i_Tend = start_end(2);
+ for iT = i_Tstart: i_Tend
+ if current_run(iT).T >= Tsol
+ combined_data(i_data) = extract_single_experiment(current_run, sample_info, iT, Tsol, sample_id);
+ Tvals = [Tvals, combined_data(i_data).Tn];
+ i_data = i_data + 1;
+ end
+ end
+ end
+
+
+
+ % finally, re-order based on homologous temperature
+ [sorted_T, idx] = sort(Tvals);
+ for isamp = 1:numel(combined_data)
+ combined_data_final(isamp) = combined_data(idx(isamp));
+ end
+
+end
+
+function single_exp = extract_single_experiment(current_run, sample_info, iT, Tsol, sample_id)
+ T = current_run(iT).T; % celcius
+ cdata = current_run(iT).data;
+ single_exp.T = T;
+ single_exp.Tn = (T + 273.0) / (Tsol+273); % homologous temperature
+ single_exp.f = cdata(:,1);
+ single_exp.f_normed = cdata(:,2);
+ single_exp.E = cdata(:,3);
+ single_exp.E_normed = cdata(:,4);
+ single_exp.Qinv = cdata(:,5);
+
+
+ phi = sample_info.phi * (T >= Tsol);
+ single_exp.phi = phi;
+ single_exp.dg_um = sample_info.dg_um;
+ single_exp.sample_id = sample_id;
+ single_exp.rho_kgm3 = sample_info.rho_kgm3;
+ single_exp.dporo = (phi > 0) * sample_info.dporo;
+end
+
+function [run_data, sample_info] = load_sample_data(sample_number, full_data_dir)
+
+ sample_str = num2str(sample_number);
+ sample_file = fullfile(full_data_dir, ['anela',sample_str,'.mat']);
+ struct_name = ['anela',sample_str];
+ sample_data = load(sample_file); % e.g., sample_data.anela42
+ data = getfield(sample_data, struct_name); % e.g., anela42
+
+ run_data = data.run;
+ sample_info = get_sample_info(sample_number);
+end
+
+
+
+function sample_data = get_sample_info(sample_number)
+
+ if sample_number == 50
+ sample_data.dg_um = 47.9;
+ sample_data.rho_kgm3 = 1.0111;
+ sample_data.phi = 0.0368;
+ sample_data.eta_r = 1061*1e12;
+ sample_data.first_Tcycle_index_start_stop = [2, 9];
+ sample_data.nT = 8;
+ sample_data.dporo = 0.135;
+ elseif sample_number == 42
+ sample_data.dg_um = 46.3;
+ sample_data.rho_kgm3 = 1.0111;
+ sample_data.phi = 0.016;
+ sample_data.eta_r = 132 * 1e12;
+ sample_data.first_Tcycle_index_start_stop = [2, 8];
+ sample_data.nT = 7;
+ sample_data.dporo = 0.0585;
+ elseif sample_number == 41
+ sample_data.dg_um = 34.2;
+ sample_data.rho_kgm3 = 1.0111;
+ sample_data.phi = 0.004;
+ sample_data.eta_r = 1433 * 1e12;
+ sample_data.first_Tcycle_index_start_stop = [3, 10];
+ sample_data.nT = 8;
+ sample_data.dporo = 0.0178;
+ end
+
+end
\ No newline at end of file
diff --git a/Projects/1_LabData/1_Attenuation/functions/setBorneolViscParams.m b/Projects/1_LabData/1_Attenuation/functions/setBorneolViscParams.m
new file mode 100644
index 0000000..a1f39da
--- /dev/null
+++ b/Projects/1_LabData/1_Attenuation/functions/setBorneolViscParams.m
@@ -0,0 +1,16 @@
+function params = setBorneolViscParams()
+ % set the general viscous parameters for borneol for YT2016
+ % near-solidus and melt effects
+ params.alpha=25;
+ params.T_eta=0.94; % eqn 17,18- T at which homologous T for premelting.
+ params.gamma=5;
+ % flow law constants for YT2016
+ params.Tr_K=23+273; % reference temp [K]
+ params.Pr_Pa=0; % reference pressure [Pa]
+ params.eta_r=7e13;% reference eta (eta at Tr_K, Pr_Pa)
+ params.H=147*1e3; % activation energy [J/mol]
+ params.V=0; % activation vol [m3/mol]
+ params.R=8.314; % gas constant [J/mol/K]
+ params.m=2.56; % grain size exponent
+ params.dg_um_r=34.2 ; % eference grain size [um]
+end
\ No newline at end of file
diff --git a/Projects/vbr_core_examples/CB_014_xfit_premelt_extended.m b/Projects/vbr_core_examples/CB_014_xfit_premelt_extended.m
new file mode 100644
index 0000000..a9451ba
--- /dev/null
+++ b/Projects/vbr_core_examples/CB_014_xfit_premelt_extended.m
@@ -0,0 +1,74 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CB_014_xfit_premelt_extended.m
+%
+% Calls VBR using xfit_premelt method including the direct melt effect,
+% from:
+% Hatsuki Yamauchi and Yasuko Takei, JGR 2024, "Effect of Melt on
+% Polycrystal Anelasticity", https://doi.org/10.1029/2023JB027738
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% put VBR in the path %%
+ clear; close all
+ path_to_top_level_vbr='../../';
+ addpath(path_to_top_level_vbr)
+ vbr_init
+
+%% write method list %%
+ VBR.in.elastic.methods_list={'anharmonic'};
+ VBR.in.anelastic.methods_list={'xfit_premelt'};
+ VBR.in.anelastic.xfit_premelt.include_direct_melt_effect = 1;
+
+ % load anharmonic parameters, adjust Gu_0_ol and derivatives to match YT2016
+ VBR.in.elastic.anharmonic.Gu_0_ol=72.45; %[GPa]
+ VBR.in.elastic.anharmonic.dG_dT = -10.94*1e6; % Pa/C (equivalent ot Pa/K)
+ VBR.in.elastic.anharmonic.dG_dP = 1.987; % GPa / GPa
+
+
+ %% Define the Thermodynamic State %%
+ VBR.in.SV.T_K=1200:5:1500;
+ VBR.in.SV.T_K=VBR.in.SV.T_K+273;
+ sz=size(VBR.in.SV.T_K); % temperature [K]
+ VBR.in.SV.P_GPa = full_nd(2.5, sz); % pressure [GPa]
+
+ Tn_cases = [.96, .98, 1.0, 1.1, 1.1, 1.1, 1.1];
+ phi_cases = [0., 0., 0., 0.1, 1, 2, 4]*0.01;
+
+ % remaining state variables (ISV)
+ VBR.in.SV.dg_um=full_nd(.004*1e6, sz); % grain size [um]
+ VBR.in.SV.rho = full_nd(3300, sz); % density [kg m^-3]
+ VBR.in.SV.sig_MPa = full_nd(1, sz); % differential stress [MPa]
+ VBR.in.SV.f = 1; % 1 Hz
+
+
+ f1=figure('PaperPosition',[0,0,6,4],'PaperPositionMode','manual');
+ nTn = numel(Tn_cases);
+ VBR_results = struct();
+
+ for iTn = 1:nTn
+ VBRi = VBR;
+ VBRi.in.SV.phi = full_nd(phi_cases(iTn), sz);
+ VBRi.in.SV.Tsolidus_K = VBR.in.SV.T_K / Tn_cases(iTn);
+ [VBRi] = VBR_spine(VBRi) ;
+
+ results.Q = VBRi.out.anelastic.xfit_premelt.Q;
+ VBR_results(iTn) = results;
+
+ dname = [num2str(Tn_cases(iTn)), ', ', num2str(phi_cases(iTn))];
+ figure(f1)
+ if iTn > 1
+ hold all
+ end
+ plot(VBR.in.SV.T_K - 273, results.Q, 'displayname', dname, 'linewidth', 1.5)
+ legend('Location','eastoutside','title', '(Tn, phi)')
+ xlabel('Temperature [C]', 'fontsize', 12)
+ ylabel('Qs', 'fontsize', 12)
+ ylim([0, 200])
+
+ yticks(0:20:200)
+
+ end
+
+
+ saveas(gcf,'./figures/CB_014_xfit_premelt_extended.png')
+
+
diff --git a/docs/_pages/examples/CB_014_xfit_premelt_extended.md b/docs/_pages/examples/CB_014_xfit_premelt_extended.md
new file mode 100644
index 0000000..bf84e72
--- /dev/null
+++ b/docs/_pages/examples/CB_014_xfit_premelt_extended.md
@@ -0,0 +1,86 @@
+---
+permalink: /examples/CB_014_xfit_premelt_extended/
+title: ""
+---
+
+# CB_014_xfit_premelt_extended.m
+## output figures
+
+!['CB_014_xfit_premelt_extended'](/vbr/assets/images/CBs/CB_014_xfit_premelt_extended.png){:class="img-responsive"}
+## contents
+```matlab
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CB_014_xfit_premelt_extended.m
+%
+% Calls VBR using xfit_premelt method including the direct melt effect,
+% from:
+% Hatsuki Yamauchi and Yasuko Takei, JGR 2024, "Effect of Melt on
+% Polycrystal Anelasticity", https://doi.org/10.1029/2023JB027738
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% put VBR in the path %%
+ clear; close all
+ path_to_top_level_vbr='../../';
+ addpath(path_to_top_level_vbr)
+ vbr_init
+
+%% write method list %%
+ VBR.in.elastic.methods_list={'anharmonic'};
+ VBR.in.anelastic.methods_list={'xfit_premelt'};
+ VBR.in.anelastic.xfit_premelt.include_direct_melt_effect = 1;
+
+ % load anharmonic parameters, adjust Gu_0_ol and derivatives to match YT2016
+ VBR.in.elastic.anharmonic.Gu_0_ol=72.45; %[GPa]
+ VBR.in.elastic.anharmonic.dG_dT = -10.94*1e6; % Pa/C (equivalent ot Pa/K)
+ VBR.in.elastic.anharmonic.dG_dP = 1.987; % GPa / GPa
+
+
+ %% Define the Thermodynamic State %%
+ VBR.in.SV.T_K=1200:5:1500;
+ VBR.in.SV.T_K=VBR.in.SV.T_K+273;
+ sz=size(VBR.in.SV.T_K); % temperature [K]
+ VBR.in.SV.P_GPa = full_nd(2.5, sz); % pressure [GPa]
+
+ Tn_cases = [.96, .98, 1.0, 1.1, 1.1, 1.1, 1.1];
+ phi_cases = [0., 0., 0., 0.1, 1, 2, 4]*0.01;
+
+ % remaining state variables (ISV)
+ VBR.in.SV.dg_um=full_nd(.004*1e6, sz); % grain size [um]
+ VBR.in.SV.rho = full_nd(3300, sz); % density [kg m^-3]
+ VBR.in.SV.sig_MPa = full_nd(1, sz); % differential stress [MPa]
+ VBR.in.SV.f = 1; % 1 Hz
+
+
+ f1=figure('PaperPosition',[0,0,6,4],'PaperPositionMode','manual');
+ nTn = numel(Tn_cases);
+ VBR_results = struct();
+
+ for iTn = 1:nTn
+ VBRi = VBR;
+ VBRi.in.SV.phi = full_nd(phi_cases(iTn), sz);
+ VBRi.in.SV.Tsolidus_K = VBR.in.SV.T_K / Tn_cases(iTn);
+ [VBRi] = VBR_spine(VBRi) ;
+
+ results.Q = VBRi.out.anelastic.xfit_premelt.Q;
+ VBR_results(iTn) = results;
+
+ dname = [num2str(Tn_cases(iTn)), ', ', num2str(phi_cases(iTn))];
+ figure(f1)
+ if iTn > 1
+ hold all
+ end
+ plot(VBR.in.SV.T_K - 273, results.Q, 'displayname', dname, 'linewidth', 1.5)
+ legend('Location','eastoutside','title', '(Tn, phi)')
+ xlabel('Temperature [C]', 'fontsize', 12)
+ ylabel('Qs', 'fontsize', 12)
+ ylim([0, 200])
+
+ yticks(0:20:200)
+
+ end
+
+
+ saveas(gcf,'./figures/CB_014_xfit_premelt_extended.png')
+
+
+```
diff --git a/docs/_pages/examples/vbrcore.md b/docs/_pages/examples/vbrcore.md
index d2e9e27..03b44e0 100644
--- a/docs/_pages/examples/vbrcore.md
+++ b/docs/_pages/examples/vbrcore.md
@@ -18,3 +18,4 @@ Simple "Cookbook" (CB) scripts demonstrating various use cases of the VBR Calcul
* `CB_011_meltEffects.m` [link](/vbr/examples/CB_011_meltEffects/)
* `CB_012_simplecrust.m` [link](/vbr/examples/CB_012_simplecrust/)
* `CB_013_G_K_inputs.m` [link](/vbr/examples/CB_013_G_K_inputs/)
+* `CB_014_xfit_premelt_extended.m` [link](/vbr/examples/CB_014_xfit_premelt_extended/)
diff --git a/docs/_pages/vbrmethods/anel/xfitpremelt.md b/docs/_pages/vbrmethods/anel/xfitpremelt.md
index 13e6838..4bdfd82 100644
--- a/docs/_pages/vbrmethods/anel/xfitpremelt.md
+++ b/docs/_pages/vbrmethods/anel/xfitpremelt.md
@@ -6,7 +6,9 @@ title: ''
# `xfit_premelt`
-Master curve maxwell scaling using near-solidus parametrization of Yamauchi and Takei (2016), J. Geophys. Res. Solid Earth, [DOI](https://doi.org/10.1002/2016JB013316).
+Master curve maxwell scaling using near-solidus parametrization of Yamauchi and Takei (2016),
+J. Geophys. Res. Solid Earth, [DOI](https://doi.org/10.1002/2016JB013316) with optional extension to include direct melt effects
+of Yamauchi and Takei (2024), J. Geophys. Res. Solid Earth, [DOI](https://doi.org/10.1029/2023JB027738).
## Requires
@@ -21,11 +23,27 @@ VBR.in.SV.sig_MPa % differential stress [MPa]
VBR.in.SV.phi % melt fraction / porosity
VBR.in.SV.rho % density in kg m-3
```
+
+To use the Yamauchi and Takei (2024) scaling that includes direct melt effects, set the
+following flag:
+
+```matlab
+VBR.in.anelastic.xfit_premelt.include_direct_melt_effect = 1;
+```
Additionally, `xfit_premelt` relies on output from the elastic and viscous methods.
-**Required Elastic Methods**: `anharmonic` MUST be in the `VBR.in.elastic.methods_list`. If `anh_poro` is in the methods list then `xfit_premelt` will use the unrelaxed moduli from `anh_poro` (which includes the P,T projection of `anharmonic` plus the poroelastic correction). See the section on [elastic methods](/vbr/vbrmethods/elastic/) for more details.
+**Required Elastic Methods**: `anharmonic` MUST be in the `VBR.in.elastic.methods_list`. Poroelasticity
+is treated differently depending on the value of `include_direct_melt_effect`.
+If `include_direct_melt_effect==0` and `anh_poro` is in the methods list then `xfit_premelt` will use the unrelaxed moduli
+from `anh_poro` (which includes the P,T projection of `anharmonic` plus the poroelastic correction). See the section
+on [elastic methods](/vbr/vbrmethods/elastic/) for more details. If `include_direct_melt_effect==1`, then poroelasticity is incororated within
+J1, following Yamauchi and Takei (2024). The current version of the VBRc uses `include_direct_melt_effect=0` as the default,
+future versions will set this flag to 1 by default.
-**Optional Viscous Methods**: `xfit_premelt` calculates maxwell times using the [viscous xfit_premelt method](/vbr/vbrmethods/visc/xfit_premelt/). If you want to adjust the viscosity calculation used in the maxwell time, you can add `xfit_premelt` to `VBR.in.viscous.methods_list` and adjust the desired parameters. The anelastic calculation will then use the results calculated by the viscous `xfit_premelt` method. This is particularly useful when fitting laboratory measurements of borneol (see [example](/vbr/vbrmethods/anel/xfitpremelt/#example-at-laboratory-conditions) below).
+**Optional Viscous Methods**: `xfit_premelt` calculates maxwell times using the [viscous xfit_premelt method](/vbr/vbrmethods/visc/xfit_premelt/).
+If you want to adjust the viscosity calculation used in the maxwell time, you can add `xfit_premelt` to `VBR.in.viscous.methods_list`
+and adjust the desired parameters. The anelastic calculation will then use the results calculated by the viscous `xfit_premelt` method.
+This is particularly useful when fitting laboratory measurements of borneol (see [example](/vbr/vbrmethods/anel/xfitpremelt/#example-at-laboratory-conditions) below).
## Calling Procedure
@@ -53,6 +71,9 @@ VBR.in.elastic.methods_list={'anharmonic';'anh_poro'};
% set anelastic methods list
VBR.in.anelastic.methods_list={'xfit_premelt'};
+% enable melt effects from Yamauchi and Takei (2024)
+VBR.in.anelastic.xfit_premelt.include_direct_melt_effect = 1;
+
% call VBR_spine
[VBR] = VBR_spine(VBR) ;
```
@@ -95,3 +116,7 @@ The Project script, `Projects/1_LabData/1_Attenuation/FitData_YT16.m` calculates
!['mxwPMLab'](/vbr/assets/images/xfitpremelt1.png){:class="img-responsive"}
Data are from figure 10 of Yamauchi and Takei (2016) and are not included in the repository at present.
+
+The Project script, `Projects/1_LabData/1_Attenuation/FitData_YT24.m` reproduces figure 7 from Yamauchi and Takei (2024).
+
+!['mxwPMLab'](/vbr/assets/images/xfitpremelt_melt_effects.png){:class="img-responsive"}
diff --git a/docs/_pages/vbrmethods/anelastic.md b/docs/_pages/vbrmethods/anelastic.md
index bf07170..2d1f1fc 100644
--- a/docs/_pages/vbrmethods/anelastic.md
+++ b/docs/_pages/vbrmethods/anelastic.md
@@ -11,6 +11,9 @@ The anelastic methods displayed by `vbrListMethods` currently include:
* `xfit_mxw` [documentation](/vbr/vbrmethods/anel/xfitmxw/): Master Curve Fit, maxwell scaling
* `xfit_premelt` [documentation](/vbr/vbrmethods/anel/xfitpremelt/): Master Curve Fit, pre-melting maxwell scaling
-A detailed theoretical description of each is provided in the full VBR Manual document (IN PREP) and so here, we only describe the computational aspects useful to the end user.
+A detailed theoretical description of each is provided in the full methods paper ([link](https://doi.org/10.1016/j.pepi.2020.106639)) or
+in the papers cited by the methods and so here, we only describe the computational aspects useful to the end user.
-All of the anelastic methods require results of an elastic calculation, specifically the unrelaxed elastic moduli. If calculated, the anelastic methods will use moduli from `VBR.out.elastic.anh_poro` and default to those from `VBR.out.elastic.anharmonic`.
+All of the anelastic methods require results of an elastic calculation, specifically the unrelaxed elastic moduli.
+If calculated, the anelastic methods may also use moduli from `VBR.out.elastic.anh_poro` and default to those from
+`VBR.out.elastic.anharmonic`.
diff --git a/docs/_pages/vbrmethods/visc/xfit_premelt.md b/docs/_pages/vbrmethods/visc/xfit_premelt.md
index 1afe3f2..7cb8d05 100644
--- a/docs/_pages/vbrmethods/visc/xfit_premelt.md
+++ b/docs/_pages/vbrmethods/visc/xfit_premelt.md
@@ -45,7 +45,11 @@ disp(VBR.in.viscous.xfit_premelt)
### eta_melt_free_method
-The parameter, `VBR.in.viscous.xfit_premelt.eta_melt_free_method`, controls what viscosity method is used to calculate the melt free viscosity. By default, this is set to `xfit_premelt`, in which case it uses the upper mantle fit directly from Yamauchi and Takei (2016). If set to one of the other viscosity mtehods, `HK2003` or `HZK2011`, then the melt free viscosity is calculated using those methods with melt fraction set to 0 and then the near-solidus pre-melting effect is then multiplied on.
+The parameter, `VBR.in.viscous.xfit_premelt.eta_melt_free_method`, controls what viscosity method is used to calculate
+the melt free viscosity. By default, this is set to `xfit_premelt`, in which case it uses the upper mantle fit directly
+from Yamauchi and Takei (2016). If set to one of the other viscosity mtehods, `HK2003` or `HZK2011`, then the melt
+free viscosity is calculated using those methods with melt fraction set to 0 and then the near-solidus pre-melting
+effect is then multiplied on.
## Output
Output is stored in `VBR.out.viscous.xfit_premelt`. Unlike the other viscous methods, `xfit_premelt` only returns a diffusion creep viscosity sub-structure:
diff --git a/docs/assets/images/CBs/CB_004_xfit_premelt.png b/docs/assets/images/CBs/CB_004_xfit_premelt.png
index 5121429..a0d3d4c 100644
Binary files a/docs/assets/images/CBs/CB_004_xfit_premelt.png and b/docs/assets/images/CBs/CB_004_xfit_premelt.png differ
diff --git a/docs/assets/images/CBs/CB_014_xfit_premelt_extended.png b/docs/assets/images/CBs/CB_014_xfit_premelt_extended.png
new file mode 100644
index 0000000..9c162b3
Binary files /dev/null and b/docs/assets/images/CBs/CB_014_xfit_premelt_extended.png differ
diff --git a/docs/assets/images/xfitpremelt_melt_effects.png b/docs/assets/images/xfitpremelt_melt_effects.png
new file mode 100644
index 0000000..059f5c0
Binary files /dev/null and b/docs/assets/images/xfitpremelt_melt_effects.png differ
diff --git a/release_notes.md b/release_notes.md
index 6c7badb..a82e210 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -1,5 +1,12 @@
# v1.1.3
## New Features
+* updates to xfit_premelt:
+ * add direct melt effects from Yamauchi and Takei, 2024. The `xfit_premelt` method will use the updated parameter values when `VBR.in.anelastic.xfit_premelt.include_direct_melt_effect = 1;` (default is 0, a future VBRc version will change the default to 1).
+ * change default exponential melt factor (the alpha in exp(-alpha*phi) in the viscosity relationship) from 25 to 30.
* add a `VBR_save` function for saving `VBR` structures
-* add framework for handling temporary files in test suite
\ No newline at end of file
+* add framework for handling temporary files in test suite
+* add convenience function, `full_nd`, to create filled arrays
+
+## Bug fix
+* fix for undefined behavior of pre-melt scaling at Tn == 1.0
\ No newline at end of file
diff --git a/vbr/support/vbr_categorical_cmap_array.m b/vbr/support/vbr_categorical_cmap_array.m
new file mode 100644
index 0000000..0b9c193
--- /dev/null
+++ b/vbr/support/vbr_categorical_cmap_array.m
@@ -0,0 +1,39 @@
+function x = vbr_categorical_cmap_array()
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %
+ % x = vbr_categorical_cmap_array()
+ %
+ % return an array of rgb values for a categorical colormap.
+ %
+ % colormap was generated with http://vrl.cs.brown.edu/color , see:
+ % Gramazio et al., 2017, IEEE Transactions on Visualization and Computer
+ % Graphics, "Colorgorical: creating discriminable and preferable color
+ % palettes for information visualization"
+ %
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ x = [get_cat_rgb(88,181,225); ...
+ get_cat_rgb(55,9,35); ...
+ get_cat_rgb(65,210,107); ...
+ get_cat_rgb(177,20,120); ...
+ get_cat_rgb(175,211,90); ...
+ get_cat_rgb(46,14,186); ...
+ get_cat_rgb(120,140,59); ...
+ get_cat_rgb(67,70,171); ...
+ get_cat_rgb(46,236,230); ...
+ get_cat_rgb(0,42,51); ...
+ get_cat_rgb(253,199,204); ...
+ get_cat_rgb(104,60,0); ...
+ get_cat_rgb(192,104,252); ...
+ get_cat_rgb(250,209,57); ...
+ get_cat_rgb(64,96,135); ...
+ get_cat_rgb(35,137,16); ...
+ get_cat_rgb(242,49,252); ...
+ get_cat_rgb(55,78,7); ...
+ get_cat_rgb(161,143,248); ...
+ get_cat_rgb(247,147,2)];
+
+end
+
+function rgb = get_cat_rgb(r, g, b)
+ rgb = [r, g, b] / 255;
+end
\ No newline at end of file
diff --git a/vbr/support/vbr_categorical_color.m b/vbr/support/vbr_categorical_color.m
new file mode 100644
index 0000000..29e09ef
--- /dev/null
+++ b/vbr/support/vbr_categorical_color.m
@@ -0,0 +1,24 @@
+function rgb = vbr_categorical_color(iclr)
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %
+ % rgb = vbr_categorical_color(iclr)
+ %
+ % return a single rgb value from the vbr_categorical_cmap_array.
+ %
+ % Parameters
+ % ----------
+ % iclr
+ % the index to sample from the colormap. Will be wrapped to be within
+ % the bounds of the colormap.
+ %
+ % Output
+ % ------
+ % rgb
+ % 3-element array of floating point rgb values in (0,1) range
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ rgbs = vbr_categorical_cmap_array();
+ ncolors = size(rgbs);
+ ncolors = ncolors(1);
+ iclr = ncolors - mod(iclr, ncolors);
+ rgb = rgbs(iclr, :);
+end
\ No newline at end of file
diff --git a/vbr/testing/test_utilities_full_nd.m b/vbr/testing/test_utilities_full_nd.m
new file mode 100644
index 0000000..0a73dea
--- /dev/null
+++ b/vbr/testing/test_utilities_full_nd.m
@@ -0,0 +1,34 @@
+function TestResult = test_utilities_full_nd()
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TestResult = test_utilities_full_nd()
+%
+% test full_nd
+%
+% Parameters
+% ----------
+% none
+%
+% Output
+% ------
+% TestResult struct with fields:
+% .passed True if passed, False otherwise.
+% .fail_message Message to display if false
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ x = full_nd(1.0, 2);
+ TestResult.passed = true;
+ TestResult.fail_message = '';
+ if all(size(x)==2) == 0
+ msg = 'full_nd failed full_nd(1.0, 2) check.';
+ TestResult.passed = false;
+ TestResult.fail_message = msg;
+ end
+
+ x = full_nd(1.0, 2, 4, 3);
+ sh = size(x);
+ if sh(1) ~= 2 | sh(2) ~= 4 | sh(3) ~= 3
+ msg = 'full_nd failed full_nd(1.0, 2, 4, 3) check.';
+ TestResult.passed = false;
+ TestResult.fail_message = msg;
+ end
+
+end
\ No newline at end of file
diff --git a/vbr/testing/test_utilities_vbr_categorical_cmap.m b/vbr/testing/test_utilities_vbr_categorical_cmap.m
new file mode 100644
index 0000000..261f964
--- /dev/null
+++ b/vbr/testing/test_utilities_vbr_categorical_cmap.m
@@ -0,0 +1,36 @@
+function TestResult = test_utilities_vbr_categorical_cmap()
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TestResult = test_utilities_vbr_categorical_cmap()
+%
+% test the categorical colormap
+%
+% Parameters
+% ----------
+% none
+%
+% Output
+% ------
+% TestResult struct with fields:
+% .passed True if passed, False otherwise.
+% .fail_message Message to display if false
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ TestResult.passed = true;
+ TestResult.fail_message = '';
+
+ x = vbr_categorical_cmap_array();
+ if max(x) > 1
+ msg = 'colormap rgb values contain value > 1';
+ TestResult.passed = false;
+ TestResult.fail_message = msg;
+ end
+
+ rgb_1 = vbr_categorical_color(1);
+ rgb_n1 = vbr_categorical_color(numel(x)+1);
+ if all(rgb_1==rgb_n1) == 0
+ msg = 'categorical colormap sample incorrectly wrapped';
+ TestResult.passed = false;
+ TestResult.fail_message = msg;
+ end
+
+end
\ No newline at end of file
diff --git a/vbr/testing/test_vbrcore_007_G_K_TP.m b/vbr/testing/test_vbrcore_007_G_K_TP.m
index 71d73c2..587c2c6 100644
--- a/vbr/testing/test_vbrcore_007_G_K_TP.m
+++ b/vbr/testing/test_vbrcore_007_G_K_TP.m
@@ -70,4 +70,5 @@
VBR.in.elastic.methods_list={'anharmonic';'anh_poro';};
VBR.in.anelastic.methods_list={'eburgers_psp';'andrade_psp';'xfit_mxw'};
VBR.in.viscous.methods_list={'HZK2011'};
+ VBR.in.elastic.quiet = 1;
end
diff --git a/vbr/testing/test_vbrcore_008_premelt_Tn_1.m b/vbr/testing/test_vbrcore_008_premelt_Tn_1.m
new file mode 100644
index 0000000..9c35b0e
--- /dev/null
+++ b/vbr/testing/test_vbrcore_008_premelt_Tn_1.m
@@ -0,0 +1,53 @@
+function TestResult = test_vbrcore_008_premelt_Tn_1()
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TestResult = test_vbrcore_008_premelt_Tn_1()
+%
+% test for undefined behavior at Tn == 1.0
+%
+% Parameters
+% ----------
+% none
+%
+% Output
+% ------
+% TestResult struct with fields:
+% .passed True if passed, False otherwise.
+% .fail_message Message to display if false
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ TestResult.passed=true;
+ TestResult.fail_message = '';
+
+ %% write method list %%
+ VBR.in.elastic.methods_list={'anharmonic'};
+ VBR.in.anelastic.methods_list={'xfit_premelt'};
+ VBR.in.anelastic.xfit_premelt.include_direct_melt_effect = 0;
+
+ % load anharmonic parameters, adjust Gu_0_ol and derivatives to match YT2016
+ VBR.in.elastic.anharmonic.Gu_0_ol=72.45; %[GPa]
+ VBR.in.elastic.anharmonic.dG_dT = -10.94*1e6; % Pa/C (equivalent ot Pa/K)
+ VBR.in.elastic.anharmonic.dG_dP = 1.987; % GPa / GPa
+
+ %% Define the Thermodynamic State %%
+ VBR.in.SV.T_K=1200:25:1500;
+ VBR.in.SV.T_K=VBR.in.SV.T_K+273;
+ VBR.in.SV.Tsolidus_K = VBR.in.SV.T_K;
+ sz=size(VBR.in.SV.T_K); % temperature [K]
+ VBR.in.SV.P_GPa = full_nd(2.5, sz); % pressure [GPa]
+ VBR.in.SV.dg_um=full_nd(0.01 * 1e6, sz); % grain size [um]
+ VBR.in.SV.rho = full_nd(3300, sz); % density [kg m^-3]
+ VBR.in.SV.sig_MPa = full_nd(.1, sz); % differential stress [MPa]
+ VBR.in.SV.phi = full_nd(0.0, sz);
+ VBR.in.SV.f = 1 ; % 1 Hz
+
+ [VBR] = VBR_spine(VBR);
+
+ if sum(VBR.out.viscous.xfit_premelt.diff.eta == 0.0) > 0
+ msg = 'xfit_premelt.diff.eta contains 0.0 values';
+ TestResult.passed = false;
+ TestResult.fail_message = msg;
+ end
+
+end
+
+
diff --git a/vbr/testing/test_vbrcore_009_premelt_direct.m b/vbr/testing/test_vbrcore_009_premelt_direct.m
new file mode 100644
index 0000000..027e29f
--- /dev/null
+++ b/vbr/testing/test_vbrcore_009_premelt_direct.m
@@ -0,0 +1,55 @@
+function TestResult = test_vbrcore_009_premelt_direct()
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TestResult = test_vbrcore_009_premelt_direct()
+%
+% test for when include_direct_melt_effect == 1
+%
+% Parameters
+% ----------
+% none
+%
+% Output
+% ------
+% TestResult struct with fields:
+% .passed True if passed, False otherwise.
+% .fail_message Message to display if false
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ TestResult.passed=true;
+ TestResult.fail_message = '';
+
+ %% write method list %%
+ VBR.in.elastic.methods_list={'anharmonic'};
+ VBR.in.anelastic.methods_list={'xfit_premelt'};
+ VBR.in.anelastic.xfit_premelt.include_direct_melt_effect = 1;
+
+ % load anharmonic parameters, adjust Gu_0_ol and derivatives to match YT2016
+ VBR.in.elastic.anharmonic.Gu_0_ol=72.45; %[GPa]
+ VBR.in.elastic.anharmonic.dG_dT = -10.94*1e6; % Pa/C (equivalent ot Pa/K)
+ VBR.in.elastic.anharmonic.dG_dP = 1.987; % GPa / GPa
+
+ %% Define the Thermodynamic State %%
+ VBR.in.SV.phi = logspace(-8,log10(0.05), 10);
+
+ sz=size(VBR.in.SV.phi); % temperature [K]
+ VBR.in.SV.T_K = full_nd(1350+273, sz);
+ VBR.in.SV.Tsolidus_K = full_nd(1300+273., sz);
+ VBR.in.SV.P_GPa = full_nd(2.5, sz); % pressure [GPa]
+ VBR.in.SV.dg_um=full_nd(0.01 * 1e6, sz); % grain size [um]
+ VBR.in.SV.rho = full_nd(3300, sz); % density [kg m^-3]
+ VBR.in.SV.sig_MPa = full_nd(.1, sz); % differential stress [MPa]
+
+ VBR.in.SV.f = 10.; % 1 Hz
+
+ [VBR] = VBR_spine(VBR);
+
+ Qinv = VBR.out.anelastic.xfit_premelt.Qinv;
+ phi = VBR.in.SV.phi;
+ dQdphi = (Qinv(2:end) - Qinv(1:end-1))./ (phi(2:end) - phi(1:end-1));
+ if sum(dQdphi<0) > 0
+ TestResult.passed=false;
+ TestResult.fail_message = 'Increasing melt fraction should increase Qinv.';
+ end
+end
+
+
diff --git a/vbr/vbrCore/functions/Q_xfit_premelt.m b/vbr/vbrCore/functions/Q_xfit_premelt.m
index 62f637b..c549e2e 100644
--- a/vbr/vbrCore/functions/Q_xfit_premelt.m
+++ b/vbr/vbrCore/functions/Q_xfit_premelt.m
@@ -16,28 +16,50 @@
disp('To use Q_xfit_premelt, you must provide VBR.in.SV.Tsolidus_K')
end
+ params=VBR.in.anelastic.xfit_premelt;
+
if has_solidus
% state variables
- if isfield(VBR.in.elastic,'anh_poro')
- Gu_in = VBR.out.elastic.anh_poro.Gu;
- elseif isfield(VBR.in.elastic,'anharmonic')
- Gu_in = VBR.out.elastic.anharmonic.Gu;
+ if params.include_direct_melt_effect == 1
+ % in YT2024, all poroealstic effects are applied internally to J1, so
+ % always use anharmonic as unrelaxed
+ Gu_in = VBR.out.elastic.anharmonic.Gu;
+ else
+ if isfield(VBR.in.elastic,'anh_poro')
+ Gu_in = VBR.out.elastic.anh_poro.Gu;
+ elseif isfield(VBR.in.elastic,'anharmonic')
+ Gu_in = VBR.out.elastic.anharmonic.Gu;
+ end
end
+
Ju_in = 1./Gu_in ;
rho = VBR.in.SV.rho ;
phi = VBR.in.SV.phi ;
Tn=VBR.in.SV.T_K./VBR.in.SV.Tsolidus_K ; % solidus-normalized temperature
- params=VBR.in.anelastic.xfit_premelt;
% maxwell time
[tau_m,VBR]=MaxwellTimes(VBR,Gu_in);
% calculate the Tn-dependent coefficients, A_p and sig_p
[A_p,sig_p]=calcApSigp(Tn,phi,params);
+ if params.include_direct_melt_effect == 1
+ Beta_B = params.Beta_B * phi;
+ else
+ Beta_B = 0.0;
+ end
+
+ % poroelastic J1 effect if applicable
+ if params.include_direct_melt_effect == 1
+ % poroelastic effect added to J1, Delta_poro
+ poro_elastic_factor = params.poro_Lambda * phi;
+ else
+ % no poroelastic effects outside of incoming unrelaxed modulus
+ poro_elastic_factor = 0.0;
+ end
% set other constants
alpha_B=params.alpha_B;
- A_B=params.A_B;
+ A_B_plus_Beta_B= params.A_B + Beta_B;
tau_pp=params.tau_pp;
% set up frequency dependence
@@ -48,20 +70,21 @@
n_freq = numel(VBR.in.SV.f);
sz = size(Gu_in);
J1 = proc_add_freq_indeces(zeros(sz),n_freq);
- J2 = J1; V = J1;
+ J2 = J1; V = J1; f_norm_glob=J1;
n_SVs=numel(Tn); % total elements in state variables
% loop over frequencies, calculate J1,J2
for i = 1:n_freq
+
sv_i0=(i-1)*n_SVs + 1; % starting linear index of this freq
sv_i1=sv_i0+n_SVs-1; % ending linear index of this freq
-
+ f_norm_glob(sv_i0:sv_i1)=tau_m*VBR.in.SV.f(i);
p_p=period_vec(i)./(2*pi*tau_m);
% tau_eta^S= tau_s / (2 pi tau_m);, tau_s = seismic wave period, tau_m = ss maxwell time
- ABppa=A_B*(p_p.^alpha_B);
+ ABppa=A_B_plus_Beta_B .* (p_p.^alpha_B);
lntaupp=log(tau_pp./p_p);
- J1(sv_i0:sv_i1)=Ju_in .* (1 + ABppa/alpha_B+ ...
+ J1(sv_i0:sv_i1)=Ju_in .* (1 + poro_elastic_factor + ABppa/alpha_B+ ...
pifac*A_p.*sig_p.*(1-erf(lntaupp./(sqrt(2).*sig_p))));
J2(sv_i0:sv_i1)=Ju_in*pi/2.*(ABppa+A_p.*(exp(-(lntaupp.^2)./(2*sig_p.^2)))) + ...
Ju_in.*p_p;
@@ -80,6 +103,7 @@
VBRout.Qinv = J2./J1.*(J2_J1_frac.^-1);
VBRout.Q = 1./VBRout.Qinv;
VBRout.M=1./sqrt(J1.^2+J2.^2);
+ VBRout.f_norm = f_norm_glob;
% calculate mean velocity along frequency dimension
VBRout.Vave = Q_aveVoverf(VBRout.V,VBR.in.SV.f);
@@ -87,6 +111,7 @@
VBRout.units = Q_method_units();
VBRout.units.M1 = 'Pa';
VBRout.units.M2 = 'Pa';
+ VBRout.units.f_norm = '';
% store the output structure
VBR.out.anelastic.xfit_premelt=VBRout;
@@ -101,11 +126,15 @@
Ap_Tn_pts=params.Ap_Tn_pts;
sig_p_Tn_pts=params.sig_p_Tn_pts;
- Beta=params.Beta; %
+ if params.include_direct_melt_effect == 1
+ Beta_p = params.Beta; % this depends on melt fraction in YT2024
+ else
+ Beta_p = 0; % no direct melt dependence
+ end
A_p=zeros(size(Tn));
- A_p(Tn>=Ap_Tn_pts(3))=params.Ap_fac_3+Beta*phi(Tn>=Ap_Tn_pts(3));
- A_p(Tn= Ap_Tn_pts(3))=params.Ap_fac_3+Beta_p*phi(Tn >= Ap_Tn_pts(3));
+ A_p(Tn < Ap_Tn_pts(3))=params.Ap_fac_3;
+ A_p(Tn < Ap_Tn_pts(2))=params.Ap_fac_1 + params.Ap_fac_2*(Tn(Tn < Ap_Tn_pts(2))-Ap_Tn_pts(1));
A_p(Tn < Ap_Tn_pts(1))=params.Ap_fac_1;
sig_p=zeros(size(Tn));
diff --git a/vbr/vbrCore/functions/el_ModUnrlx_dTdP_f.m b/vbr/vbrCore/functions/el_ModUnrlx_dTdP_f.m
index fdb7a2d..5d8f338 100644
--- a/vbr/vbrCore/functions/el_ModUnrlx_dTdP_f.m
+++ b/vbr/vbrCore/functions/el_ModUnrlx_dTdP_f.m
@@ -37,9 +37,19 @@
Gu_TP = VBR.in.elastic.Gu_TP; % Pa
% calculate bulk modulus
-disp(['Unrelaxed shear modulus was provided without an unrelaxed bulk modulus.', ...
- ' Calculating bulk modulus assuming nu=', num2str(nu), ...
- '. Set VBR.in.elastic.Ku_TP to specify a value.']);
+ if isfield(VBR.in.elastic,'quiet')
+ quiet_mode = VBR.in.elastic.quiet;
+ else
+ quiet_mode = 0;
+ end
+
+ if quiet_mode == 0
+ msg = ['Unrelaxed shear modulus was provided without an unrelaxed ', ...
+ 'bulk modulus. Calculating bulk modulus assuming nu=', num2str(nu), ...
+ '. Set VBR.in.elastic.Ku_TP to specify a value or set ', ...
+ 'VBR.in.elastic.quiet = 1 to silence this warning.'];
+ disp(msg);
+ end
Ku_TP = calc_Ku(Gu_TP,nu);
else
dT = (VBR.in.SV.T_K-T_K_ref);
diff --git a/vbr/vbrCore/functions/full_nd.m b/vbr/vbrCore/functions/full_nd.m
new file mode 100644
index 0000000..4abb0bb
--- /dev/null
+++ b/vbr/vbrCore/functions/full_nd.m
@@ -0,0 +1,23 @@
+function X = full_nd(fill_val, varargin)
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %
+ % X = full_nd(fill_val, N)
+ %
+ % returns an N-D array filled with a constant. After fill_val, all arguments
+ % are forwarded to ones().
+ %
+ % Parameters:
+ % ----------
+ % fill_val
+ % the number to fill the array (or matrix) with
+ %
+ % remaining arguments are forwarded to ones().
+ %
+ %
+ % Output:
+ % ------
+ % matrix
+ %
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ X = ones(varargin{:}) * fill_val;
+end
\ No newline at end of file
diff --git a/vbr/vbrCore/functions/visc_calc_xfit_premelt.m b/vbr/vbrCore/functions/visc_calc_xfit_premelt.m
index 35cd6cc..1d8ddcc 100644
--- a/vbr/vbrCore/functions/visc_calc_xfit_premelt.m
+++ b/vbr/vbrCore/functions/visc_calc_xfit_premelt.m
@@ -130,7 +130,7 @@
T_eta=params.T_eta;
gamma=params.gamma;
lambda=params.alpha; % rename to be consistent with YT2016 nomenclature
-
+ B = params.B;
A_n=zeros(size(Tn));
A_n(Tn= T_eta) & (Tn < 1);
A_n(msk)=exp(-(Tn(msk)-T_eta)./(Tn(msk)-Tn(msk)*T_eta)*log(gamma));
- msk=(Tn > 1);
- A_n(msk)=exp(-lambda*phi(msk))/gamma;
+ msk=(Tn >= 1);
+ A_n(msk)=exp(-lambda*phi(msk))/gamma/B;
end
diff --git a/vbr/vbrCore/params/Params_Anelastic.m b/vbr/vbrCore/params/Params_Anelastic.m
index 62d7e78..dd41324 100644
--- a/vbr/vbrCore/params/Params_Anelastic.m
+++ b/vbr/vbrCore/params/Params_Anelastic.m
@@ -102,7 +102,8 @@
if strcmp(method,'xfit_premelt')
% xfit_premelt parameters
- params.citations={'Yamauchi and Takei, 2016, J. Geophys. Res. Solid Earth, https://doi.org/10.1002/2016JB013316'};
+ params.citations={'Yamauchi and Takei, 2016, J. Geophys. Res. Solid Earth, https://doi.org/10.1002/2016JB013316';
+ 'Yamauchi and Takei, 2024, J. Geophys. Res. Solid Earth, https://doi.org/10.1029/2023JB027738'};
params.func_name='Q_xfit_premelt'; % the name of the matlab function
% high temp background spectrum
@@ -110,8 +111,7 @@
params.A_B=0.664; % high temp background dissipation strength
% pre-melting dissipation peak settings:
- params.tau_pp=6*1e-5; % peak center
- params.Beta=0; %
+ params.tau_pp=6*1e-5; % peak center, table 4 of YT16, paragraph before eq 10
params.Ap_fac_1=0.01;
params.Ap_fac_2=0.4;
params.Ap_fac_3=0.03;
@@ -120,6 +120,20 @@
params.sig_p_fac_3=7;
params.Ap_Tn_pts=[0.91,0.96,1]; % Tn cuttoff points
params.sig_p_Tn_pts=[0.92,1]; % Tn cuttoff points
+
+ % note: sig_p_fac2 and Ap_fac_2 above are combinations of the other constants
+ % and appear in the original papers as:
+ % sig_p_fac2 = (sig_p_fac_3-sig_p_fac_1) / (sig_p_Tn_pts(2) - sig_p_Tn_pts(1))
+ % Ap_fac_2 = (Ap_fac_3-Ap_fac_1) / (Ap_Tn_pts(3) - Ap_Tn_pts(1))
+
+ % melt effects. The following beta values are set to 0.0 within Q_xfit_premelt
+ % if include_direct_melt_effect = 0, corresponding to YT2016. If set to 1,
+ % the scaling will follow YT2024. Additionally, include_direct_melt_effect=1
+ % will trigger different poro-elastic behavior.
+ params.include_direct_melt_effect = 0; % set to 1 to include YT2024 melt effect
+ params.Beta=1.38; % this is determined in YT2024, named Beta_P in YT2024 eq 5
+ params.Beta_B=6.94; % YT2024 only
+ params.poro_Lambda = 4.0; % Table 6 YT2024,
params.description='pre-melting scaling';
end
diff --git a/vbr/vbrCore/params/Params_Viscous.m b/vbr/vbrCore/params/Params_Viscous.m
index fd5dc27..d33c266 100644
--- a/vbr/vbrCore/params/Params_Viscous.m
+++ b/vbr/vbrCore/params/Params_Viscous.m
@@ -47,9 +47,10 @@
params.citations={'Yamauchi and Takei, 2016, J. Geophys. Res. Solid Earth, https://doi.org/10.1002/2016JB013316'};
params.description='Steady state flow law for pre-melting viscosity drop, flow law parameters from fitting upper mantle.';
% near-solidus and melt effects
- params.alpha=25; % taken from diff. creep value of HZK2011. YT2016 call this lambda.
+ params.alpha=30; % taken from diff. creep value of HZK2011. YT2016 call this lambda.
params.T_eta=0.94;
params.gamma=5;
+ params.B = 1.0;
% method to use for melt-free diff. creep viscosity
params.eta_melt_free_method='xfit_premelt';