6161 "force_partitioning" : {"type" : float , "help" : "Force partitioning" , "default" : 0.5 },
6262 "water_entropy" : {
6363 "type" : bool ,
64- "help" : "Calculate water entropy" ,
65- "default" : False ,
64+ "help" : "If set to False, disables the calculation of water entropy" ,
65+ "default" : True ,
66+ },
67+ "grouping" : {
68+ "type" : str ,
69+ "help" : "How to group molecules for averaging" ,
70+ "default" : "molecules" ,
6671 },
6772}
6873
@@ -85,15 +90,54 @@ def load_config(self, file_path):
8590
8691 return config
8792
93+ def str2bool (self , value ):
94+ """
95+ Convert a string or boolean input into a boolean value.
96+
97+ Accepts common string representations of boolean values such as:
98+ - True values: "true", "t", "yes", "1"
99+ - False values: "false", "f", "no", "0"
100+
101+ If the input is already a boolean, it is returned as-is.
102+ Raises:
103+ argparse.ArgumentTypeError: If the input cannot be interpreted as a boolean.
104+
105+ Args:
106+ value (str or bool): The input value to convert.
107+
108+ Returns:
109+ bool: The corresponding boolean value.
110+ """
111+ if isinstance (value , bool ):
112+ return value
113+ value = value .lower ()
114+ if value in {"true" , "t" , "yes" , "1" }:
115+ return True
116+ elif value in {"false" , "f" , "no" , "0" }:
117+ return False
118+ else :
119+ raise argparse .ArgumentTypeError ("Boolean value expected (True/False)." )
120+
88121 def setup_argparse (self ):
89122 """Setup argument parsing dynamically based on arg_map."""
90123 parser = argparse .ArgumentParser (
91124 description = "CodeEntropy: Entropy calculation with MCC method."
92125 )
93126
94127 for arg , properties in self .arg_map .items ():
95- kwargs = {key : properties [key ] for key in properties if key != "help" }
96- parser .add_argument (f"--{ arg } " , ** kwargs , help = properties .get ("help" ))
128+ help_text = properties .get ("help" , "" )
129+ default = properties .get ("default" , None )
130+
131+ if properties .get ("type" ) == bool :
132+ parser .add_argument (
133+ f"--{ arg } " ,
134+ type = self .str2bool ,
135+ default = default ,
136+ help = f"{ help_text } (default: { default } )" ,
137+ )
138+ else :
139+ kwargs = {k : v for k , v in properties .items () if k != "help" }
140+ parser .add_argument (f"--{ arg } " , ** kwargs , help = help_text )
97141
98142 return parser
99143
@@ -146,3 +190,62 @@ def merge_configs(self, args, run_config):
146190 handler .setLevel (logging .INFO )
147191
148192 return args
193+
194+ def input_parameters_validation (self , u , args ):
195+ """Check the validity of the user inputs against sensible values"""
196+
197+ self ._check_input_start (u , args )
198+ self ._check_input_end (u , args )
199+ self ._check_input_step (args )
200+ self ._check_input_bin_width (args )
201+ self ._check_input_temperature (args )
202+ self ._check_input_force_partitioning (args )
203+
204+ def _check_input_start (self , u , args ):
205+ """Check that the input does not exceed the length of the trajectory."""
206+ if args .start > len (u .trajectory ):
207+ raise ValueError (
208+ f"Invalid 'start' value: { args .start } . It exceeds the trajectory length"
209+ " of {len(u.trajectory)}."
210+ )
211+
212+ def _check_input_end (self , u , args ):
213+ """Check that the end index does not exceed the trajectory length."""
214+ if args .end > len (u .trajectory ):
215+ raise ValueError (
216+ f"Invalid 'end' value: { args .end } . It exceeds the trajectory length of"
217+ " {len(u.trajectory)}."
218+ )
219+
220+ def _check_input_step (self , args ):
221+ """Check that the step value is non-negative."""
222+ if args .step < 0 :
223+ logger .warning (
224+ f"Negative 'step' value provided: { args .step } . This may lead to"
225+ " unexpected behavior."
226+ )
227+
228+ def _check_input_bin_width (self , args ):
229+ """Check that the bin width is within the valid range [0, 360]."""
230+ if args .bin_width < 0 or args .bin_width > 360 :
231+ raise ValueError (
232+ f"Invalid 'bin_width': { args .bin_width } . It must be between 0 and 360"
233+ " degrees."
234+ )
235+
236+ def _check_input_temperature (self , args ):
237+ """Check that the temperature is non-negative."""
238+ if args .temperature < 0 :
239+ raise ValueError (
240+ f"Invalid 'temperature': { args .temperature } . Temperature cannot be"
241+ " below 0."
242+ )
243+
244+ def _check_input_force_partitioning (self , args ):
245+ """Warn if force partitioning is not set to the default value."""
246+ default_value = arg_map ["force_partitioning" ]["default" ]
247+ if args .force_partitioning != default_value :
248+ logger .warning (
249+ f"'force_partitioning' is set to { args .force_partitioning } ,"
250+ " which differs from the default ({default_value})."
251+ )
0 commit comments