Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions biosim_extractor/helpers/metadata_utils.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
#!/usr/bin/env python3


def round_floats(obj, decimals=3):
def round_floats(obj, decimals=3, preserve_below=1e-3):
"""
Recursively round all floats in a nested structure (dict, list, tuple) to the given decimals.
Recursively round floats in nested dicts, lists, and tuples.

Very small non-zero floats are rounded in scientific notation so they are
not rounded to zero. They remain numbers.

Args:
obj: The object to process (dict, list, tuple, float, etc.).
decimals: Number of decimal places to round to.
obj: Object to process.
decimals: Decimal places to keep.
preserve_below: Lower absolute-value threshold for preserving floats.

Returns:
The processed object with all floats rounded.
Object with floats rounded while preserving numeric types.
"""
if isinstance(obj, float):
if obj != 0 and abs(obj) < preserve_below:
return float(f"{obj:.{decimals}e}")
return round(obj, decimals)

elif isinstance(obj, list):
return [round_floats(item, decimals) for item in obj]
return [round_floats(item, decimals, preserve_below) for item in obj]

elif isinstance(obj, tuple):
return tuple(round_floats(item, decimals) for item in obj)
return tuple(round_floats(item, decimals, preserve_below) for item in obj)

elif isinstance(obj, dict):
return {k: round_floats(v, decimals) for k, v in obj.items()}
else:
return obj
return {k: round_floats(v, decimals, preserve_below) for k, v in obj.items()}

return obj
17 changes: 12 additions & 5 deletions biosim_extractor/units/unitconversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def __init__(self, standard_units: Optional[Dict[str, str]] = None) -> None:
self.standards: Dict[str, str] = standard_units or {
"length": "nm", # nanometers
"volume": "nm³", # nanometers cubed
"time": "ps", # picoseconds
"time": "s", # seconds
"energy": "kJ/mol", # kilojoules per mole
"temperature": "K", # Kelvin
"pressure": "bar", # bar
Expand All @@ -37,6 +37,7 @@ def __init__(self, standard_units: Optional[Dict[str, str]] = None) -> None:
"angle": "degree", # degree
"charge": "e", # atomic charge units
"molecular_weight": "g/mol", # grams per mol
"information_storage": "GB", # gigabytes
}

# Conversion factors to standard units
Expand All @@ -59,10 +60,12 @@ def __init__(self, standard_units: Optional[Dict[str, str]] = None) -> None:
"ų": 1000,
},
"time": {
"fs": 0.001,
"ps": 1.0,
"ns": 1000.0,
"s": 1e12,
"fs": 1e-15,
"ps": 1e-12,
"ns": 1e-9,
"μs": 1e-6,
"ms": 0.001,
"s": 1.0,
},
"energy": {
"kcal/mol": 4.184,
Expand Down Expand Up @@ -120,6 +123,10 @@ def __init__(self, standard_units: Optional[Dict[str, str]] = None) -> None:
"amu": 1.0,
"Da": 1.0,
},
"information_storage": {
"GB": 1.0,
"MB": 0.001,
},
}

# Create reverse lookup: unit -> unit_type
Expand Down
Loading