Skip to content

Commit

Permalink
Resolved merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashwin Kumar Rajagopalan authored and Ashwin Kumar Rajagopalan committed May 17, 2022
2 parents f22a974 + 3cdf396 commit 493d8e8
Show file tree
Hide file tree
Showing 40 changed files with 8,915 additions and 24 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ __pycache__/
#*.bib
*.xlsx
*.txt
*.zip

# Python related outputs
*.npy
Expand All @@ -25,6 +26,9 @@ __pycache__/
# C extensions
*.so

# MATLAB extensions
*.mat

# Distribution / packaging
.Python
build/
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "IsothermFittingTool"]
path = IsothermFittingTool
url = https://github.com/ImperialCollegeLondon/IsothermFittingTool.git
1 change: 1 addition & 0 deletions IsothermFittingTool
Submodule IsothermFittingTool added at 9eed15
1 change: 1 addition & 0 deletions experimental/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This folder contains files that are used for the experimental work of ERASE!!
226 changes: 226 additions & 0 deletions experimental/analysis/analyzeCalibration.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Imperial College London, United Kingdom
% Multifunctional Nanomaterials Laboratory
%
% Project: ERASE
% Year: 2021
% MATLAB: R2020a
% Authors: Ashwin Kumar Rajagopalan (AK)
% Hassan Azzan (HA)
%
% Purpose:
%
%
% Last modified:
% - 2021-05-10, AK: Remove single gas calibration
% - 2021-04-27, AK: Change the calibration model to linear interpolation
% - 2021-04-23, AK: Change the calibration model to Fourier series based
% - 2021-04-21, AK: Change the calibration equation to mole fraction like
% - 2021-04-19, AK: Change MFC and MFM calibration (for mixtures)
% - 2021-04-08, AK: Add ratio of gas for calibration
% - 2021-04-07, AK: Modify for addition of MFM
% - 2021-03-26, AK: Fix for number of repetitions
% - 2021-03-19, HA: Add legends to the plots
% - 2021-03-24, AK: Remove k-means and replace with averaging of n points
% - 2021-03-19, HA: Add kmeans calculation to obtain mean ion current for
% polynomial fitting
% - 2021-03-18, AK: Fix variable names
% - 2021-03-17, AK: Change structure
% - 2021-03-17, AK: Initial creation
%
% Input arguments:
%
% Output arguments:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function analyzeCalibration(parametersFlow,parametersMS)
% Find the directory of the file and move to the top folder
filePath = which('analyzeCalibration');
cd(filePath(1:end-21));

% Get the git commit ID
gitCommitID = getGitCommit;

% Load the file that contains the flow meter calibration
if ~isempty(parametersFlow)
flowData = load(parametersFlow);
% Analyse flow data
MFM = [flowData.outputStruct.MFM]; % MFM
MFC1 = [flowData.outputStruct.MFC1]; % MFC1
MFC2 = [flowData.outputStruct.MFC2]; % MFC2
UMFM = [flowData.outputStruct.UMFM]; % UMFM
% Get the volumetric flow rate
volFlow_MFM = [MFM.volFlow];
volFlow_MFC1 = [MFC1.volFlow]; % Flow rate for MFC1 [ccm]
setPt_MFC1 = [MFC1.setpoint]; % Set point for MFC1
volFlow_MFC2 = [MFC2.volFlow]; % Flow rate for MFC2 [ccm]
setPt_MFC2 = [MFC2.setpoint]; % Set point for MFC2
volFlow_UMFM = [UMFM.volFlow]; % Flow rate for UMFM [ccm]
% Find indices corresponding to pure gases
indexPureHe = find(setPt_MFC2 == 0); % Find pure He index
indexPureCO2 = find(setPt_MFC1 == 0); % Find pure CO2 index
% Parse the flow rate from the MFC, MFM, and UMFM for pure gas
% MFC
volFlow_MFC1_PureHe = volFlow_MFC1(indexPureHe);
volFlow_MFC2_PureCO2 = volFlow_MFC2(indexPureCO2);
% UMFM for pure gases
volFlow_UMFM_PureHe = volFlow_UMFM(indexPureHe);
volFlow_UMFM_PureCO2 = volFlow_UMFM(indexPureCO2);
% Calibrate the MFC
calibrationFlow.MFC_He = volFlow_MFC1_PureHe'\volFlow_UMFM_PureHe'; % MFC 1
calibrationFlow.MFC_CO2 = volFlow_MFC2_PureCO2'\volFlow_UMFM_PureCO2'; % MFC 2

% Compute the mole fraction of CO2 using flow data
moleFracCO2 = (calibrationFlow.MFC_CO2*volFlow_MFC2)./...
(calibrationFlow.MFC_CO2*volFlow_MFC2 + calibrationFlow.MFC_He*volFlow_MFC1);
indNoNan = ~isnan(moleFracCO2); % Find indices correponsing to no Nan
% Calibrate the MFM
% Fit a 23 (2nd order in mole frac and 3rd order in MFM flow) to UMFM
% Note that the MFM flow rate corresponds to He gas configuration in
% the MFM
modelFlow = fit([moleFracCO2(indNoNan)',volFlow_MFM(indNoNan)'],volFlow_UMFM(indNoNan)','poly23');
calibrationFlow.MFM = modelFlow;

% Also save the raw data into the calibration file
calibrationFlow.rawData = flowData;

% Save the calibration data into a .mat file
% Check if calibration data folder exists
if exist(['..',filesep,'experimentalData',filesep,...
'calibrationData'],'dir') == 7
% Save the calibration data for further use
save(['..',filesep,'experimentalData',filesep,...
'calibrationData',filesep,parametersFlow,'_Model'],'calibrationFlow',...
'gitCommitID');
else
% Create the calibration data folder if it does not exist
mkdir(['..',filesep,'experimentalData',filesep,'calibrationData'])
% Save the calibration data for further use
save(['..',filesep,'experimentalData',filesep,...
'calibrationData',filesep,parametersFlow,'_Model'],'calibrationFlow',...
'gitCommitID');
end

% Plot the raw and the calibrated data (for pure gases at MFC)
figure
MFC1Set = 0:80;
subplot(1,2,1)
hold on
scatter(volFlow_MFC1_PureHe,volFlow_UMFM_PureHe,'or')
plot(MFC1Set,calibrationFlow.MFC_He*MFC1Set,'b')
xlim([0 1.1*max(volFlow_MFC1_PureHe)]);
ylim([0 1.1*max(volFlow_UMFM_PureHe)]);
box on; grid on;
xlabel('He MFC Flow Rate [ccm]')
ylabel('He Actual Flow Rate [ccm]')
subplot(1,2,2)
hold on
scatter(volFlow_MFC2_PureCO2,volFlow_UMFM_PureCO2,'or')
plot(MFC1Set,calibrationFlow.MFC_CO2*MFC1Set,'b')
xlim([0 1.1*max(volFlow_MFC2_PureCO2)]);
ylim([0 1.1*max(volFlow_UMFM_PureCO2)]);
box on; grid on;
xlabel('CO2 MFC Flow Rate [ccm]')
ylabel('CO2 Actual Flow Rate [ccm]')

% Plot the raw and the calibrated data (for mixtures at MFM)
figure
x = 0:0.1:1; % Mole fraction
y = 0:1:150; % Total flow rate
[X,Y] = meshgrid(x,y); % Create a grid for the flow model
Z = modelFlow(X,Y); % Actual flow rate from the model % [ccm]
hold on
surf(X,Y,Z,'FaceAlpha',0.25,'EdgeColor','none');
scatter3(moleFracCO2,volFlow_MFM,volFlow_UMFM,'r');
xlim([0 1.1*max(X(:))]);
ylim([0 1.1*max(Y(:))]);
zlim([0 1.1*max(Z(:))]);
box on; grid on;
xlabel('CO2 Mole Fraction [-]')
ylabel('MFM Flow Rate [ccm]')
zlabel('Actual Flow Rate [ccm]')
view([30 30])
end

% Load the file that contains the MS calibration
if ~isempty(parametersMS)
% Call reconcileData function for calibration of the MS
[reconciledData, expInfo] = concatenateData(parametersMS);
% Find the index that corresponds to the last time for a given set
% point
setPtMFC = unique(reconciledData.flow(:,5));
% Find total number of data points
numDataPoints = length(reconciledData.flow(:,1));
% Total number of points per set point
numPointsSetPt = expInfo.maxTime/expInfo.samplingTime;
% Number of repetitions per set point (assuming repmat in calibrateMS)
numRepetitions = floor((numDataPoints/numPointsSetPt)/length(setPtMFC));
% Remove the 5 min idle time between repetitions
% For two repetitions
if numRepetitions == 2
indRepFirst = numPointsSetPt*length(setPtMFC)+1;
indRepLast = indRepFirst+numPointsSetPt-1;
reconciledData.flow(indRepFirst:indRepLast,:) = [];
reconciledData.MS(indRepFirst:indRepLast,:) = [];
reconciledData.moleFrac(indRepFirst:indRepLast,:) = [];
% For one repetition
elseif numRepetitions == 1
% Do nothing %
else
error('Currently more than two repetitions are not supported by analyzeCalibration.m');
end
% Find indices that corresponds to a given set point
indList = ones(numRepetitions*length(setPtMFC),2);
% Loop over all the set points
for kk = 1:numRepetitions
for ii=1:length(setPtMFC)
% Indices for a given set point accounting for set point and
% number of repetitions
initInd = length(setPtMFC)*numPointsSetPt*(kk-1) + (ii-1)*numPointsSetPt + 1;
finalInd = initInd + numPointsSetPt - 1;
% Find the mean value of the signal for numMean number of points
% for each set point
indMean = (finalInd-parametersMS.numMean+1):finalInd;
% MS Signal mean
meanHeSignal((kk-1)*length(setPtMFC)+ii) = mean(reconciledData.MS(indMean,2)); % He
meanCO2Signal((kk-1)*length(setPtMFC)+ii) = mean(reconciledData.MS(indMean,3)); % CO2
% Mole fraction mean
meanMoleFrac(((kk-1)*length(setPtMFC)+ii),1) = mean(reconciledData.moleFrac(indMean,1)); % He
meanMoleFrac(((kk-1)*length(setPtMFC)+ii),2) = mean(reconciledData.moleFrac(indMean,2)); % CO2
end
end
% Use a linear interpolation to fit the calibration data of the signal
% ratio w.r.t He composition
calibrationMS.ratioHeCO2 = fit((meanHeSignal./(meanCO2Signal+meanHeSignal))',meanMoleFrac(:,1),'linearinterp');

% Save the calibration data into a .mat file
% Check if calibration data folder exists
if exist(['..',filesep,'experimentalData',filesep,...
'calibrationData'],'dir') == 7
% Save the calibration data for further use
save(['..',filesep,'experimentalData',filesep,...
'calibrationData',filesep,parametersMS.flow,'_Model'],'calibrationMS',...
'gitCommitID','parametersMS');
else
% Create the calibration data folder if it does not exist
mkdir(['..',filesep,'experimentalData',filesep,'calibrationData'])
% Save the calibration data for further use
save(['..',filesep,'experimentalData',filesep,...
'calibrationData',filesep,parametersMS.flow,'_Model'],'calibrationMS',...
'gitCommitID','parametersMS');
end

% Plot the raw and the calibrated data
figure(1)
plot(meanHeSignal./(meanHeSignal+meanCO2Signal),meanMoleFrac(:,1),'or') % Experimental
hold on
plot(0:0.001:1,calibrationMS.ratioHeCO2(0:0.001:1),'b')
xlim([0 1]);
ylim([0 1]);
box on; grid on;
xlabel('Helium Signal/(CO2 Signal+Helium Signal) [-]')
ylabel('Helium mole frac [-]')
set(gca,'FontSize',8)
end
end
115 changes: 115 additions & 0 deletions experimental/analysis/analyzeExperiment.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Imperial College London, United Kingdom
% Multifunctional Nanomaterials Laboratory
%
% Project: ERASE
% Year: 2021
% MATLAB: R2020a
% Authors: Ashwin Kumar Rajagopalan (AK)
% Hassan Azzan (HA)
%
% Purpose:
% Script to define inputs to calibrate flowmeter and MS or to analyze a
% real experiment using calibrated flow meters and MS
%
% Last modified:
% - 2021-07-23, AK: Add calibration model to the output
% - 2021-07-02, AK: Bug fix for threshold
% - 2021-05-10, AK: Convert into a function
% - 2021-04-20, AK: Add experiment struct to output .mat file
% - 2021-04-19, AK: Major revamp for flow rate computation
% - 2021-04-13, AK: Add threshold to cut data below a given mole fraction
% - 2021-04-08, AK: Add ratio of gas for calibration
% - 2021-03-24, AK: Add flow rate computation and prepare structure for
% Python script
% - 2021-03-18, AK: Updates to structure
% - 2021-03-18, AK: Initial creation
%
% Input arguments:
%
% Output arguments:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function analyzeExperiment(experimentStruct,flagCalibration,flagFlowMeter)
% Get the git commit ID
gitCommitID = getGitCommit;

% Mode to switch between calibration and analyzing real experiment
% Analyze calibration data
if flagCalibration
% Calibrate flow meter
if flagFlowMeter
% File with the calibration data to build a model for MFC/MFM
experimentStruct = 'ZLCCalibrateMeters_20210419'; % Experimental flow file (.mat)
% Call analyzeCalibration function for calibration of the MS
analyzeCalibration(experimentStruct,[]) % Call the function to generate the calibration file
% Calibrate MS
else
% Call analyzeCalibration function for calibration of the MS
analyzeCalibration([],experimentStruct) % Call the function to generate the calibration file
end
% Analyze real experiment
else
% Call reconcileData function to get the output mole fraction for a
% real experiment
[outputStruct,~] = concatenateData(experimentStruct);

% Clean mole fraction to remove negative values (due to calibration)
% Replace all negative molefraction with eps
outputStruct.moleFrac(outputStruct.moleFrac(:,2)<0,1)=eps; % CO2
outputStruct.moleFrac(:,1)=1-outputStruct.moleFrac(:,2); % Compute He with mass balance

% Convert the MFM flow to real flow
% Load the meter calibrations
load(experimentStruct.calibrationFlow);
% Get the MFM flow rate
volFlow_MFM = outputStruct.flow(:,2);
% Get the CO2 mole fraction for obtaining real flow rate
moleFracCO2 = outputStruct.moleFrac(:,2);
% Compute the total flow rate of the gas [ccm]
% Round the flow rate to the nearest first decimal (as this is the
% resolution of the meter)
totalFlowRate = round(calibrationFlow.MFM(moleFracCO2,volFlow_MFM),1);

% Input for the ZLC script (Python)
% Find the index for the mole fraction that corresponds to the
% threshold mole fraction
moleFracThresholdInd = min([find(outputStruct.moleFrac(:,2)<experimentStruct.moleFracThreshold,1,'first'),...
find(~isnan(totalFlowRate),1,'last')]); % Additional check to weed out nan flow due to interpolation
% Set the final index to be the length of the series, if threshold not
% reached
if isempty(moleFracThresholdInd)
moleFracThresholdInd = length(outputStruct.moleFrac(:,2));
end
experimentOutput.timeExp = outputStruct.flow(1:moleFracThresholdInd,1); % Time elapsed [s]
experimentOutput.moleFrac = outputStruct.moleFrac(1:moleFracThresholdInd,2); % Mole fraction CO2 [-]
experimentOutput.totalFlowRate = totalFlowRate(1:moleFracThresholdInd)./60; % Total flow rate of the gas [ccs]
experimentOutput.volFlow_MFM = volFlow_MFM; % Actual MFM flow rate of the gas [ccm]
% Flow calibration model
% p00 + p10*x + p01*y + p20*x^2 + p11*x*y + p02*y^2 + p21*x^2*y + p12*x*y^2 + p03*y^3
% x - mole fraction of CO2; y = volumetric flow rate from MFM [ccm]
% This wilL be used in the simulateCombinedModel.py to compute the
% correct flow accounting for the time lag in the concentration
% due to the MS
experimentOutput.flowCalibration = coeffvalues(calibrationFlow.MFM)'; % Coefficient of flow calibration
% Save outputStruct to semiProcessedStruct
semiProcessedStruct = outputStruct; % Check concatenateData for more (this is reconciledData there)
% Save the experimental output into a .mat file
% Check if runData data folder exists
if exist(['..',filesep,'experimentalData',filesep,...
'runData'],'dir') == 7
% Save the calibration data for further use
save(['..',filesep,'experimentalData',filesep,...
'runData',filesep,experimentStruct.flow,'_Output'],'experimentOutput',...
'experimentStruct','semiProcessedStruct','gitCommitID');
else
% Create the calibration data folder if it does not exist
mkdir(['..',filesep,'experimentalData',filesep,'runData'])
% Save the calibration data for further use
save(['..',filesep,'experimentalData',filesep,...
'runData',filesep,experimentStruct.flow,'_Output'],'experimentOutput',...
'experimentStruct','semiProcessedStruct','gitCommitID');
end
end
end
Loading

0 comments on commit 493d8e8

Please sign in to comment.