#pragma rtGlobals=1 // Use modern global access method. #include #include Window Panel01() : Panel PauseUpdate; Silent 1 // building window... VARIABLE/G NPFSTime, NPFEtime NewPanel /W=(356,388,1025,883) ShowTools SetDrawLayer UserBack SetDrawEnv linethick= 0 DrawRect 26,12,563,48 SetDrawEnv fname= "Century Gothic",fsize= 25,fstyle= 1 DrawText 32,43,"PARGAN (PARticle Growth And Nucleation)" SetDrawEnv linethick= 3,fname= "MS Sans Serif" DrawText 188,101,"Time wave" SetDrawEnv linethick= 3,fname= "MS Sans Serif" DrawText 187,176,"dN/dLogDp (cm-3)" SetDrawEnv linethick= 3,fname= "MS Sans Serif",fstyle= 1 DrawText 30,372,"Calculate Growth Rate (nm.h-1)" SetDrawEnv linethick= 3,fname= "MS Sans Serif",fstyle= 1 DrawText 294,373,"Calculate Nucleation Rate (cm-3.s-1)" SetDrawEnv linethick= 3,fname= "MS Sans Serif",fstyle= 1 DrawText 28,74,"Input files " SetDrawEnv linethick= 3,fname= "MS Sans Serif" DrawText 186,207,"Raw count matrix" SetDrawEnv linethick= 3,fname= "MS Sans Serif" DrawText 186,137,"Diameter wave (nm)" SetDrawEnv linefgc= (65280,0,0),fillfgc= (65280,0,0) DrawRect 22,77,184,223 Button Obtaining_growth_rate,pos={27,377},size={167,30},proc=Growth_Rate,title="Calculate Growth Rate" Button Graph_growthvstime,pos={28,413},size={167,28},proc=Call_Graph_growth_vs_time,title="Plot: Growth Rate vs Time" Button Obtaining_nucl_rate,pos={294,378},size={185,28},proc=Nucl_Rate,title="Calculate Nucleation Rate (J)" Button Graph_nuclrate,pos={294,446},size={186,28},proc=Nucl_Rate_Graphs,title="Plot: Nucl Rate vs Time" Button nuclrate_median,pos={294,412},size={185,28},proc=Get_Nucl_Rate_median,title="Get 1 min. interval median J" Button load_n1,pos={26,229},size={155,30},proc=Makebanana_func,title="Make Banana Plot" Button load_n1,fStyle=0 Button load_dndlogdpmatrix,pos={27,155},size={155,30},proc=Input_dNdlogDp_matrix,title="Load dN_dlogD" Button load_dndlogdpmatrix,fStyle=0 Button load_rawcounts_matrix,pos={26,190},size={155,30},proc=input_counts,title="Load Raw Counts matrix" Button load_rawcounts_matrix,fStyle=0 SetVariable NPFStartTime,pos={29,266},size={155,16},title="NPF starting point" SetVariable NPFStartTime,value= NPFSTime SetVariable NPFendingTime,pos={31,286},size={155,16},title="NPF ending point" SetVariable NPFendingTime,value= NPFEtime Button load_n2,pos={29,308},size={155,30},proc=Select_NPFtime,title="Select NPF time" Button load_n2,fStyle=0 Button load_dndlogdpmatrix1,pos={26,80},size={155,30},proc=input_time,title="Load time" Button load_dndlogdpmatrix1,fStyle=0 Button load_dndlogdpmatrix2,pos={26,118},size={155,30},proc=input_diam,title="Load Dp" Button load_dndlogdpmatrix2,fStyle=0 Button Graph_nuclrate1,pos={493,446},size={130,28},proc=save_GR_Jnuc,title="Save GR and Jnuc" Button load_dndlogdpmatrix3,pos={302,157},size={155,30},proc=Input_dNdlogDp_matrix,title="Load dN_dlogD" Button load_dndlogdpmatrix3,fStyle=0 Button load_rawcounts_matrix1,pos={303,190},size={155,30},proc=Input_cnt_matrix,title="Load Raw Counts matrix" Button load_rawcounts_matrix1,fStyle=0 EndMacro //SetVariable var_str_row_5,pos={309,382},size={174,20},title="Time Interval (min)" //SetVariable var_str_row_5,help={"Enter the starting date"},value= K16 //Button nuclrate_median1,pos={489,377},size={102,28},proc=Get_Jmedian,title="Get median J" NVAR NPFSTime, NPFEtime //VARIABLE/G NPFSTime, NPFEtime //FUNCTION Load_diffusionfactor(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LOADWAVE/A/J/D/A=DC_factor/P=$pathname/K=0 filename // DUPLICATE/O DC_factor0 DC_factor // KILLWAVES/Z DC_factor0 //END //FUNCTION input_time(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LOADWAVE/A/J/D/A=t_wave/P=$pathname/K=0 filename // DUPLICATE/O t_wave0 t_wave // KILLWAVES/Z t_wave0 //END // //FUNCTION input_diam(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LoadWave/A/J/D/A=diam/P=$pathname/K=0 filename // DUPLICATE/O diam0 diam // MAKE/D/O/N=(NUMPNTS(diam)) radius // radius = diam/2. // KILLWAVES/Z diam0 //END //FUNCTION Input_dNdlogDp_matrix(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LoadWave/J/M/U={0,0,0,0}/D/O/N=n/K=0/P=$pathname filename // DUPLICATE/O n0 n // KILLWAVES/Z n0 // // //############# Fitting lognormal fucntion to the data #################### // WAVE t_wave, diam // VARIABLE rows,cols // rows=DIMSIZE(t_wave,0) // cols=DIMSIZE(diam,0) // MAKE/D/N=(rows,cols) dNdlogDp // dNdlogDp=n // //SMOOTH/B=3 2, dNdlogDp // SMOOTH/B=2 5,dNdlogDp // // MAKE/O/D/N=(3350) actual_N, smoothed_N // VARIABLE i,j,nn,mm // actual_N=NAN // smoothed_N=NAN // nn=0 // mm=0 // FOR(i=0;i=0.0) //// dNdlogDp_fitted_matrix[i][j] = dNdlogDp_fitted_wave[j] //// ELSE //// dNdlogDp_fitted_matrix[i][j] =NAN //// ENDIF //// ENDFOR //// //// ENDFOR //// //// DUPLICATE/O/D dNdlogDp_fitted_matrix dNdlogDp // // //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // // Note that for dNdlogDp and raw counts matrix should be rows=rows_diam AND cols=rows_t_wave // //Since we have opposite formatting as required, we need to transpose dNdlogDp and raw count matrix's // //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // MAKE/O/D/N=( (DIMSIZE(dNdlogDp,1)), (DIMSIZE(dNdlogDp,0)) ) dNdlogDp_dum // DUPLICATE/O/D dNdlogDp dNdlogDp_dum,dNdlogDp_plot // Redimension dNdlogDp_dum // MatrixTranspose dNdlogDp_dum // DUPLICATE/O/D dNdlogDp_dum dNdlogDp // KILLWAVES dNdlogDp_dum //END // //// this input count matrix , same as dndlogdp format //FUNCTION input_counts(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LoadWave/J/M/U={0,0,0,0}/D/O/N=cnt/K=0/P=$pathname filename // DUPLICATE/O cnt0 cnt // KILLWAVES/Z cnt0 // //// WAVE t_wave, diam //// VARIABLE rows,cols,i,j //// rows=DIMSIZE(t_wave,0) //// cols=DIMSIZE(diam,0) //// //// MAKE/D/N=(rows,cols) cnt_init //// cnt_init = cnt // //SMOOTH/B= 3 2, cnt // SMOOTH/B=2 5,cnt //// //// MAKE/O/D/N=(cols) cnt_wave,cnt_fitted_wave //// MAKE/O/D/N=(rows,cols) cnt_fitted_matrix //// FOR(i=0;i= N)) // The exit condition, when no more cells are found or the index reaches N (END of the STRING) Count += 1 Print "Count :", Count BREAK ENDIF result = STRSEARCH(Midpoints, "\t", index) // Get the index of "\t" IF(result != -1) // IF found Count += 1 // increment Count of cells by 1 index = result + 1 // set the starting index of next search iteration to the last "\t" index found plus 1 ENDIF WHILE(1) VARIABLE M_Col = Count MAKE/O/D/N=(M_Col) Dp result = 0 Count = 0 index = 0 i = 0 // Determine the length of the entier sting DO IF((result == -1) || (index >= N)) // The exit condition, when no more cells are found or the index reaches N (END of the STRING) Count += 1 Dp[Count-1] = STR2NUM(Midpoints[index, N-1]) BREAK ENDIF result = STRSEARCH(Midpoints, "\t", index) // Get the index of "\t" IF(result != -1) // IF found Count += 1 // increment Count of cells by 1 Dp[Count-1] = STR2NUM(Midpoints[index, result]) index = result + 1 // set the starting index of next search iteration to the last "\t" index found plus 1 ENDIF WHILE(1) //################### READ dNdlogDp matrix - this is column formatted matrix ###################### rows=DIMSIZE(SMPS_datetime,0) cols=DIMSIZE(Dp,0) LOADWAVE/A=X/O/J/M/D/A=WAVE/P=$pathName/K=0/L={0,16,0,3,cols} fileName //WAVE DC_factor //MAKE/O/D/N=(cols) DC_factor_div //DC_factor_div = NAN //DC_factor_div = DC_factor MAKE/O/D/N=(rows, cols) dNdlogDp WAVE X0 FOR(i=0;i= lower_limit_fitted[i] && Diam[j] <= upper_limit_fitted[i]) // dNdlogDp_dummy[i][j] = dNdlogDp[i][j] // ELSE // dNdlogDp_dummy[i][j] =1E-6 // ENDIF // // ENDFOR // ENDFOR // DUPLICATE/O/D dNdlogDp_dummy dNdlogDp //############# Fitting lognormal fucntion to the data #################### SMOOTH/B=2 5,dNdlogDp //fit_lognormal() //DUPLICATE/O/D dNdlogDp_fitted_matrix dNdlogDp //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Note that for dNdlogDp and raw counts matrix should be rows=rows_diam AND cols=rows_t_wave //Since we have opposite formatting as required, we need to transpose dNdlogDp and raw count matrix's //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MAKE/O/D/N=( (DIMSIZE(dNdlogDp,1)), (DIMSIZE(dNdlogDp,0)) ) dNdlogDp_dum DUPLICATE/O/D dNdlogDp dNdlogDp_dum,dNdlogDp_plot Redimension dNdlogDp_dum MatrixTranspose dNdlogDp_dum DUPLICATE/O/D dNdlogDp_dum dNdlogDp KILLWAVES dNdlogDp_dum END //################### READ Raw Counts matrix - this is also column formatted matrix ###################### FUNCTION Input_cnt_matrix(ctrlName) : ButtonControl STRING ctrlName STRING pathname="" STRING filename="" VARIABLE rows, cols,i,j WAVE t_wave,Diam WAVE lower_limit_fitted,upper_limit_fitted rows=DIMSIZE(t_wave,0) cols=DIMSIZE(Diam,0) LOADWAVE/A=X/O/J/M/D/A=WAVE/P=$pathName/K=0/L={0,16,0,3,cols} fileName MAKE/O/D/N=(rows, cols) cnt WAVE X0 FOR(i=0;i= lower_limit_fitted[i] && Diam[j] <= upper_limit_fitted[i]) // cnt_dummy[i][j] = cnt_fitted_matrix[i][j] // ELSE // cnt_dummy[i][j] =1E-6 // ENDIF // // ENDFOR // ENDFOR // DUPLICATE/O/D cnt_dummy cnt //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // Note that for dNdlogDp and raw counts matrix should be rows=rows_diam AND cols=rows_t_wave //Since we have opposite formatting as required, we need to transpose dNdlogDp and raw count matrix's //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MAKE/O/D/N=( (DIMSIZE(cnt,1)), (DIMSIZE(cnt,0)) ) cnt_dum DUPLICATE/O/D cnt cnt_dum Redimension cnt_dum MatrixTranspose cnt_dum DUPLICATE/O/D cnt_dum cnt KILLWAVES cnt_dum KILLWAVES X0 END //FUNCTION input_time(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LOADWAVE/A/J/D/A=t_wave/P=$pathname/K=0 filename // DUPLICATE/O t_wave0 t_wave // KILLWAVES/Z t_wave0 //END // //FUNCTION input_diam(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LoadWave/A/J/D/A=diam/P=$pathname/K=0 filename // DUPLICATE/O diam0 diam // MAKE/D/O/N=(NUMPNTS(diam)) radius // radius = diam/2. // KILLWAVES/Z diam0 //END // // // this input count wave for definition dndlogdp/count ////FUNCTION input_counts(ctrlName) : ButtonControl //// STRING ctrlName //// STRING pathname="" //// STRING filename="" //// LOADWAVE/J/D/N=cnt/O/K=0/P=$pathname filename //// DUPLICATE/O cnt0 cnt //// KILLWAVES/Z cnt0 ////END // //// this input count matrix , same as dndlogdp format //FUNCTION input_counts(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LoadWave/J/M/U={0,0,0,0}/D/O/N=cnt/K=0/P=$pathname filename // DUPLICATE/O cnt0 cnt // KILLWAVES/Z cnt0 //END // // //FUNCTION input_n(ctrlName) : ButtonControl // STRING ctrlName // STRING pathname="" // STRING filename="" // LoadWave/J/M/U={0,0,0,0}/D/O/N=dNdlogDp/K=0/P=$pathname filename // DUPLICATE/O dNdlogDp0 dNdlogDp // KILLWAVES/Z dNdlogDp0 //END // FUNCTION Makebanana_func(ctrlName) : ButtonControl STRING ctrlName WAVE t_wave, dNdlogDp_plot, diam,Geo_diam,Geo_diam_std Makebanana(t_wave, dNdlogDp_plot, diam,Geo_diam,Geo_diam_std ) END //FUNCTION fit_lognormal() // WAVE dNdlogDp,diam,t_wave // VARIABLE rows=DIMSIZE(t_wave,0) // VARIABLE cols=DIMSIZE(diam,0) // VARIABLE i,j // // MAKE/O/D/N=(cols) dNdlogDp_wave,dNdlogDp_fitted_wave // MAKE/O/D/N=(rows,cols) dNdlogDp_fitted_matrix // FOR(i=0;i -10) // i.e. if it is a real data value IF (NUMTYPE(name_of_wave[i]) == 0) // i.e. if it is a real data value name_of_wave[i] = name_of_wave[i] ELSE // i.e. if it is either INF or NaN name_of_wave[i] = num ENDIF i = i+1 WHILE(i < NUMPNTS(name_of_wave)) END FUNCTION stdev_cnt(scan) // Calculates sd(dNc/dt) from imported matrix of # counts VARIABLE scan WAVE bin, cnt, Nc_t1, Nc_t2, dNc_dt, dt, n_t1, d_lnr, Nc_avg, dNdlogDp, n_t2 //, prop_11_16_run13 NVAR L VARIABLE f_sd, i DUPLICATE/O/D bin cnt_t1, cnt_t2, prop_t1, prop_t2, var_dn, var_dNc, sd_dNc_dt, sd_n DUPLICATE/D/O bin var_stat_t1, var_stat_t2, var_flow_t1, var_flow_t2, var_one, sd_dn_dt, var_dN_ind f_sd = 0.01 // empirical number cnt_t1 = cnt[p][scan] // number of counts in a bin: taken from matrix of counts as input. cnt_t2 = cnt[p][scan+1] i = 0 IF(NUMTYPE(cnt_t1[p]) == 0 ) DO IF ( cnt_t1[i]>0 ) prop_t1[i] = n_t1[i]*d_lnr[i] / cnt_t1[i] ELSE // proportionality constant between concentration and counts prop_t1[i] = 0 // because otherwise st.dev. becomes NaN. ENDIF IF(cnt_t2[i]>0 ) prop_t2[i] = n_t2[i]*d_lnr[i] / cnt_t2[i] ELSE prop_t2[i] = 0 ENDIF i = i+1 WHILE(ir_max (radius[0]). When resulting size "a" is larger than centre radius of largest bin, both // "fraction" and "upper" get messed up. In that case, dn/dt is 100% appointed to the largest bin, i.e. particles are not allowed to be produced outside the // size range. This way, volume (and thus mass) is (more or less) conserved, and the ratio of total loss/production remains 2, which can be checked. DO //dn_dt_ind[0] = dn_dt_ind[0] + dn_dt_ind_raw[m] // case 1 & 3 dn_dt_ind[0] = dn_dt_ind[0] + dn_dt_ind_raw[m]/d_lnr[0] // case 2 m = m-1 // m = m+1 for small to large size and m = m-1 for large to small size WHILE( m>=0) // ( m=0 ) for large to small size KILLWAVES a2, a, n_avg_a2, Kc_n_n_J, int_Kc_n_n_J_wave, upper, fraction KILLWAVES d_lnr_2, int_Kc_n_n_J_sum, jacobian, dn_dt_ind_raw //, dn_dt_ind END FUNCTION coag_rate_constant(R1,R2) // kinetic correction is included (enhancement factor). calculates the coagulation rate constant for a pair of particles. // cgs units: K_coag in cm^3 /s , equations given in CHEM5740-First Handout are used: convention for identical particles. // "factor of two" included in rate expression, not in rate constant K_coag. VARIABLE R1, R2 VARIABLE K_coag, Kc_kin, Kc_con, c_ij, red_mass, a1, a2, D_ij, t_ij, beta_const VARIABLE xx, yy, E0, Einf, RedHam NVAR Boltz, Temp, density a1 = 1.0e-7*R1 // convert from nm to cm a2 = 1.0e-7*R2 red_mass = (((4/3)*density*PI)^2 *(a1^3)*(a2^3)) / (((4/3)*density*pi)*((a1^3)+(a2^3))) // reduced mass (g) c_ij = SQRT(8*Boltz*Temp/(PI*red_mass)) // mean relative speed of the pair of particles (cm/s) // compute the enhancement factors [Chan and Mozurkewich, 2001]. //RedHam = 16 // reduced Hamaker Constant //ergs // 1.6E6 Joule RedHam = 6.4E-13 //ergs // 6.4E-20 Joule xx = ln(1+RedHam) yy = SQRT(RedHam) E0 = 1 + 0.0757*xx + 0.0015*xx^3 Einf = 1 + ((yy/SQRT(3))/(1+0.0151*yy)) - 0.186*xx - 0.0163*xx^3 Kc_kin = (a1+a2)^2 * 0.5*PI*c_ij*Einf // Kinetic regime rate constant D_ij = diffusioncoeff(R1) + diffusioncoeff(R2) Kc_con = 2*PI*D_ij*(a1+a2)*E0 // Continuum regime rate constant t_ij = Kc_kin/(2*Kc_con) // same as tij/2 in Sceats beta_const = SQRT(1+(t_ij^2)) - t_ij K_coag = Kc_kin*beta_const // Transition regime rate constant (Sceats, 1989) //IF(R10.1"}//,"K6>0.1"} // when coag and wall loss are fitted simultaneously //T_Constraints = {"K1>0.7","K1<1"} // when alpha is fitted //T_Constraints = {"K1>0.7","K1<1","K2>0.08","K2<0.12"} // when DiffCoeff is fitted //T_Constraints = {"K8>0.0001"}//,"K9>20","K9<40"} // when svp & surface tension are fitted w_all = NaN w_all[0][] = -999 // set growth rate to -999 instead of NaN, to not interfere with interpolation sigma_w = NaN res_all = NaN coag_total_loss_rate = NaN //coag_total_loss_r_ex_nano = NaN coag_net_rate = NaN //dNc_dt_all = NaN res_dNc_dt = NaN Conf_IV_g = NaN scan = first_g DO WAVE W_ParamConfidenceInterval start (scan) losses( ) UC_dNc_dt = NaN LC_dNc_dt = NaN UP_dNc_dt = NaN LP_dNc_dt = NaN dNc_dt_calc =NaN coag_total_loss_rate[scan] = coag_loss_rate[L-1] // dN(total)/dt due to coag loss //coag_total_loss_r_ex_nano[scan] = coag_loss_rate[29] // idem, excl nanoDMA (Pacific 2001) coag_net_rate[][scan] = dn_dt_coag_loss[p] - dn_dt_coag_prod[p] // dn/dt due to coag loss-prod, for each size bin. // performs the fit, to be repeated for each time interval specified. //FuncFit /Q/H="01111111" GDE w dNc_dt[first_g, last_g] /I=1 /W=sd_dNc_dt /D=dNc_dt_calc /R ///C=T_Constraints //FuncFit /Q/G/H="01111111" GDE w dNc_dt[first_g, last_g] /W=sd_dNc_dt /I=1 /D=dNc_dt_calc /R /F={0.95, 7, Contour, UC_dNc_dt, LC_dNc_dt, UP_dNc_dt, LP_dNc_dt} //FUNCFIT/Q/G/H="01111111" GDE w dNc_dt[first_g, last_g] /W=sd_dNc_dt /I=1 /D=dNc_dt_calc /R /F={0.95, 4} //7, Contour, UC_dNc_dt, LC_dNc_dt, UP_dNc_dt, LP_dNc_dt} // FuncFit /Q/H="01111111" GDE w dNc_dt /I=1/W=sd_dNc_dt /D=dNc_dt_calc /R //C=T_Constraints //FUNCFIT/Q/G/H="01111111" GDE w dNc_dt[first_g, last_g] /W=sd_dNc_dt /D=dNc_dt_calc /R /F={0.95, 4} FuncFit /Q/G/H="01111111" GDE w dNc_dt[first_g, last_g] /W=sd_dNc_dt /I=1 /D=dNc_dt_calc /R /F={0.99, 4}//, Contour, UC_dNc_dt, LC_dNc_dt, UP_dNc_dt, LP_dNc_dt} rel_res = Res_dNc_dt / sd_dNc_dt // chi = relative residual / standard deviation i = 0 DO w_all[i][scan] = w[i] // save fit parameters in matrix w_all sigma_w[i][scan] = w_sigma[i] // save estimated error of fit parameters in matrix sigma_w i = i + 1 m = 0 DO res_all[m][scan] = Res_dNc_dt[m] / sd_dNc_dt[m] // matrix of rel_res // during the fit, weighted residuals (res./sd.) are written to matrix res_all // abs_res_all[m][scan] = Res_dNc_dt[m] // dNc_dt_all[m][scan] = dNc_dt[m] // during the fit, the values for dNc_dt are written to matrix dNc_dt_all m = m+1 WHILE(m < L) WHILE(i < NUMPNTS(w)) w_all[NUMPNTS(w)][scan] = V_chisq // save chi-squared of fit Conf_IV_g[scan] = W_ParamConfidenceInterval[0] // confidence interval of fit parameter w[0] = growth rate // sigma_w[numpnts(w)+1][scan] = w_sigma[0] // save st.dev. of growth estimate scan = scan + 1 WHILE(scan <= last_g) // defines the number of the last time interval to be analyzed growth = w_all[0][p] // wave of size-averaged growth rate (at infinite Kn) for each time interval i = 0 DO IF(growth[i] == -999 || growth > 300 || growth < -300 ) growth[i] = NaN ENDIF i = i+1 WHILE(i < NUMPNTS(growth)) rate_c = w_all[8][p] * 3600 // wave of size-averaged rate (at infinite Kn) for each time interval //duplicate/O/D growth g_smooth //Smooth 7, g_smooth // adapt smoothing according to amount of noise in growth vs. time chisq = w_all[NUMPNTS(w)][p] // wave of chi-squared values sigma_g = sigma_w[0][p] // wave of IGOR reported (estimated) sd of growth estimate duplicate/O/D sigma_g error_g_all, error_scatter // V_npnts is number of size bins included in the fit error_scatter = SQRT(chisq/(V_npnts-1)) // error related to scatter around the obtained value for fit parameter // This assumes only one parameter being fitted (# degrees of freedom = V_npnts - # fit parameters) //error_g_all = sigma_g * error_scatter // combined error (estimated (expected) and from scatter) error_g_all = Conf_IV_g * error_scatter // combined error (estimated (expected) and from scatter) //killwaves error_scatter, sigma_g, w_sigma //separate_factors() //chi_squared(first, last) // Elaborate error analysis using chi-values END FUNCTION GDE(w,bin) : FitFunc // describes fitting function: General Dynamic Equation in cumulative form, n=dN/dln(r) WAVE w // wave holding the parameters that can be fitted VARIABLE bin NVAR L WAVE Nc_avg, n_avg, radius, coag_loss_rate, nn_avg2, nn_avg WAVE wall_diff_rate, wall_grav_rate, coag_prod_rate // , first_rate,appear,appear_rate // Input data tables. VARIABLE growth, wall, dNc_dt_calc, coag, rate //two_dim_avg(w) // VARIABLE appear // appearance rate of particles at smallest size (due to nucleation) // growth applies Fuchs/Sutugin correction for all sizes. // w[0] is the radius growth rate (nm/h) divided by gamma at infinite Knudsen number (g_0) // w[1] is alpha // w[2] is the diffusion coefficient of the condensing species // w[3] is coagulation loss and production multiplier, which multiplies both by the same factor // w[4] is coagulation loss multiplier // w[5] is coagulation production multiplier // w[6] is diffusional wall loss multiplier // w[7] is gravitational wall loss multiplier // w[3] should not be fitted simultaneously with either w[4] or w[5] // the "multiplier" parameters are set equal to 1 to give the calculated value // growth = ((w[0]-evaporation(radius[bin], w[8], w[9], 1))/3600)*nn_avg[bin]*Gamma_meas(radius[bin], w[1], w[2]) growth = (w[0]/3600)*nn_avg[bin]*Gamma_meas(radius[bin], w[1], w[2]) coag = w[3] * ( (coag_loss_rate[bin]*w[4]) - (coag_prod_rate[bin]*w[5])) wall = (wall_diff_rate[bin]*w[6]) + (wall_grav_rate[bin]*w[7]) // + w[8]*Nc_avg[bin] // rate = first_rate[bin] * w[8] // appear = appear_rate[bin] * w[9] //IF(bin == (L-1) ) // appear = w[9] //ELSEIF(bin < (L-1) ) // appear = 0 //ENDIF dNc_dt_calc = growth - coag - wall //+ rate// + appear RETURN dNc_dt_calc END FUNCTION Gamma_meas( radius, alpha, DiffCoef) // Returns the apparent sticking coefficient for the given parameters. // DiffCoef is the gas phase diffusion coeffcient of the condensing species == 0.1 cm^2/s (+/- 10%) for H2SO4 VARIABLE radius, alpha, DiffCoef VARIABLE lambda, resistance NVAR speed_gas lambda = (1e7*3*DiffCoef) / speed_gas // lambda (nm) of condensible species resistance = (1/alpha) + ((3*radius)/(4*lambda)) - ((0.47*radius)/(radius+lambda)) RETURN 1/resistance // dimensionless gamma END FUNCTION Call_Graph_growth_vs_time(ctrlName) : ButtonControl STRING ctrlName Graph_growth_vs_time( ) END FUNCTION save_GR_Jnuc(ctrlName) : ButtonControl STRING ctrlName WAVE t_midgrowth,growth_smth,t_meas_long,Jnuc SMOOTH/B=2 5, J_nucl Save/J/M="\r\n" t_midgrowth, growth_smth as "GR_.txt" Save/J/M="\r\n" t_form_long,J_nucl as "Jnucl_.txt" END FUNCTION Graph_growth_vs_time() : Graph //Save/J/M="\r\n" t_midgrowth as "GR_time.txt" //Save/J/M="\r\n" growth as "GR.txt" wave growth IF(growth > 300 || growth < -300) growth=NAN ENDIF PauseUpdate; Silent 1 Display /W=(294.75,333.5,590.25,552.5) growth vs t_midgrowth as "growth_vs_time" ModifyGraph mode=3 ModifyGraph marker=19 ModifyGraph tick=2 ModifyGraph mirror=1 ModifyGraph minor=1 ModifyGraph sep(left)=15,sep(bottom)=10 ModifyGraph lblMargin(bottom)=2 ModifyGraph standoff=0 ModifyGraph axOffset(left)=-2.71429,axOffset(bottom)=-0.1875 ModifyGraph lblLatPos(left)=-1,lblLatPos(bottom)=-9 ModifyGraph dateInfo(bottom)={1,1,0} Label left "growth rate (nm/h)" Label bottom "time" SetAxis/A/N=1 left ModifyGraph dateInfo(bottom)={1,0,0} print "GR=", MedianEO(growth, 0, DIMSIZE(t_midgrowth,0)-1) print "GR=", Median(growth, 0, DIMSIZE(t_midgrowth,0)-1) END //################################################################### //################### Obtaining Nucleation Rates ########################## //################################################################### FUNCTION Nucl_Rate(ctrlName) : ButtonControl STRING ctrlName NVAR K VARIABLE first_g,last_g first_g = 0 last_g = K Fit_Kw() Fit_kc1() Fit_Kc() back_calc_mult(first_g, last_g) END FUNCTION Fit_Kw() // fit the wall loss rate constant to powerlaw of form K_w = wall_const/radius MAKE/D/O/N=20 a_small, Kw_s, Kw_fit_s VARIABLE/G wall_const VARIABLE i WAVE w NVAR r_nucl a_small[0] = r_nucl i = 1 DO a_small[i] = a_small[i-1] + 0.5 i = i+1 WHILE(i<20) Kw_s = wall_loss_diff(a_small) * w[6] K0 = 0 K1 = 0.00098*w[6] K2 = -1 //CurveFit/G Power Kw_s /X=a_small /D=Kw_fit_s CurveFit/G/H="101" Power Kw_s /X=a_small /D=Kw_fit_s wall_const = K1 // nm/s //KILLWAVES/Z a_small, Kw_s, Kw_fit_s END FUNCTION Fit_kc1() // Fitting a power-law to the pseudo first order coagulation rate constant to be used for back-calculation. // Kc1(a) = Sum(Kc2(a,A)*n(A)) = i+C*a^p, where a1e-15", "K1>1e-15", "K2<-1", "K2>-2"} scan = 0 // the parameter for scan number, i.e. time DO i = 0 // the parameter for a_small DO Kc1_wave = 0 // not NaN, because then Kc1_wave[L-1] returns NaN. Kc1_wave_sc = 0 r_var = a_small[i] Kc2_r_var = w[3] * coag_rate_constant(r_var,radius) // 2nd order K_coag Kc1_wave = dNdlogDp[p][scan] * Kc2_r_var * d_lnr // ps. 1st order K_coag for sc. by all part. j = 0 // the parameter for bin number of scavenging particle DO // only inlcude scavenging by larger particles than r_var itself: Kc1_wave_sc[j] = dNdlogDp[j][scan] * Kc2_r_var[j] * d_lnr[j] // ps. 1st order K_coag j = j+1 WHILE( (jr_var) ) j = 0 // the parameter for bin number of scavenging particle DO // only inlcude scavenging by much larger, accumulation mode particles: Kc1_wave_sc_acc[j] = dNdlogDp[j][scan] * Kc2_r_var[j] * d_lnr[j] // ps. 1st order K_coag j = j+1 WHILE( (j<21) && (radius[j]>r_var) ) //Kc1[i] = sum(Kc1_wave, 0, L) // identical to rectangular integration INTEGRATE Kc1_wave // summation over all bins: rectangular integration INTEGRATE Kc1_wave_sc // summation over all bins: rectangular integration INTEGRATE Kc1_wave_sc_acc // summation over all bins: rectangular integration Kc1[i] = Kc1_wave[L-1] Kc1_sc[i] = Kc1_wave_sc[L-1] Kc1_sc_acc[i] = Kc1_wave_sc_acc[L-1] // note that Kc1 has a different meaning here than in previous function. i = i+1 WHILE(i 0"} i = 0 DO // Calculate K_coag as it is actually used in the fit procedure by including w[3] Kc_x = coag_rate_constant(a_small, radius[i]) * w[3] w_Kc_fit1 = w_Kc_fit[p][i] CurveFit/G Power KwCWave=w_Kc_fit1 Kc_x /X=a_small /D=Kc_fit_x /C=T_Constraints_coag w_Kc_fit[][i] = w_Kc_fit1[p] //w_Kc_fit contains fitting parameters for Kc as a function of radius(A). i = i+1 //WHILE(radius[i] > a_small[19]) WHILE(i t_wave[scan] ) // This "can not" happen, but strangely enough, it does. t_form[bin][scan] = 999 // discard formation times that are later than actual measurement ELSE t_form[bin][scan] = t_form_ind_var // wave of formation times for particular meas. time (scan) //For each value of "bin", the wave "n_back_ind" is overwritten. nn_form_cor[bin][scan] = correct_losses_mult(bin,scan) // corrected for losses. //fill_n_back(bin, scan) //Only executed t_form is later than first measurement time, unless //you are interested in checking n_back_all //nn_form_cor_ind[bin] = n[bin][scan]/r_back_ind[scan] // n[bin][scan]/radius[bin] not corrected for losses. //n_back_ind is now specified. ENDIF //NOTE: enable the next two command if you want to look at the backcalculated waves //If not, better put previous command within last "else-endif" loop to save computing time. //specifies r_back_all & n_back_all for one value of bin & scan. //nn_form_cor[bin][scan] = correct_losses_mult(bin, scan) // corrected for losses. //fill_n_back(bin, scan) bin=bin+1 //print "Updated bin and L=",bin,L //WHILE(bin<36) WHILE(bin5E2 || J_nucl[i] < 1E-4) J_nucl[i]=NAN ENDIF ENDFOR //DUPLICATE/O/D g_long growth_smth //SMOOTH/B=3 3, growth_smth //DUPLICATE/O/D J_nucl J_nucl_smth //SMOOTH/B=3 3, J_nucl_smth //J_nucl_new = nn_form_long*g_long/3600 // Nucleation Rate, NOT corrected //J_new_wmcp = J_nucl_new*wmcp_F_long/wmc_F_long //ratio_b1_long = b1_F_long / (dep_F_long*coagsc_F_long) //ratio_b1p_long = b1p_F_long / (dep_F_long*coagsc_F_long) //coag_total = wmc_F_long*coagsc_F_long //MAKE/D/O ratio_b1_h //HISTOGRAM/B={0, 0.1, 20} ratio_b1_long, ratio_b1_h //DUPLICATE/O/D ratio_b1_h ratio_b1 //ratio_b1[0] = 0.05 //i=1 //DO // ratio_b1[i] = ratio_b1[i-1]+0.1 // i=i+1 //WHILE(i<20) // for losses having occurred before time of measurement. Include measured radius and time of measurement in table for clarity: r_meas_long = radius[p] REDIMENSION/D/N=(K*L) r_meas_long i=0 j=0 t_meas_long = NaN DO // this nested do-loop writes a t_meas at each r_meas. DO t_meas_long[i] = t_wave[j] i=i+1 WHILE( i<((j+1)*L) ) j=j+1 WHILE(j0 // Kw = (1/R)*wall_const; sqrt(...) = sqrt(D) i = scan-1 DO // calculates loss processes integrated backwards to t_form IF( r_back_ind[i]>r_nucl ) r_var_2 = r_back_ind[i+1] // the later (larger) radius r_var_1 = r_back_ind[i] // the earlier (smaller) radius r_var = (r_var_1+r_var_2) / 2 g_r_var = growth[i]*gamma_meas(r_var, w[1], w[2])/3600 ELSEIF(r_back_ind[i+1]>r_nucl) // When r_var_1 surpasses value of r_nucl, set it equal to r_nucl // At this point, n(t_N) is calculated, used to obtain J. r_var_2 = r_back_ind[i+1] r_var_1 = r_nucl r_var = (r_var_1+r_var_2) / 2 g_r_var = INTERP(r_nucl, r_back_ind, growth) /3600 //j = i ELSE //To not let either r_var decrease below r_nucl. r_var_2 = r_nucl r_var_1 = r_nucl r_var = r_nucl g_r_var = interp(r_nucl, r_back_ind, growth) /3600 ENDIF IF(g_r_var > 0) DF_wave[i] = (r_var_2/r_var_1)^(wall_const/g_r_var) // w[6] included in wall_const (see fit_Kw()) ELSE DF_wave[i] = 1 ENDIF // DF = deposition factor to correct n(a) backwards in time and size. // DF = exp[-int(1/a)da*(wall_const/g_r_var)] = exp[ln(a1/a2)*(w_c/g)] // DF_wave[i] = 1/exp( -w[6]*wall_loss_diff(r_var)*(r_var_2-r_var_1)/g_r_var ) // For coagulation, using average value of k(a) over delta_t (and thus delta_a) // integrate fitted power law for Kc(II) and sum over all values of A to obtain // pseudo first order rate constant, Kc1_r_var for Kc(a,A) for one value of a (r_var) and all values of A (radius). //Kc1_int1 = i_fit_c*r_var_1 + ( (c_fit_c/(p_fit_c+1)) * r_var_1^(p_fit_c+1) ) //Kc1_int2 = i_fit_c*r_var_2 + ( (c_fit_c/(p_fit_c+1)) * r_var_2^(p_fit_c+1) ) //Kc1_int = 0 //NaN //j = 0 // j = bin of n[j][i] that r_var is scavenged by. //DO // Only coag scavenging by particles larger than r_meas should be included. // Kc1_int[j] = (n[j][i]+n[j][i+1])/2 * (Kc1_int2[j]-Kc1_int1[j]) * d_lnr[j] // j = j+1 //WHILE(radius[j] > r_meas) //Kc1_int = (n[p][i]+n[p][i+1])/2 * (Kc1_int2-Kc1_int1) * d_lnr //Kc2_r_var = w[3]*coag_rate_constant(r_var,radius) // 2nd order K_coag //Kc1 = (n[p][i]+n[p][i+1])/2 * Kc2_r_var * d_lnr // ps. 1st order K_coag //Kc1_r_var = sum(Kc1_int, 0, L) //CF_wave[i] = exp( Kc1_r_var*(r_var_2-r_var_1)/g_r_var ) // for averaging method. //CF_wave[i] = exp( Kc1_r_var/g_r_var ) // for integration method. inner_int = 0 // necessary to include before do- loop, to avoid Inf values. //inner_int = d_lnr * w[3]*coag_rate_constant(r_var,radius) * (n[p][i+1]+n[p][i])/2 // scav by all part. n_t1 = dNdlogDp[p][i] // to read in from dN/dlnr matrix (produced by awk) n_t2 = dNdlogDp[p][i+1] // dN/dlnr (units of r don't matter) replace_NaN_by_num(n_t1, 0) replace_NaN_by_num(n_t2, 0) //SMOOTH/B=2/F/E=3 7, n_t1 // NOTE THE SMOOTHING!!! //SMOOTH/B=2/F/E=3 7, n_t2 Smooth/B=2 5, n_t1 Smooth/B=2 5, n_t2 inner_int = d_lnr * w[3]*coag_rate_constant(r_var,radius) * (n_t1+n_t2)/2 // scav by all part. //j = 0 // j = bin of n[j][i] that r_var is scavenged by. //DO // include only coag scavenging by particles larger than r_meas, but not smaller than r_det // inner_int[j] = d_lnr[j] * w[3]*coag_rate_constant(r_var,radius[j]) * (n[j][i+1]+n[j][i])/2 //inner integral evaluated for r_var (average value of backwards calculated radius) // j = j+1 //WHILE( (jr_var) ) //r_var = cohort radius; r_meas = measured radius ////integrate inner_int_1 // inner integral for r_var_1 ////integrate inner_int_2 // inner integral for r_var_2 INTEGRATE inner_int // inner integral for r_var IF(g_r_var > 0) CF_wave[i] = exp( inner_int[L-1] * (r_var_2 - r_var_1) / g_r_var ) ELSE CF_wave[i] = 1 ENDIF //print CF_wave[i] //print CF_wave[i-1] ///////CF_wave[i] = exp( ( (inner_int_2[L-1]+inner_int_1[L-1])*(r_var_2-r_var_1) )/g_r_var ) IF( r_back_ind[i+1]=r_nucl) && (i>=0) ) //while( i>= 0) //54) //0 ) // CF_wave and DF_wave are computed for each "backwards" timestep. // Total correction factor obtained by multiplying all individual ones. CF = 1 DF = 1 m = scan-1 DO CF = CF * CF_wave[m] DF = DF * DF_wave[m] m = m-1 WHILE(m>0) //m = 0 //DO // CF = CF * CF_wave[m] // DF = DF * DF_wave[m] // m = m+1 //WHILE(m 998) r_back_all[(scan*L)+bin][i] = NaN ELSE r_back_all[(scan*L)+bin][i] = r_back_ind[i] ENDIF i=i+1 WHILE(i1 ) min_point = TRUNC( ( temp_wave[ref] + temp_wave[ref-1] ) / 2 ) max_point = TRUNC( (temp_wave[ref] + temp_wave[ref+1] ) / 2 ) IF( t_form_long[i] > max_point ) DO ref = ref+1 new_nucl_time_median [ref] = temp_wave[ref] new_nucl_median[ref] = NAN min_point = TRUNC( ( temp_wave[ref] + temp_wave[ref-1] ) / 2 ) max_point = TRUNC( (temp_wave[ref] + temp_wave[ref+1] ) / 2 ) WHILE(t_form_long[i] > max_point && ref < size) ENDIF IF(t_form_long[i] >= min_point && t_form_long[i] <=max_point) MAKE/O/D temp_median DO temp_median[m] = J_nucl [i] m=m+1 i=i+1 WHILE( t_form_long[i] >= min_point && t_form_long[i] <=max_point && i< size_inputdata ) new_nucl_time_median [ref] = temp_wave[ref] IF(DIMSIZE(temp_median,0) >1) new_nucl_median[ref] = MEAN( temp_median, 0, m-1) ELSE new_nucl_median[ref] = temp_median[0] ENDIF KILLWAVES temp_median m=0 ELSEIF( t_form_long[i] > max_point ) ref = ref+1 ELSEIF( t_form_long[i] < min_point) i=i+1 ENDIF //ENDIF WHILE( i< size_inputdata && ref < size) END FUNCTION Nucl_Rate_Graphs(ctrlName) : ButtonControl STRING ctrlName variable x1 J_nucl_graph() END FUNCTION J_nucl_graph() : Graph PauseUpdate; Silent 1 // building window... WAVE growth,t_midgrowth DUPLICATE/D growth growth_new VARIABLE i FOR(i=0;i 300 ) growth_new[i] = NAN ELSE growth_new[i] = growth[i] ENDIF ENDFOR DUPLICATE/D growth_new growth_smth SMOOTH/B=3 3, growth_smth Display growth_new vs t_midgrowth SetAxis bottom 36000,75600 SetAxis left 0,40 ModifyGraph mode=3,marker(growth_new)=5,rgb(growth_new)=(0,0,0) AppendToGraph/R J_nucl vs t_form_long ModifyGraph mode(J_nucl)=3 ModifyGraph msize(J_nucl)=2.5,rgb(J_nucl)=(30464,30464,30464) AppendToGraph growth_smth vs t_midgrowth ModifyGraph mode(growth_smth)=4,marker(growth_smth)=16,lsize(growth_smth)=1;DelayUpdate ModifyGraph rgb(growth_smth)=(0,0,65280) AppendToGraph nucl_median vs nucl_time_median ModifyGraph mode(nucl_median)=4,marker(nucl_median)=7;DelayUpdate ModifyGraph rgb(nucl_median)=(65280,0,0) SetAxis right 0.001,100 Legend/C/N=text0/F=0/A=MC ModifyGraph hideTrace(growth_new)=1,hideTrace(J_nucl)=1 Label left "GR (nm h-1)" Label right "Jnuc (cm-3 s-1)" ModifyGraph hideTrace=0 END END