pytabs.case_static_nonlinear
1# pyTABS - ETABS .NET API python wrapper 2# CaseStaticNonlinear - cCaseStaticNonlinear 3__all__ = ['CaseStaticNonlinear'] 4 5# import ETABS namespace and pyTABS error handler 6from pytabs.etabs_config import * 7from pytabs.error_handle import * 8 9# import custom enumerations 10from pytabs.enumerations import (eGeometryNonlinearityType, 11 eLoadApplicationControlType, 12 eDisplacementControlType, 13 eDisplacementMonitorType, 14 eMonitoredDisplacementDoF, 15 eNonlinearStaticCaseLoadType) 16 17 18class CaseStaticNonlinear: 19 """CaseStaticNonlinearStaged interface""" 20 def __init__(self, sap_model : etabs.cSapModel) -> None: 21 # link of SapModel interface 22 self.sap_model = sap_model 23 # create interface for static nonlinear load cases 24 self.static_nonlinear = etabs.cCaseStaticNonlinear(sap_model.LoadCases.StaticNonlinear) 25 26 # relate custom enumerations 27 self.eGeometryNonlinearityTypes = eGeometryNonlinearityType 28 self.eLoadApplicationControlType = eLoadApplicationControlType 29 self.eDisplacementControlType = eDisplacementControlType 30 self.eMonitoredDisplacementType = eDisplacementMonitorType 31 self.eMonitoredDisplacementDoF = eMonitoredDisplacementDoF 32 self.eNonlinearStaticCaseLoadType = eNonlinearStaticCaseLoadType 33 34 35 # TODO Get Methods 36 37 38 def set_case(self, name : str) -> None: 39 """Initializes a static nonlinear load case. 40 41 :param name: name of an existing or new load case. If this is an existing case, that case is modified; otherwise, a new case is added 42 :type name: str 43 """ 44 handle(self.static_nonlinear.SetCase(name)) 45 46 47 def set_geometric_nonlinearity(self, name : str, geometry_nonlinearity_type : eGeometryNonlinearityType) -> None: 48 """Sets the geometric nonlinearity option for the specified load case. 49 50 :param name: name of an existing static nonlinear load case 51 :type name: str 52 :param geometry_nonlinearity_type: one of load case 53 :type geometry_nonlinearity_type: eGeometryNonlinearityTypes 54 """ 55 handle(self.static_nonlinear.SetGeometricNonlinearity(name, int(geometry_nonlinearity_type))) 56 57 58 # TODO SetHingeUnloading - need to understand types 59 60 61 def set_initial_case(self, name : str, initial_case_name : str) -> None: 62 """Sets the nonlinear static load case to be considered to contain the initial conditions. 63 64 :param name: name of existing nonlinear static load case 65 :type name: str 66 :param initial_case_name: name of nonlinear static load case to be considered as the initial conditions 67 :type initial_case_name: str 68 """ 69 handle(self.static_nonlinear.SetInitialCase(name, initial_case_name)) 70 71 72 def set_load_application(self, name : str, 73 load_application_control : eLoadApplicationControlType, 74 displacement_control : eDisplacementControlType, 75 displacement : float, 76 displacement_monitor : eDisplacementMonitorType, 77 monitored_dof : eMonitoredDisplacementDoF, 78 point_name : str, 79 generalized_displacement : str) -> None: 80 """Set load case load application control parameters. 81 82 :param name: name of existing nonlinear static load case 83 :type name: str 84 :param load_application_control: load application control method 85 :type load_application_control: eLoadApplicationControlType 86 :param displacement_control: displacement control method 87 :type displacement_control: eDisplacementControlType 88 :param displacement: monitored displacement magnitude 89 :type displacement: float 90 :param displacement_monitor: displacement monitor method 91 :type displacement_monitor: eDisplacementMonitorType 92 :param monitored_dof: monitored degree of freedom 93 :type monitored_dof: eMonitoredDisplacementDoF 94 :param point_name: name of existing point to be monitored 95 :type point_name: str 96 :param generalized_displacement: generalized displacement input (refer ETABS manual) 97 :type generalized_displacement: str 98 """ 99 handle(self.static_nonlinear.SetLoadApplication(name, load_application_control, displacement_control, 100 displacement, displacement_monitor, monitored_dof, 101 point_name, generalized_displacement)) 102 103 104 def set_loads(self, name : str, number_loads : int, load_types : list[eNonlinearStaticCaseLoadType], 105 load_names : list[str], scale_factors : list[float]) -> None: 106 """Sets the load data for the specified analysis case. 107 108 :param name: name of an existing static nonlinear load case 109 :type name: str 110 :param number_loads: number of loads assigned to the specified analysis case 111 :type number_loads: int 112 :param load_types: load type; one of `eNonlinearStaticCaseLoadType` 113 :type load_types: list[eNonlinearStaticCaseLoadType] 114 :param load_names: for a load this is the name of a defined load pattern, for an acceleration this is UX, UY, UZ, RX, RY or RZ and for a mode this is the mode number. 115 :type load_names: list[str] 116 :param scale_factors: scaling factor for load or mode, or magnitude of an acceleration 117 :type scale_factors: list[float] 118 """ 119 self.__verify_loading_details(number_loads, load_types, load_names, scale_factors) 120 load_types = [load_type.value for load_type in load_types] 121 [ret, ret_load_types, ret_load_names, ret_scale_factors] = self.static_nonlinear.SetLoads(name, number_loads, load_types, load_names, scale_factors) 122 handle(ret) 123 124 125 def set_mass_source(self, name : str, mass_source : str) -> None: 126 """Sets the mass source for the specified analysis case. 127 128 :param name: name of an existing static nonlinear load case 129 :type name: str 130 :param mass_source: name of an existing mass source 131 :type mass_source: str 132 """ 133 handle(self.static_nonlinear.SetMassSource(name, mass_source)) 134 135 136 def set_modal_case(self, name : str, modal_case : str) -> None: 137 """Sets the mass source for the specified analysis case. 138 139 :param name: name of an existing static nonlinear load case 140 :type name: str 141 :param modal_case: name of an existing modal load case 142 :type modal_case: str 143 """ 144 handle(self.static_nonlinear.SetModalCase(name, modal_case)) 145 146 147 def set_results_saved(self, name : str, save_multiple_steps : bool, min_saved_steps : int = 10, 148 max_saved_steps : int = 100, save_positive_displacements_only : bool = True) -> None: 149 """Set results saved settings for specified load case. 150 151 :param name: name of an existing static nonlinear load case 152 :type name: str 153 :param save_multiple_steps: if `True`, save multiple steps, if `False` save final step only 154 :type save_multiple_steps: bool 155 :param min_saved_steps: minimum number of steps saved per stage, defaults to 10 156 :type min_saved_steps: int, optional 157 :param max_saved_steps: maximum number of steps saved per stage, defaults to 100 158 :type max_saved_steps: int, optional 159 :param save_positive_displacements_only: if `True` save positive displacement increments only, defaults to True 160 :type save_positive_displacements_only: bool, optional 161 """ 162 handle(self.static_nonlinear.SetResultsSaved(name, save_multiple_steps, min_saved_steps, 163 max_saved_steps, save_positive_displacements_only)) 164 165 166 # TODO SetSolControlParameters 167 # TODO SetTargetForceParameters 168 169 def __verify_loading_details(self, number_loads : int, load_types : list[eNonlinearStaticCaseLoadType], 170 load_names : list[str], scale_factors : list[float]): 171 """Private method for verifying loading details used by method `.set_loads` 172 """ 173 if any(len(input_list) != number_loads for input_list in [load_types, load_names, scale_factors]): 174 raise ValueError('length of all input lists must must be equal to input number_loads') 175 for _l, load_type in enumerate(load_types): 176 load_name = load_names[_l] 177 if load_type is eNonlinearStaticCaseLoadType.ACCELERATION and (load_name not in ['UX', 'UY', 'UZ', 'RX', 'RY', 'RZ']): 178 raise ValueError('where load type is acceleration, the load name must be UX, UY, UZ, RX, RY or RZ, indicating the direction') 179 elif load_type is eNonlinearStaticCaseLoadType.MODE: 180 try: 181 int(load_name) 182 except ValueError: 183 raise ValueError('where load type is mode, the load name must be a node number')
class
CaseStaticNonlinear:
19class CaseStaticNonlinear: 20 """CaseStaticNonlinearStaged interface""" 21 def __init__(self, sap_model : etabs.cSapModel) -> None: 22 # link of SapModel interface 23 self.sap_model = sap_model 24 # create interface for static nonlinear load cases 25 self.static_nonlinear = etabs.cCaseStaticNonlinear(sap_model.LoadCases.StaticNonlinear) 26 27 # relate custom enumerations 28 self.eGeometryNonlinearityTypes = eGeometryNonlinearityType 29 self.eLoadApplicationControlType = eLoadApplicationControlType 30 self.eDisplacementControlType = eDisplacementControlType 31 self.eMonitoredDisplacementType = eDisplacementMonitorType 32 self.eMonitoredDisplacementDoF = eMonitoredDisplacementDoF 33 self.eNonlinearStaticCaseLoadType = eNonlinearStaticCaseLoadType 34 35 36 # TODO Get Methods 37 38 39 def set_case(self, name : str) -> None: 40 """Initializes a static nonlinear load case. 41 42 :param name: name of an existing or new load case. If this is an existing case, that case is modified; otherwise, a new case is added 43 :type name: str 44 """ 45 handle(self.static_nonlinear.SetCase(name)) 46 47 48 def set_geometric_nonlinearity(self, name : str, geometry_nonlinearity_type : eGeometryNonlinearityType) -> None: 49 """Sets the geometric nonlinearity option for the specified load case. 50 51 :param name: name of an existing static nonlinear load case 52 :type name: str 53 :param geometry_nonlinearity_type: one of load case 54 :type geometry_nonlinearity_type: eGeometryNonlinearityTypes 55 """ 56 handle(self.static_nonlinear.SetGeometricNonlinearity(name, int(geometry_nonlinearity_type))) 57 58 59 # TODO SetHingeUnloading - need to understand types 60 61 62 def set_initial_case(self, name : str, initial_case_name : str) -> None: 63 """Sets the nonlinear static load case to be considered to contain the initial conditions. 64 65 :param name: name of existing nonlinear static load case 66 :type name: str 67 :param initial_case_name: name of nonlinear static load case to be considered as the initial conditions 68 :type initial_case_name: str 69 """ 70 handle(self.static_nonlinear.SetInitialCase(name, initial_case_name)) 71 72 73 def set_load_application(self, name : str, 74 load_application_control : eLoadApplicationControlType, 75 displacement_control : eDisplacementControlType, 76 displacement : float, 77 displacement_monitor : eDisplacementMonitorType, 78 monitored_dof : eMonitoredDisplacementDoF, 79 point_name : str, 80 generalized_displacement : str) -> None: 81 """Set load case load application control parameters. 82 83 :param name: name of existing nonlinear static load case 84 :type name: str 85 :param load_application_control: load application control method 86 :type load_application_control: eLoadApplicationControlType 87 :param displacement_control: displacement control method 88 :type displacement_control: eDisplacementControlType 89 :param displacement: monitored displacement magnitude 90 :type displacement: float 91 :param displacement_monitor: displacement monitor method 92 :type displacement_monitor: eDisplacementMonitorType 93 :param monitored_dof: monitored degree of freedom 94 :type monitored_dof: eMonitoredDisplacementDoF 95 :param point_name: name of existing point to be monitored 96 :type point_name: str 97 :param generalized_displacement: generalized displacement input (refer ETABS manual) 98 :type generalized_displacement: str 99 """ 100 handle(self.static_nonlinear.SetLoadApplication(name, load_application_control, displacement_control, 101 displacement, displacement_monitor, monitored_dof, 102 point_name, generalized_displacement)) 103 104 105 def set_loads(self, name : str, number_loads : int, load_types : list[eNonlinearStaticCaseLoadType], 106 load_names : list[str], scale_factors : list[float]) -> None: 107 """Sets the load data for the specified analysis case. 108 109 :param name: name of an existing static nonlinear load case 110 :type name: str 111 :param number_loads: number of loads assigned to the specified analysis case 112 :type number_loads: int 113 :param load_types: load type; one of `eNonlinearStaticCaseLoadType` 114 :type load_types: list[eNonlinearStaticCaseLoadType] 115 :param load_names: for a load this is the name of a defined load pattern, for an acceleration this is UX, UY, UZ, RX, RY or RZ and for a mode this is the mode number. 116 :type load_names: list[str] 117 :param scale_factors: scaling factor for load or mode, or magnitude of an acceleration 118 :type scale_factors: list[float] 119 """ 120 self.__verify_loading_details(number_loads, load_types, load_names, scale_factors) 121 load_types = [load_type.value for load_type in load_types] 122 [ret, ret_load_types, ret_load_names, ret_scale_factors] = self.static_nonlinear.SetLoads(name, number_loads, load_types, load_names, scale_factors) 123 handle(ret) 124 125 126 def set_mass_source(self, name : str, mass_source : str) -> None: 127 """Sets the mass source for the specified analysis case. 128 129 :param name: name of an existing static nonlinear load case 130 :type name: str 131 :param mass_source: name of an existing mass source 132 :type mass_source: str 133 """ 134 handle(self.static_nonlinear.SetMassSource(name, mass_source)) 135 136 137 def set_modal_case(self, name : str, modal_case : str) -> None: 138 """Sets the mass source for the specified analysis case. 139 140 :param name: name of an existing static nonlinear load case 141 :type name: str 142 :param modal_case: name of an existing modal load case 143 :type modal_case: str 144 """ 145 handle(self.static_nonlinear.SetModalCase(name, modal_case)) 146 147 148 def set_results_saved(self, name : str, save_multiple_steps : bool, min_saved_steps : int = 10, 149 max_saved_steps : int = 100, save_positive_displacements_only : bool = True) -> None: 150 """Set results saved settings for specified load case. 151 152 :param name: name of an existing static nonlinear load case 153 :type name: str 154 :param save_multiple_steps: if `True`, save multiple steps, if `False` save final step only 155 :type save_multiple_steps: bool 156 :param min_saved_steps: minimum number of steps saved per stage, defaults to 10 157 :type min_saved_steps: int, optional 158 :param max_saved_steps: maximum number of steps saved per stage, defaults to 100 159 :type max_saved_steps: int, optional 160 :param save_positive_displacements_only: if `True` save positive displacement increments only, defaults to True 161 :type save_positive_displacements_only: bool, optional 162 """ 163 handle(self.static_nonlinear.SetResultsSaved(name, save_multiple_steps, min_saved_steps, 164 max_saved_steps, save_positive_displacements_only)) 165 166 167 # TODO SetSolControlParameters 168 # TODO SetTargetForceParameters 169 170 def __verify_loading_details(self, number_loads : int, load_types : list[eNonlinearStaticCaseLoadType], 171 load_names : list[str], scale_factors : list[float]): 172 """Private method for verifying loading details used by method `.set_loads` 173 """ 174 if any(len(input_list) != number_loads for input_list in [load_types, load_names, scale_factors]): 175 raise ValueError('length of all input lists must must be equal to input number_loads') 176 for _l, load_type in enumerate(load_types): 177 load_name = load_names[_l] 178 if load_type is eNonlinearStaticCaseLoadType.ACCELERATION and (load_name not in ['UX', 'UY', 'UZ', 'RX', 'RY', 'RZ']): 179 raise ValueError('where load type is acceleration, the load name must be UX, UY, UZ, RX, RY or RZ, indicating the direction') 180 elif load_type is eNonlinearStaticCaseLoadType.MODE: 181 try: 182 int(load_name) 183 except ValueError: 184 raise ValueError('where load type is mode, the load name must be a node number')
CaseStaticNonlinearStaged interface
CaseStaticNonlinear(sap_model: ETABSv1.cSapModel)
21 def __init__(self, sap_model : etabs.cSapModel) -> None: 22 # link of SapModel interface 23 self.sap_model = sap_model 24 # create interface for static nonlinear load cases 25 self.static_nonlinear = etabs.cCaseStaticNonlinear(sap_model.LoadCases.StaticNonlinear) 26 27 # relate custom enumerations 28 self.eGeometryNonlinearityTypes = eGeometryNonlinearityType 29 self.eLoadApplicationControlType = eLoadApplicationControlType 30 self.eDisplacementControlType = eDisplacementControlType 31 self.eMonitoredDisplacementType = eDisplacementMonitorType 32 self.eMonitoredDisplacementDoF = eMonitoredDisplacementDoF 33 self.eNonlinearStaticCaseLoadType = eNonlinearStaticCaseLoadType
def
set_case(self, name: str) -> None:
39 def set_case(self, name : str) -> None: 40 """Initializes a static nonlinear load case. 41 42 :param name: name of an existing or new load case. If this is an existing case, that case is modified; otherwise, a new case is added 43 :type name: str 44 """ 45 handle(self.static_nonlinear.SetCase(name))
Initializes a static nonlinear load case.
Parameters
- name: name of an existing or new load case. If this is an existing case, that case is modified; otherwise, a new case is added
def
set_geometric_nonlinearity( self, name: str, geometry_nonlinearity_type: pytabs.enumerations.eGeometryNonlinearityType) -> None:
48 def set_geometric_nonlinearity(self, name : str, geometry_nonlinearity_type : eGeometryNonlinearityType) -> None: 49 """Sets the geometric nonlinearity option for the specified load case. 50 51 :param name: name of an existing static nonlinear load case 52 :type name: str 53 :param geometry_nonlinearity_type: one of load case 54 :type geometry_nonlinearity_type: eGeometryNonlinearityTypes 55 """ 56 handle(self.static_nonlinear.SetGeometricNonlinearity(name, int(geometry_nonlinearity_type)))
Sets the geometric nonlinearity option for the specified load case.
Parameters
- name: name of an existing static nonlinear load case
- geometry_nonlinearity_type: one of load case
def
set_initial_case(self, name: str, initial_case_name: str) -> None:
62 def set_initial_case(self, name : str, initial_case_name : str) -> None: 63 """Sets the nonlinear static load case to be considered to contain the initial conditions. 64 65 :param name: name of existing nonlinear static load case 66 :type name: str 67 :param initial_case_name: name of nonlinear static load case to be considered as the initial conditions 68 :type initial_case_name: str 69 """ 70 handle(self.static_nonlinear.SetInitialCase(name, initial_case_name))
Sets the nonlinear static load case to be considered to contain the initial conditions.
Parameters
- name: name of existing nonlinear static load case
- initial_case_name: name of nonlinear static load case to be considered as the initial conditions
def
set_load_application( self, name: str, load_application_control: pytabs.enumerations.eLoadApplicationControlType, displacement_control: pytabs.enumerations.eDisplacementControlType, displacement: float, displacement_monitor: pytabs.enumerations.eDisplacementMonitorType, monitored_dof: pytabs.enumerations.eMonitoredDisplacementDoF, point_name: str, generalized_displacement: str) -> None:
73 def set_load_application(self, name : str, 74 load_application_control : eLoadApplicationControlType, 75 displacement_control : eDisplacementControlType, 76 displacement : float, 77 displacement_monitor : eDisplacementMonitorType, 78 monitored_dof : eMonitoredDisplacementDoF, 79 point_name : str, 80 generalized_displacement : str) -> None: 81 """Set load case load application control parameters. 82 83 :param name: name of existing nonlinear static load case 84 :type name: str 85 :param load_application_control: load application control method 86 :type load_application_control: eLoadApplicationControlType 87 :param displacement_control: displacement control method 88 :type displacement_control: eDisplacementControlType 89 :param displacement: monitored displacement magnitude 90 :type displacement: float 91 :param displacement_monitor: displacement monitor method 92 :type displacement_monitor: eDisplacementMonitorType 93 :param monitored_dof: monitored degree of freedom 94 :type monitored_dof: eMonitoredDisplacementDoF 95 :param point_name: name of existing point to be monitored 96 :type point_name: str 97 :param generalized_displacement: generalized displacement input (refer ETABS manual) 98 :type generalized_displacement: str 99 """ 100 handle(self.static_nonlinear.SetLoadApplication(name, load_application_control, displacement_control, 101 displacement, displacement_monitor, monitored_dof, 102 point_name, generalized_displacement))
Set load case load application control parameters.
Parameters
- name: name of existing nonlinear static load case
- load_application_control: load application control method
- displacement_control: displacement control method
- displacement: monitored displacement magnitude
- displacement_monitor: displacement monitor method
- monitored_dof: monitored degree of freedom
- point_name: name of existing point to be monitored
- generalized_displacement: generalized displacement input (refer ETABS manual)
def
set_loads( self, name: str, number_loads: int, load_types: list[pytabs.enumerations.eNonlinearStaticCaseLoadType], load_names: list[str], scale_factors: list[float]) -> None:
105 def set_loads(self, name : str, number_loads : int, load_types : list[eNonlinearStaticCaseLoadType], 106 load_names : list[str], scale_factors : list[float]) -> None: 107 """Sets the load data for the specified analysis case. 108 109 :param name: name of an existing static nonlinear load case 110 :type name: str 111 :param number_loads: number of loads assigned to the specified analysis case 112 :type number_loads: int 113 :param load_types: load type; one of `eNonlinearStaticCaseLoadType` 114 :type load_types: list[eNonlinearStaticCaseLoadType] 115 :param load_names: for a load this is the name of a defined load pattern, for an acceleration this is UX, UY, UZ, RX, RY or RZ and for a mode this is the mode number. 116 :type load_names: list[str] 117 :param scale_factors: scaling factor for load or mode, or magnitude of an acceleration 118 :type scale_factors: list[float] 119 """ 120 self.__verify_loading_details(number_loads, load_types, load_names, scale_factors) 121 load_types = [load_type.value for load_type in load_types] 122 [ret, ret_load_types, ret_load_names, ret_scale_factors] = self.static_nonlinear.SetLoads(name, number_loads, load_types, load_names, scale_factors) 123 handle(ret)
Sets the load data for the specified analysis case.
Parameters
- name: name of an existing static nonlinear load case
- number_loads: number of loads assigned to the specified analysis case
- load_types: load type; one of
eNonlinearStaticCaseLoadType
- load_names: for a load this is the name of a defined load pattern, for an acceleration this is UX, UY, UZ, RX, RY or RZ and for a mode this is the mode number.
- scale_factors: scaling factor for load or mode, or magnitude of an acceleration
def
set_mass_source(self, name: str, mass_source: str) -> None:
126 def set_mass_source(self, name : str, mass_source : str) -> None: 127 """Sets the mass source for the specified analysis case. 128 129 :param name: name of an existing static nonlinear load case 130 :type name: str 131 :param mass_source: name of an existing mass source 132 :type mass_source: str 133 """ 134 handle(self.static_nonlinear.SetMassSource(name, mass_source))
Sets the mass source for the specified analysis case.
Parameters
- name: name of an existing static nonlinear load case
- mass_source: name of an existing mass source
def
set_modal_case(self, name: str, modal_case: str) -> None:
137 def set_modal_case(self, name : str, modal_case : str) -> None: 138 """Sets the mass source for the specified analysis case. 139 140 :param name: name of an existing static nonlinear load case 141 :type name: str 142 :param modal_case: name of an existing modal load case 143 :type modal_case: str 144 """ 145 handle(self.static_nonlinear.SetModalCase(name, modal_case))
Sets the mass source for the specified analysis case.
Parameters
- name: name of an existing static nonlinear load case
- modal_case: name of an existing modal load case
def
set_results_saved( self, name: str, save_multiple_steps: bool, min_saved_steps: int = 10, max_saved_steps: int = 100, save_positive_displacements_only: bool = True) -> None:
148 def set_results_saved(self, name : str, save_multiple_steps : bool, min_saved_steps : int = 10, 149 max_saved_steps : int = 100, save_positive_displacements_only : bool = True) -> None: 150 """Set results saved settings for specified load case. 151 152 :param name: name of an existing static nonlinear load case 153 :type name: str 154 :param save_multiple_steps: if `True`, save multiple steps, if `False` save final step only 155 :type save_multiple_steps: bool 156 :param min_saved_steps: minimum number of steps saved per stage, defaults to 10 157 :type min_saved_steps: int, optional 158 :param max_saved_steps: maximum number of steps saved per stage, defaults to 100 159 :type max_saved_steps: int, optional 160 :param save_positive_displacements_only: if `True` save positive displacement increments only, defaults to True 161 :type save_positive_displacements_only: bool, optional 162 """ 163 handle(self.static_nonlinear.SetResultsSaved(name, save_multiple_steps, min_saved_steps, 164 max_saved_steps, save_positive_displacements_only))
Set results saved settings for specified load case.
Parameters
- name: name of an existing static nonlinear load case
- save_multiple_steps: if
True
, save multiple steps, ifFalse
save final step only - min_saved_steps: minimum number of steps saved per stage, defaults to 10
- max_saved_steps: maximum number of steps saved per stage, defaults to 100
- save_positive_displacements_only: if
True
save positive displacement increments only, defaults to True