#!/usr/bin/env python import h5py as h import numpy as np import matplotlib matplotlib.use("Agg") from pylab import * import os.path kernel_gamma = 1.825742 kernel_gamma2 = kernel_gamma * kernel_gamma kernel_gamma_dim = np.power(kernel_gamma, 3) hydro_dimension_unit_sphere = 4.0 * np.pi / 3.0 kernel_norm = hydro_dimension_unit_sphere * kernel_gamma_dim error = False inputFile1 = "" inputFile2 = "" # Compare the values of two floats def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) # Check list of density neighbours and check that they are correct. def check_density_neighbours( pids, ngb_ids_naive, ngb_ids_sort, mask, pos, h_naive, h_sort, num_invalid, acc ): for k in range(0, num_invalid): # Filter neighbour lists for valid particle ids filter_neigh_naive = [i for i in ngb_ids_naive[mask][k] if i > -1] filter_neigh_sort = [i for i in ngb_ids_sort[mask][k] if i > -1] # Check neighbour lists for differences id_list = set(filter_neigh_naive).symmetric_difference(set(filter_neigh_sort)) # Check for duplicate IDs duplicate_check_naive = len(filter_neigh_naive) != len(set(filter_neigh_naive)) duplicate_check_sort = len(filter_neigh_sort) != len(set(filter_neigh_sort)) if duplicate_check_naive: print("Duplicate neighbour ID found in: ", inputFile1) print(filter_neigh_naive) return True if duplicate_check_sort: print("Duplicate neighbour ID found in: ", inputFile2) print(filter_neigh_sort) return True pid = pids[mask][k] # Loop over discrepancies and check if they are actually neighbours for pjd in id_list: pi_pos = pos[np.where(pids == pid)] pj_pos = pos[np.where(pids == pjd)] hi = h_naive[np.where(pids == pid)] dx = pi_pos[0][0] - pj_pos[0][0] dy = pi_pos[0][1] - pj_pos[0][1] dz = pi_pos[0][2] - pj_pos[0][2] # Correct for BCs dx = nearest(dx) dy = nearest(dy) dz = nearest(dz) r2 = dx * dx + dy * dy + dz * dz hig2 = hi * hi * kernel_gamma2 diff = abs(r2 - hig2) print( "Particle {} is missing {}, hig2: {}, r2: {}, |r2 - hig2|: {}".format( pid, pjd, hig2, r2, diff ) ) if diff < acc * hig2: print("Missing interaction due to precision issue will be ignored.") else: hi_2 = h_sort[np.where(pids == pid)] # If a neigbour is missing and the particle has the same h throw # an error. if isclose(hi, hi_2): print( "Missing interaction found but particle has the same smoothing length (hi_1: %e, hi_2: %e)." % (hi, hi_2) ) return True else: print( "Missing interaction due to different smoothing lengths will be ignored (hi_1: %e, hi_2: %e)." % (hi, hi_2) ) return False # Check list of force neighbours and check that they are correct. def check_force_neighbours( pids, ngb_ids_naive, ngb_ids_sort, mask, pos, h_naive, h_sort, num_invalid, acc ): error_val = False for k in range(0, num_invalid): # Filter neighbour lists for valid particle ids filter_neigh_naive = [i for i in ngb_ids_naive[mask][k] if i > -1] filter_neigh_sort = [i for i in ngb_ids_sort[mask][k] if i > -1] # Check neighbour lists for differences id_list = set(filter_neigh_naive).symmetric_difference(set(filter_neigh_sort)) pid = pids[mask][k] # Loop over discrepancies and check if they are actually neighbours for pjd in id_list: pi_pos = pos[np.where(pids == pid)] pj_pos = pos[np.where(pids == pjd)] hi = h_naive[np.where(pids == pid)] hj = h_naive[np.where(pids == pjd)] dx = pi_pos[0][0] - pj_pos[0][0] dy = pi_pos[0][1] - pj_pos[0][1] dz = pi_pos[0][2] - pj_pos[0][2] # Correct for BCs dx = nearest(dx) dy = nearest(dy) dz = nearest(dz) r2 = dx * dx + dy * dy + dz * dz hig2 = hi * hi * kernel_gamma2 hjg2 = hj * hj * kernel_gamma2 diff = abs(r2 - max(hig2, hjg2)) print( "Particle {} is missing {}, hig2: {}, hjg2: {}, r2: {}, |r2 - max(hig2,hjg2)|: {}".format( pid, pjd, hig2, hjg2, r2, diff ) ) if diff < acc * max(hig2, hjg2): print("Missing interaction due to precision issue will be ignored.") else: hi_2 = h_sort[np.where(pids == pid)] if isclose(hi, hi_2): print( "Missing interaction due to the same smoothing lengths will not be ignored (hi_1: %e, hi_2: %e)." % (hi, hi_2) ) error_val = True else: print( "Missing interaction due to different smoothing lengths will be ignored (hi_1: %e, hi_2: %e)." % (hi, hi_2) ) return error_val def nearest(dx): if dx > 0.5 * box_size: return dx - box_size elif dx < -0.5 * box_size: return dx + box_size else: return dx # Parse command line arguments if len(sys.argv) < 3: print("Error: pass input files as arguments") sys.exit() else: inputFile1 = sys.argv[1] inputFile2 = sys.argv[2] if os.path.exists(inputFile1) != 1: print("\n{} does not exist!\n".format(inputFile1)) sys.exit() if os.path.exists(inputFile2) != 1: print("\n{} does not exist!\n".format(inputFile2)) sys.exit() # Open input files file_naive = h.File(inputFile1, "r") file_sort = h.File(inputFile2, "r") box_size = file_naive["/Header"].attrs["BoxSize"][0] # Read input file fields ids_naive = file_naive["/PartType0/ParticleIDs"][:] ids_sort = file_sort["/PartType0/ParticleIDs"][:] h_naive = file_naive["/PartType0/SmoothingLength"][:] h_sort = file_sort["/PartType0/SmoothingLength"][:] pos_naive = file_naive["/PartType0/Coordinates"][:, :] # pos_sort = file_sort["/PartType0/Coordinates"][:,:] num_density_naive = file_naive["/PartType0/Num_ngb_density"][:] num_density_sort = file_sort["/PartType0/Num_ngb_density"][:] num_force_naive = file_naive["/PartType0/Num_ngb_force"][:] num_force_sort = file_sort["/PartType0/Num_ngb_force"][:] neighbour_ids_density_naive = file_naive["/PartType0/Ids_ngb_density"][:] neighbour_ids_density_sort = file_sort["/PartType0/Ids_ngb_density"][:] neighbour_ids_force_naive = file_naive["/PartType0/Ids_ngb_force"][:] neighbour_ids_force_sort = file_sort["/PartType0/Ids_ngb_force"][:] # wcount_naive = file_naive["/PartType0/Wcount"][:] # wcount_sort = file_sort["/PartType0/Wcount"][:] # # wcount_naive = wcount_naive * np.power(h_naive,3) * kernel_norm # wcount_sort = wcount_sort * np.power(h_sort,3) * kernel_norm # Cross check max_density_ngbs_naive = np.max(num_density_naive) max_density_ngbs_sort = np.max(num_density_sort) max_force_ngbs_naive = np.max(num_force_naive) max_force_ngbs_sort = np.max(num_force_sort) print(" Min Mean Max ") print(" ---------------------") print( "Ngbs density naiv: ", np.min(num_density_naive), np.mean(num_density_naive), max_density_ngbs_naive, ) print( "Ngbs density sort: ", np.min(num_density_sort), np.mean(num_density_sort), max_density_ngbs_sort, ) print( "Ngbs force naiv: ", np.min(num_force_naive), np.mean(num_force_naive), max_force_ngbs_naive, ) print( "Ngbs force sort: ", np.min(num_force_sort), np.mean(num_force_sort), max_force_ngbs_sort, ) # print "Wcount naiv: ", np.min(wcount_naive), np.mean(wcount_naive), np.max(wcount_naive) # print "Wcount sort: ", np.min(wcount_sort), np.mean(wcount_sort), np.max(wcount_sort) # Sort index_naive = np.argsort(ids_naive) index_sort = np.argsort(ids_sort) num_density_naive = num_density_naive[index_naive] num_density_sort = num_density_sort[index_sort] num_force_naive = num_force_naive[index_naive] num_force_sort = num_force_sort[index_sort] ids_naive = ids_naive[index_naive] ids_sort = ids_sort[index_sort] neighbour_ids_density_naive = neighbour_ids_density_naive[index_naive] neighbour_ids_density_sort = neighbour_ids_density_sort[index_sort] neighbour_ids_force_naive = neighbour_ids_force_naive[index_naive] neighbour_ids_force_sort = neighbour_ids_force_sort[index_sort] # wcount_naive = wcount_naive[index_naive] # wcount_sort = wcount_sort[index_sort] h_naive = h_naive[index_naive] h_sort = h_sort[index_sort] pos_naive = pos_naive[index_naive] # pos_sort = pos_sort[index_sort] neighbour_length_naive = len(neighbour_ids_density_naive[0]) neighbour_length_sort = len(neighbour_ids_density_sort[0]) # Check that input files are logging the same number of neighbours if neighbour_length_naive != neighbour_length_sort: print("Input files have logged different numbers of neighbour lengths!") print("{} has logged: {} neighbours".format(inputFile1, neighbour_length_naive)) print("{} has logged: {} neighbours".format(inputFile2, neighbour_length_sort)) exit(1) if ( max_density_ngbs_naive > neighbour_length_naive or max_force_ngbs_naive > neighbour_length_naive or max_density_ngbs_sort > neighbour_length_sort or max_force_ngbs_sort > neighbour_length_sort ): print("The number of neighbours has exceeded the number of neighbours logged.") print("Modify NUM_OF_NEIGHBOURS in hydro_part.h to log more neighbours.") print( "The highest neighbour count is: ", max( max_density_ngbs_naive, max_force_ngbs_naive, max_density_ngbs_sort, max_force_ngbs_sort, ), ) exit(1) # First check print("\n Min Max") print(" ----------") print( "Differences for density: ", min(num_density_naive - num_density_sort), max(num_density_naive - num_density_sort), ) print( "Differences for force: ", min(num_force_naive - num_force_sort), max(num_force_naive - num_force_sort), ) # Get the IDs that are different mask_density = num_density_naive != num_density_sort mask_force = num_force_naive != num_force_sort num_invalid_density = np.sum(mask_density) num_invalid_force = np.sum(mask_force) print("\nNum non-zero density: ", num_invalid_density) print("Num non-zero force: ", num_invalid_force) print("\nParticle IDs with incorrect densities") print("----------------------------------------") print(ids_naive[mask_density]) # Check density neighbour lists error += check_density_neighbours( ids_naive, neighbour_ids_density_naive, neighbour_ids_density_sort, mask_density, pos_naive, h_naive, h_sort, num_invalid_density, 2e-6, ) print("Num of density interactions", inputFile1) print(num_density_naive[mask_density]) print("Num of density interactions", inputFile2) print(num_density_sort[mask_density]) print("\nParticle IDs with incorrect forces") print("------------------------------------") print(ids_naive[mask_force]) # Check force neighbour lists error += check_force_neighbours( ids_naive, neighbour_ids_force_naive, neighbour_ids_force_sort, mask_force, pos_naive, h_naive, h_sort, num_invalid_force, 2e-6, ) print("Num of force interactions", inputFile1) print(num_force_naive[mask_force]) # print "Smoothing lengths", inputFile1 # print h_naive[mask_force] print("Num of force interactions", inputFile2) print(num_force_sort[mask_force]) # print "Smoothing lengths", inputFile2 # print h_sort[mask_force] # Statistics of h difference h_relative = (h_naive - h_sort) / h_naive print( "h statistics: {} {} (Min, 1st Percentile)".format( np.min(h_relative), np.percentile(h_relative, 1) ) ) print( "h statistics: {} {} (Mean, Median)".format( np.mean(h_relative), np.median(h_relative) ) ) print( "h statistics: {} {} (Max, 99th Percentile)".format( np.max(h_relative), np.percentile(h_relative, 99) ) ) if error: print("\n------------------") print("Differences found.") print("------------------") exit(1) else: print("\n---------------------") print("No differences found.") print("---------------------") exit(0)