Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2box_wilson: Box-Wilson experiment designs, sometimes referred to as Central-Composite Designs
3(CCDs), are useful for measuring quadratic effects.
5Linear effects are typically measured using 2 level factorial or 2 level Plackett-Burman
6experiments. However, if the relationship between treatments and response are quadratic, more than
72 levels may be required to accurately represent the response surface of the experiment.
9CCDs allow experimenters to model quadratic response surfaces without implementing full 3 level
10factorial experiments. CCD designs consist of three "runs": A) a factorial experiment (sometimes
11fractional in design) B) a set of center points, experimental runs whose values of each factor are
12the medians of the values used in the factorial portion C) a set of axial points, experimental runs
13identical to the centre points except for one factor, which will take on values both below and
14above the median of the two factorial levels.
16| A) corner points (defined by the factorial design or matrix_f)
17| B) center points (defined by the matrix_c)
18| C) axial points (defined by the matrix_e)
20Axial points are sometimes referred to as star points.
22If the distance from the center of the design space to a factorial point is 1 unit for each
23factor, the distance from the center of the design space to a star point is |alpha| > 1. The
24precise value of alpha depends on the variables center, alpha_design, and face_design.
26In rare cases (i.e. k=2) a design can be orthogonal and rotatable. However, this is only
27true in a vary limited number of cases. See the example below:
28>>> design_box_wilson(k=2, alpha_design="orthogonal", center=(1,1), face_design="CCC")
29>>> design_box_wilson(k=2, alpha_design="rotatable", center=(1,1), face_design="CCC")
31"""
33import logging
34from typing import Optional, Tuple
36from numpy import zeros, ndarray, r_
37from pandas import DataFrame
39from lind.design.factorial import design_full_factorial
40from lind._utilities import _check_int_input, _check_str_input
42# set logging
43logging.basicConfig(level=logging.INFO)
44logger = logging.getLogger(__name__)
46# define public functions (ignored by jupyter notebooks)
47__all__ = ["design_box_wilson"]
50####################################################################################################
53def _get_alpha(num_factors: int, alpha_design: Optional[str] = None,
54 center: Tuple[int, int] = (1, 1)) -> [ndarray, float]:
55 """
56 Find the distance measure `alpha`
58 Notes
59 -----
60 * number of factorial points = 2.0**num_factors
61 * number of axial points = 2*num_factors
62 * factorial center position = center[0]
63 * axial center position = center[1]
64 * alpha is always 1 for CCF face_design (hence default behavior for alpha_design=None)
65 * CCDs always contain twice as many star points (axial points) as factors. The star points
66 represent new extreme values (low and high) for each factor.
67 """
68 if alpha_design is None:
69 return 1.0
70 if alpha_design == 'orthogonal':
71 # see Response Surface Methodology by Raymond Myers (1971)
72 return (
73 num_factors *
74 (1.0 + center[1] / (2.0*num_factors)) /
75 (1.0 + center[0] / (2.0**num_factors))
76 )**0.5
77 if alpha_design == 'rotatable':
78 # see Section 5.3.3.6.1 of the Engineering Statistics Handbook for formula
79 return (2.0**num_factors)**0.25
80 raise ValueError("Invalid value for alpha_design: {}".format(alpha_design))
83def _get_matrix_f(num_factors):
84 """2 level full factorial experiment design defines the matrix_f"""
85 return design_full_factorial([[-1, 1] for _ in range(num_factors)]).values
88def _get_matrix_c(num_factors):
89 """Generate the center point matrix"""
90 matrix_c = zeros((2*num_factors, num_factors))
91 for i in range(num_factors):
92 matrix_c[2*i:2*i+2, i] = [-1, 1]
93 return matrix_c
96####################################################################################################
99def design_box_wilson(k: int, alpha_design: Optional[str] = "rotatable",
100 center: Optional[Tuple[int, int]] = (1, 1),
101 face_design: Optional[str] = "CCC") -> DataFrame:
102 """
103 boc_wilson: Central Composite Design (CCD)
105 A CCD design contains an embedded factorial design with center points
106 that are augmented with a group of 'star points' that allow estimation of curvature useful for
107 estimating quadratic relationships.
109 CCD designs can use facing options: CCC (Circumscribed), CCI (Inscribed), and
110 CCF (Face Centered).
112 CCC designs are the original form of the central composite design. The star points are at some
113 distance alpha from the center based on the properties desired for the design and the number of
114 factors in the design. The star points establish new extremes for the low and high settings for
115 all factors. These designs have circular, spherical, or hyperspherical symmetry and require 5
116 levels for each factor. Augmenting an existing factorial or resolution V fractional factorial
117 design with star points can produce this design.
119 CCI is useful in situations where the limits specified for factor settings are truly limits, the
120 CCI design uses the factor settings as the star points and creates a factorial design within
121 those limits (in other words, a CCI design is a scaled down CCC design with each factor level of
122 the CCC design divided by alpha to generate the CCI design). This design also requires 5 levels
123 of each factor. CCI designs can use partial factorial designs for matrix_f. This is not
124 supported here.
126 CCF design star points are at the center of each face of the factorial space, so alpha=1. This
127 requires 3 levels of each factor. Augmenting an existing factorial or resolution V design with
128 appropriate star points can also produce this design.
130 Parameters
131 ----------
132 k: int
133 the total number of factors considered in the design
134 alpha_design: str, optional
135 The method of calculating the distance alpha. Available options: `orthogonal`, `rotatable`;
136 Just like MATLAB ccdesign, `rotatable` is the default
137 center: Tuple[int, int], optional
138 the first value of the tuple is the factorial center point, the second value of the tuple
139 is the axial center point; default value is (1, 1)
140 face_design: str, optional
141 this input determines the symmetry / geometric of the design; valid options are: `CCC`,
142 `CCF`, and `CCI`
144 Returns
145 -------
146 pd.DataFrame
147 the box-wilson experimental design
149 Examples
150 --------
151 >>> design = design_box_wilson(k=2, alpha_design="rotatable", center=(1,1), face_design="CCC")
153 References
154 ----------
155 NIST
156 * Section 5.3.3.6.1 of the Engineering Statistics Handbook
157 Myers
158 * Response Surface Methodology (1971)
159 Box and Wilson
160 * On the Experimental Attainment of Optimum Conditions (1951)
162 Notes
163 -----
164 * When face_design=`CCF` the alpha_design argument is ignored and alpha is set to 1.
165 * Popular CCD designs are orthogonal (OCCD), rotatable (RCCD), face (FCC), spherical (SCCD),
166 and Slope Rotatable (Slope-R); of these only the first three are supported
168 """
170 k = _check_int_input(k, "k")
171 alpha_design = _check_str_input(alpha_design, "alpha_design", ["orthogonal", "rotatable"])
172 face_design = _check_str_input(face_design, "face_design", ["CCC", "CCF", "CCI"])
174 if k < 2:
175 raise ValueError("Input k must be >= 2 to produce a valid design.")
177 center = center if alpha_design == "orthogonal" else (1, 1)
178 alpha = _get_alpha(k, alpha_design=alpha_design, center=center) if \
179 face_design != "ccf" else 1.0
181 matrix_f = _get_matrix_f(k)
182 matrix_c = _get_matrix_c(k)
184 # Circumscribed Face (CCC)
185 if face_design == "ccc":
186 matrix_c = matrix_c * alpha
188 # Inscribed Face (CCI)
189 elif face_design == "cci":
190 # normalize matrix_f by distance alpha
191 matrix_f = matrix_f / alpha
193 # Faced Centered Face (CCF): alpha is always 1
195 center_1 = zeros((center[0], k))
196 center_2 = zeros((center[1], k))
198 return DataFrame(data=r_[
199 r_[matrix_f, center_1],
200 r_[matrix_c, center_2]
201 ], columns=["x{}".format(i) for i in range(k)])