5050 compute_FIM_metrics ,
5151 _SMALL_TOLERANCE_DEFINITENESS ,
5252 snake_traversal_grid_sampling ,
53+ update_model_from_suffix ,
5354)
5455
5556
@@ -1615,7 +1616,8 @@ def compute_FIM_full_factorial(
16151616 def compute_FIM_factorial (
16161617 self ,
16171618 model = None ,
1618- design_values : dict = None ,
1619+ abs_change : list = None ,
1620+ rel_change : list = None ,
16191621 method = "sequential" ,
16201622 change_one_design_at_a_time = True ,
16211623 file_name : str = None ,
@@ -1629,6 +1631,14 @@ def compute_FIM_factorial(
16291631 ----------
16301632 model : DoE model, optional
16311633 The model to perform the full factorial exploration on. Default: None
1634+ # TODO: Update doc string for absolute and relative change
1635+ abs_change : list, optional
1636+ Absolute change in the design variable values. Default: None.
1637+ If provided, will use this value to generate the design values.
1638+ If not provided, will use the `design_values` parameter.
1639+ rel_change : list, optional
1640+ Relative change in the design variable values. Default: None.
1641+ If provided, will use this value to generate the design values.
16321642 design_values : dict,
16331643 dict of lists or other array-like objects, of the form {"var_name": <var_values>}. Default: None.
16341644 The `design_values` should have the key(s) passed as strings that is a
@@ -1687,35 +1697,47 @@ def compute_FIM_factorial(
16871697 ).clone ()
16881698 model = self .factorial_model
16891699
1690- if not design_values :
1691- raise ValueError (
1692- "design_values must be provided as a dictionary of array-like objects "
1693- "in the form {<'var_name'>: <var_values>}."
1694- )
1695-
1696- # Check whether the design_ranges keys are in the experiment_inputs
1697- design_keys = set (design_values .keys ())
1698- map_keys = set ([k .name for k in model .experiment_inputs .keys ()])
1699- if not design_keys .issubset (map_keys ):
1700- incorrect_given_keys = design_keys - map_keys
1701- suggested_keys = map_keys - design_keys
1702- raise ValueError (
1703- f"design_values keys: { incorrect_given_keys } are incorrect."
1704- f"The keys should be from the following keys: { suggested_keys } ."
1705- )
1706-
17071700 # Get the design map keys that match the design_values keys
1708- design_map_keys = [
1709- k for k in model .experiment_inputs .keys () if k .name in design_values .keys ()
1710- ]
1701+ # design_map_keys = [
1702+ # k for k in model.experiment_inputs.keys() if k.name in design_values.keys()
1703+ # ]
17111704 # This ensures that the order of the design_values keys matches the order of the
17121705 # design_map_keys so that design_point can be constructed correctly in the loop.
17131706 # TODO: define an Enum to add different sensitivity analysis sequences
1714- des_ranges = [design_values [k .name ] for k in design_map_keys ]
1707+ # des_ranges = [design_values[k.name] for k in design_map_keys]
1708+
1709+ design_keys = [k for k in model .experiment_inputs .keys ()]
1710+
1711+ design_values = []
1712+ for i , comp in enumerate (design_keys ):
1713+ lb = comp .lb
1714+ ub = comp .ub
1715+ if lb is None or ub is None :
1716+ raise ValueError (f"{ comp .name } does not have a lower or upper bound." )
1717+
1718+ if abs_change [i ] is None and rel_change [i ] is None :
1719+ n_des = 5 # Default number of points in the design value
1720+ des_val = np .linspace (lb , ub , n_des )
1721+
1722+ elif abs_change [i ] is not None and rel_change [i ] is not None :
1723+ des_val = []
1724+ del_val = comp .lb * rel_change [i ] + abs_change [i ]
1725+ if del_val == 0 :
1726+ raise ValueError (
1727+ f"Design variable { comp .name } has no change in value - check "
1728+ "abs_change and rel_change values."
1729+ )
1730+ val = lb
1731+ while val <= ub :
1732+ des_val .append (val )
1733+ val += del_val
1734+
1735+ design_values .append (des_val )
1736+
17151737 if change_one_design_at_a_time :
1716- factorial_points = snake_traversal_grid_sampling (* des_ranges )
1738+ factorial_points = snake_traversal_grid_sampling (* design_values )
17171739 else :
1718- factorial_points = product (* des_ranges )
1740+ factorial_points = product (* design_values )
17191741
17201742 factorial_points_list = list (factorial_points )
17211743
@@ -1747,7 +1769,7 @@ def compute_FIM_factorial(
17471769 for design_point in factorial_points_list :
17481770 # Fix design variables at fixed experimental design point
17491771 for i in range (len (design_point )):
1750- design_map_keys [i ].fix (design_point [i ])
1772+ design_keys [i ].fix (design_point [i ])
17511773
17521774 # Timing and logging objects
17531775 self .logger .info (f"=======Iteration Number: { curr_point } =======" )
@@ -1817,6 +1839,23 @@ def compute_FIM_factorial(
18171839 "FIM_all" : FIM_all .tolist (), # Save all FIMs
18181840 }
18191841 )
1842+ if self .tee :
1843+ exclude_keys = {
1844+ "total_points" ,
1845+ "success_counts" ,
1846+ "failure_counts" ,
1847+ "FIM_all" ,
1848+ }
1849+ dict_for_df = {
1850+ k : v for k , v in factorial_results .items () if k not in exclude_keys
1851+ }
1852+ res_df = pd .DataFrame (dict_for_df )
1853+ print ("\n \n =========Factorial results DataFrame===========" )
1854+ print (res_df )
1855+ print ("\n \n " )
1856+ print ("Total points:" , total_points )
1857+ print ("Success counts:" , success_count )
1858+ print ("Failure counts:" , failure_count )
18201859
18211860 self .factorial_results = factorial_results
18221861
0 commit comments