diff --git a/testing/diff_output_files.py b/testing/diff_output_files.py new file mode 100644 index 00000000..b2a3da6b --- /dev/null +++ b/testing/diff_output_files.py @@ -0,0 +1,93 @@ +# Copyright (C) 2015-2023: The University of Edinburgh, United Kingdom +# Authors: Craig Warren, Antonis Giannopoulos, and John Hartley +# +# This file is part of gprMax. +# +# gprMax is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# gprMax is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with gprMax. If not, see . + +import logging +from pathlib import Path + +import h5py +import numpy as np + +logger = logging.getLogger(__name__) + +def diff_output_files(filename1, filename2): + """Calculates differences between two output files. + + Args: + filename1: string of filename (including path) of output file 1. + filename2: string of filename (including path) of output file 2. + + Returns: + time: numpy array containing time. + datadiffs: numpy array containing power (dB) of differences. + """ + + file1 = h5py.File(Path(filename1), "r") + file2 = h5py.File(Path(filename2), "r") + # Path to receivers in files + path = "rxs/rx1/" + + # Get available field output component names + outputs1 = list(file1[path].keys()) + outputs2 = list(file2[path].keys()) + if outputs1 != outputs2: + logger.exception("Field output components are not the same in each file") + raise ValueError + + # Check that type of float used to store fields matches + floattype1 = file1[path + outputs1[0]].dtype + floattype2 = file2[path + outputs2[0]].dtype + if floattype1 != floattype2: + logger.warning( + f"Type of floating point number in test model ({file1[path + outputs1[0]].dtype}) " + f"does not match type in reference solution ({file2[path + outputs2[0]].dtype})\n" + ) + + # Arrays for storing time + time1 = np.zeros((file1.attrs["Iterations"]), dtype=floattype1) + time1 = np.linspace(0, (file1.attrs["Iterations"] - 1), num=file1.attrs["Iterations"]) + time2 = np.zeros((file2.attrs["Iterations"]), dtype=floattype2) + time2 = np.linspace(0, (file2.attrs["Iterations"] - 1), num=file2.attrs["Iterations"]) + + # Arrays for storing field data + data1 = np.zeros((file1.attrs["Iterations"], len(outputs1)), dtype=floattype1) + data2 = np.zeros((file2.attrs["Iterations"], len(outputs2)), dtype=floattype2) + for ID, name in enumerate(outputs1): + data1[:, ID] = file1[path + str(name)][:] + data2[:, ID] = file2[path + str(name)][:] + if np.any(np.isnan(data1[:, ID])) or np.any(np.isnan(data2[:, ID])): + logger.exception("Data contains NaNs") + raise ValueError + + file1.close() + file2.close() + + # Diffs + datadiffs = np.zeros(data1.shape, dtype=np.float64) + for i in range(len(outputs2)): + maxi = np.amax(np.abs(data1[:, i])) + datadiffs[:, i] = np.divide( + np.abs(data2[:, i] - data1[:, i]), maxi, out=np.zeros_like(data1[:, i]), where=maxi != 0 + ) # Replace any division by zero with zero + + # Calculate power (ignore warning from taking a log of any zero values) + with np.errstate(divide="ignore"): + datadiffs[:, i] = 20 * np.log10(datadiffs[:, i]) + # Replace any NaNs or Infs from zero division + datadiffs[:, i][np.invert(np.isfinite(datadiffs[:, i]))] = 0 + + return time1, datadiffs diff --git a/testing/models_pmls/plot_pml_comparison.py b/testing/models_pmls/plot_pml_comparison.py deleted file mode 100644 index 95c5a79f..00000000 --- a/testing/models_pmls/plot_pml_comparison.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright (C) 2015-2023: The University of Edinburgh, United Kingdom -# Authors: Craig Warren, Antonis Giannopoulos, and John Hartley -# -# This file is part of gprMax. -# -# gprMax is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# gprMax is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with gprMax. If not, see . - -import itertools -import logging -from operator import add -from pathlib import Path - -import h5py -import matplotlib.pyplot as plt -import numpy as np - -logger = logging.getLogger(__name__) - -# Create/setup plot figure -# colors = ['#E60D30', '#5CB7C6', '#A21797', '#A3B347'] # Plot colours from http://tools.medialab.sciences-po.fr/iwanthue/index.php -# colorIDs = ["#62a85b", "#9967c7", "#b3943f", "#6095cd", "#cb5c42", "#c95889"] -colorIDs = ["#79c72e", "#5774ff", "#ff7c2c", "#4b4e80", "#d7004e", "#007545", "#ff83ec"] -# colorIDs = ["#ba0044", "#b2d334", "#470055", "#185300", "#ff96b1", "#3e2700", "#0162a9", "#fdb786"] -colors = itertools.cycle(colorIDs) -# for i in range(2): -# next(colors) -lines = itertools.cycle(("--", ":", "-.", "-")) -markers = ["o", "d", "^", "s", "*"] - -parts = Path(__file__).parts -path = "rxs/rx1/" -basename = "pml_3D_pec_plate" -PMLIDs = ["CFS-PML", "HORIPML-1", "HORIPML-2", "MRIPML-1", "MRIPML-2"] -maxerrors = [] -testmodels = ["pml_3D_pec_plate_" + s for s in PMLIDs] - -fig, ax = plt.subplots( - subplot_kw=dict(xlabel="Iterations", ylabel="Error [dB]"), figsize=(20, 10), facecolor="w", edgecolor="w" -) - -for x, model in enumerate(testmodels): - # Open output file and read iterations - fileref = h5py.File(Path(*parts[:-1], basename, basename + "_ref.h5"), "r") - filetest = h5py.File(Path(*parts[:-1], basename, basename + str(x + 1) + ".h5"), "r") - - # Get available field output component names - outputsref = list(fileref[path].keys()) - outputstest = list(filetest[path].keys()) - if outputsref != outputstest: - logger.exception("Field output components do not match reference solution") - raise ValueError - - # Check that type of float used to store fields matches - if filetest[path + outputstest[0]].dtype != fileref[path + outputsref[0]].dtype: - logger.warning( - f"Type of floating point number in test model ({filetest[path + outputstest[0]].dtype}) " - f"does not match type in reference solution ({fileref[path + outputsref[0]].dtype})\n" - ) - floattyperef = fileref[path + outputsref[0]].dtype - floattypetest = filetest[path + outputstest[0]].dtype - # logger.info(f'Data type: {floattypetest}') - - # Arrays for storing time - # timeref = np.zeros((fileref.attrs['Iterations']), dtype=floattyperef) - # timeref = np.linspace(0, (fileref.attrs['Iterations'] - 1) * fileref.attrs['dt'], num=fileref.attrs['Iterations']) / 1e-9 - # timetest = np.zeros((filetest.attrs['Iterations']), dtype=floattypetest) - # timetest = np.linspace(0, (filetest.attrs['Iterations'] - 1) * filetest.attrs['dt'], num=filetest.attrs['Iterations']) / 1e-9 - timeref = np.zeros((fileref.attrs["Iterations"]), dtype=floattyperef) - timeref = np.linspace(0, (fileref.attrs["Iterations"] - 1), num=fileref.attrs["Iterations"]) - timetest = np.zeros((filetest.attrs["Iterations"]), dtype=floattypetest) - timetest = np.linspace(0, (filetest.attrs["Iterations"] - 1), num=filetest.attrs["Iterations"]) - - # Arrays for storing field data - dataref = np.zeros((fileref.attrs["Iterations"], len(outputsref)), dtype=floattyperef) - datatest = np.zeros((filetest.attrs["Iterations"], len(outputstest)), dtype=floattypetest) - for ID, name in enumerate(outputsref): - dataref[:, ID] = fileref[path + str(name)][:] - datatest[:, ID] = filetest[path + str(name)][:] - if np.any(np.isnan(datatest[:, ID])): - logger.exception("Test data contains NaNs") - raise ValueError - - fileref.close() - filetest.close() - - # Diffs - datadiffs = np.zeros(datatest.shape, dtype=np.float64) - for i in range(len(outputstest)): - maxi = np.amax(np.abs(dataref[:, i])) - datadiffs[:, i] = np.divide( - np.abs(datatest[:, i] - dataref[:, i]), maxi, out=np.zeros_like(dataref[:, i]), where=maxi != 0 - ) # Replace any division by zero with zero - - # Calculate power (ignore warning from taking a log of any zero values) - with np.errstate(divide="ignore"): - datadiffs[:, i] = 20 * np.log10(datadiffs[:, i]) - # Replace any NaNs or Infs from zero division - datadiffs[:, i][np.invert(np.isfinite(datadiffs[:, i]))] = 0 - - # Print maximum error value - start = 210 - maxerrors.append(f": {np.amax(datadiffs[start::, 1]):.1f} [dB]") - logger.info(f"{model}: Max. error {maxerrors[x]}") - - # Plot diffs (select column to choose field component, 0-Ex, 1-Ey etc..) - ax.plot(timeref[start::], datadiffs[start::, 1], color=next(colors), lw=2, ls=next(lines), label=model) - ax.set_xticks(np.arange(0, 2200, step=100)) - ax.set_xlim([0, 2100]) - ax.set_yticks(np.arange(-160, 0, step=20)) - ax.set_ylim([-160, -20]) - ax.set_axisbelow(True) - ax.grid(color=(0.75, 0.75, 0.75), linestyle="dashed") - -mylegend = list(map(add, PMLIDs, maxerrors)) -legend = ax.legend(mylegend, loc=1, fontsize=14) -frame = legend.get_frame() -frame.set_edgecolor("white") -frame.set_alpha(0) - -plt.show() - -# Save a PDF/PNG of the figure -# fig.savefig(basepath + '.pdf', dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1) -# fig.savefig(savename + '.png', dpi=150, format='png', bbox_inches='tight', pad_inches=0.1) diff --git a/testing/models_pmls/pml_3D_pec_plate/plot_pml_comparison.py b/testing/models_pmls/pml_3D_pec_plate/plot_pml_comparison.py new file mode 100644 index 00000000..52968ef1 --- /dev/null +++ b/testing/models_pmls/pml_3D_pec_plate/plot_pml_comparison.py @@ -0,0 +1,80 @@ +# Copyright (C) 2015-2023: The University of Edinburgh, United Kingdom +# Authors: Craig Warren, Antonis Giannopoulos, and John Hartley +# +# This file is part of gprMax. +# +# gprMax is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# gprMax is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with gprMax. If not, see . + +import itertools +import logging +from operator import add +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np + +from testing.diff_output_files import diff_output_files + +logger = logging.getLogger(__name__) + +# Create/setup plot figure +# colors = ['#E60D30', '#5CB7C6', '#A21797', '#A3B347'] # Plot colours from http://tools.medialab.sciences-po.fr/iwanthue/index.php +# colorIDs = ["#62a85b", "#9967c7", "#b3943f", "#6095cd", "#cb5c42", "#c95889"] +colorIDs = ["#79c72e", "#5774ff", "#ff7c2c", "#4b4e80", "#d7004e", "#007545", "#ff83ec"] +# colorIDs = ["#ba0044", "#b2d334", "#470055", "#185300", "#ff96b1", "#3e2700", "#0162a9", "#fdb786"] +colors = itertools.cycle(colorIDs) +# for i in range(2): +# next(colors) +lines = itertools.cycle(("--", ":", "-.", "-")) +markers = ["o", "d", "^", "s", "*"] + +fn = Path(__file__) +basename = "pml_3D_pec_plate" +PMLIDs = ["CFS-PML", "HORIPML-1", "HORIPML-2", "MRIPML-1", "MRIPML-2"] +maxerrors = [] +testmodels = [basename + "_" + s for s in PMLIDs] + +fig, ax = plt.subplots( + subplot_kw=dict(xlabel="Iterations", ylabel="Error [dB]"), figsize=(20, 10), facecolor="w", edgecolor="w" +) + +for x, model in enumerate(testmodels): + time, datadiffs = diff_output_files(fn.parent.joinpath(basename + "_ref.h5"), + fn.parent.joinpath(basename + str(x + 1) + ".h5")) + + # Print maximum error value + start = 210 + maxerrors.append(f": {np.amax(datadiffs[start::, 1]):.1f} [dB]") + logger.info(f"{model}: Max. error {maxerrors[x]}") + + # Plot diffs (select column to choose field component, 0-Ex, 1-Ey etc..) + ax.plot(time[start::], datadiffs[start::, 1], color=next(colors), lw=2, ls=next(lines), label=model) + ax.set_xticks(np.arange(0, 2200, step=100)) + ax.set_xlim([0, 2100]) + ax.set_yticks(np.arange(-160, 0, step=20)) + ax.set_ylim([-160, -20]) + ax.set_axisbelow(True) + ax.grid(color=(0.75, 0.75, 0.75), linestyle="dashed") + +mylegend = list(map(add, PMLIDs, maxerrors)) +legend = ax.legend(mylegend, loc=1, fontsize=14) +frame = legend.get_frame() +frame.set_edgecolor("white") +frame.set_alpha(0) + +plt.show() + +# Save a PDF/PNG of the figure +# fig.savefig(basepath + '.pdf', dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1) +# fig.savefig(savename + '.png', dpi=150, format='png', bbox_inches='tight', pad_inches=0.1) diff --git a/testing/models_pmls/pml_basic/plot_pml_comparison.py b/testing/models_pmls/pml_basic/plot_pml_comparison.py new file mode 100644 index 00000000..7429dca2 --- /dev/null +++ b/testing/models_pmls/pml_basic/plot_pml_comparison.py @@ -0,0 +1,75 @@ +# Copyright (C) 2015-2023: The University of Edinburgh, United Kingdom +# Authors: Craig Warren, Antonis Giannopoulos, and John Hartley +# +# This file is part of gprMax. +# +# gprMax is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# gprMax is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with gprMax. If not, see . + +import itertools +import logging +from operator import add +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np + +from testing.diff_output_files import diff_output_files + +logger = logging.getLogger(__name__) + +# Create/setup plot figure +# Plot colours from http://tools.medialab.sciences-po.fr/iwanthue/index.php +colorIDs = ["#79c72e", "#5774ff", "#ff7c2c", "#4b4e80", "#d7004e", "#007545", "#ff83ec"] +colors = itertools.cycle(colorIDs) +lines = itertools.cycle(("--", ":", "-.", "-")) +markers = ["o", "d", "^", "s", "*"] + +fn = Path(__file__) +basename = "pml_basic" +PMLIDs = ["off", "x0", "y0", "z0", "xmax", "ymax", "zmax"] +maxerrors = [] + +for x in range(len(PMLIDs)): + file1 = fn.parent.joinpath(basename + str(x + 1) + "_CPU.h5") + file2 = fn.parent.joinpath(basename + str(x + 1) + "_GPU.h5") + time, datadiffs = diff_output_files(file1, file2) + + # Print maximum error value + start = 0 + maxerrors.append(f": {np.amax(datadiffs[start::, 1]):.1f} [dB]") + logger.info(f"{file1.name} - {file2.name}: Max. error {maxerrors[x]}") + + fig, ax = plt.subplots( + subplot_kw=dict(xlabel="Iterations", ylabel="Error [dB]"), figsize=(20, 10), facecolor="w", edgecolor="w") + + # Plot diffs (select column to choose field component, 0-Ex, 1-Ey etc..) + ax.plot(time[start::], datadiffs[start::, 1], color=next(colors), lw=2, ls=next(lines), label=f"{file1.name} - {file2.name}") + ax.set_xticks(np.arange(0, 2200, step=100)) + ax.set_xlim([0, 2100]) + ax.set_yticks(np.arange(-160, 0, step=20)) + ax.set_ylim([-160, -20]) + ax.set_axisbelow(True) + ax.grid(color=(0.75, 0.75, 0.75), linestyle="dashed") + +mylegend = list(map(add, PMLIDs, maxerrors)) +legend = ax.legend(mylegend, loc=1, fontsize=14) +frame = legend.get_frame() +frame.set_edgecolor("white") +frame.set_alpha(0) + +plt.show() + +# Save a PDF/PNG of the figure +# fig.savefig(basepath + '.pdf', dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1) +# fig.savefig(savename + '.png', dpi=150, format='png', bbox_inches='tight', pad_inches=0.1) diff --git a/testing/models_pmls/pml_basic.py b/testing/models_pmls/pml_basic/pml_basic.py similarity index 100% rename from testing/models_pmls/pml_basic.py rename to testing/models_pmls/pml_basic/pml_basic.py