band-unfolding / banduppy

Python version ofthe BandUP code
GNU General Public License v3.0
17 stars 7 forks source link

Python wrong flotting point precission #24

Closed bmondal94 closed 3 months ago

bmondal94 commented 5 months ago

Dear @stepan-tsirkin ,

I have recently started using banduppy. I am reaching out regarding a critical Python issue I have noticed while using Banduppy. I see that the Unfolding class utilizes the % operator. However, as you may know, due to tiny inaccuracies in floating-point operations, 1.1%1 does not yield the same result as 0.1%1 in python, potentially leading to incorrect reductions during np.unique operations.

print(0.1%1 == 1.1%1) 
# Output -> False

A propose a possible solution using np.round. Here is a code snippet showing this issue.

import numpy as np

# Perform modulo operation
result = np.array([[0.1,0.0,0.0],[1.1,0,0]]) % 1
# result = np.fmod(np.array([[0.1,0.0,0.0],[1.1,0,0]]), 1) # np.fmod, np.mod -> Same problem
print(f'Another e.g.: {1.4%1:0.16f}', 0.4%1==0.4)
# Use np.unique with a tolerance-based comparison function
unique_result = np.unique(result, axis=0)
# Filter unique values based on tolerance
unique_result_round = np.unique(np.round(result, decimals=12), axis=0)
print("Unique values without tolerance:")
print(unique_result)
print("Unique values with tolerance:")
print(unique_result_round)

This issue is especially crucial, as it impacts the accuracy of supercell band folding calculations. Here is an example:

import banduppy
unfold_path=banduppy.UnfoldingPath(supercell= np.diag([4,4,2]), pathPBZ=[[0,0,0],[1/2,0,0]], nk=21, labels=None) 
print(f"-Info: Contains {unfold_path.nkptPBZ} points in PC ({unfold_path.nkptPBZunique} unique),")
print(f"corresponding to {unfold_path.nkptSBZ} unique SC points")
print(unfold_path.kpointsSBZ)

This produces wrong reduction in supercell band folding.

bmondal94 commented 3 months ago

Problem fixed in the latest version.