Shape2Force / utils /substrate_settings.py
kaveh's picture
added
6cbe52d
"""
Substrate settings for force map prediction.
Loads from config/substrate_settings.json - users can edit this file to add/modify substrates.
"""
import os
import json
def _default_config_path():
"""Default path to substrate settings config (S2F/config/substrate_settings.json)."""
this_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(this_dir) # S2F root
return os.path.join(project_root, 'config', 'substrate_settings.json')
def load_substrate_config(config_path=None):
"""
Load substrate settings from config file.
Args:
config_path: Path to JSON config. If None, uses config/substrate_settings.json in S2F root.
Returns:
dict: Config with 'substrates', 'default_substrate'
"""
path = config_path or _default_config_path()
if not os.path.exists(path):
raise FileNotFoundError(
f"Substrate config not found at {path}. "
"Create config/substrate_settings.json or pass config_path."
)
with open(path, 'r') as f:
return json.load(f)
def resolve_substrate(name, config=None, config_path=None):
"""
Resolve substrate name to a canonical substrate key.
Args:
name: Substrate key (e.g. 'fibroblasts_PDMS', 'PDMS_10kPa')
config: Pre-loaded config dict. If None, loads from config_path.
config_path: Path to config file (used if config is None).
Returns:
str: Canonical substrate key
"""
if config is None:
config = load_substrate_config(config_path)
s = (name or '').strip()
if not s:
return config.get('default_substrate', 'fibroblasts_PDMS')
substrates = config.get('substrates', {})
s_lower = s.lower()
for key in substrates:
if key.lower() == s_lower:
return key
for key in substrates:
if s_lower.startswith(key.lower()) or key.lower().startswith(s_lower):
return key
return config.get('default_substrate', 'fibroblasts_PDMS')
def get_settings_of_category(substrate_name, config=None, config_path=None):
"""
Get pixelsize and young's modulus for a substrate.
Args:
substrate_name: Substrate or folder name (case-insensitive)
config: Pre-loaded config dict. If None, loads from config_path.
config_path: Path to config file (used if config is None).
Returns:
dict: {'name': str, 'pixelsize': float, 'young': float}
"""
if config is None:
config = load_substrate_config(config_path)
substrate_key = resolve_substrate(substrate_name, config=config)
substrates = config.get('substrates', {})
default = config.get('default_substrate', 'fibroblasts_PDMS')
if substrate_key in substrates:
return substrates[substrate_key].copy()
default_settings = substrates.get(default, {'name': 'Fibroblasts on PDMS', 'pixelsize': 3.0769, 'young': 6000})
return default_settings.copy()
def list_substrates(config=None, config_path=None):
"""
Return list of available substrate keys for user selection.
Returns:
list: Substrate keys
"""
if config is None:
config = load_substrate_config(config_path)
return list(config.get('substrates', {}).keys())
def compute_settings_normalization(config=None, config_path=None):
"""
Compute min-max normalization parameters from all substrates in config.
Returns:
dict: {'pixelsize': {'min', 'max'}, 'young': {'min', 'max'}}
"""
if config is None:
config = load_substrate_config(config_path)
substrates = config.get('substrates', {})
all_pixelsizes = [s['pixelsize'] for s in substrates.values()]
all_youngs = [s['young'] for s in substrates.values()]
if not all_pixelsizes or not all_youngs:
pixelsize_min, pixelsize_max = 3.0769, 9.8138
young_min, young_max = 1000.0, 10000.0
else:
pixelsize_min, pixelsize_max = min(all_pixelsizes), max(all_pixelsizes)
young_min, young_max = min(all_youngs), max(all_youngs)
return {
'pixelsize': {'min': pixelsize_min, 'max': pixelsize_max},
'young': {'min': young_min, 'max': young_max}
}