T_make_sys_ADY¶
test.ASC_SOLVER.T_make_sys_ADY
This File has the sole purpose of creating the ASC DHARD Y Model that is then exported to the buzz repository.
Functions
|
|
|
|
|
|
|
This is a pytest needing documentation |
|
This is a pytest needing documentation |
|
Create a state space model for an adder. |
|
This is a pytest needing documentation |
|
Create a state space model for the delay block. |
|
Create a state space model for the null block. |
|
This is the main function that is called to create the model for the ASC DHARD Y. |
Details
- FBNSSS_DARM(return_name=False, return_scale=False, as_zpk=False, normalize=True)[source]¶
code
docstring
""" """
1def FBNSSS_DARM( 2 return_name=False, 3 return_scale=False, 4 as_zpk=False, 5 normalize=True, 6): 7 8 if return_name: 9 name = "FOM BNS (Hand Fit)" 10 return name 11 12 #BNS_zpk = file_io.load(fjoin('ExampleModels_DARMFOM/BNS_FOM_from_DARM.yml')) 13 BNS_zpk = file_io.load(fjoin('ExampleModels_DARMFOM/BNS_FOM_IR.yml')) 14 F_z = np.array(BNS_zpk["z"], dtype=np.complex128) 15 F_p = np.array(BNS_zpk["p"], dtype=np.complex128) 16 F_k = BNS_zpk["k"] 17 18 F_zpk = SISO.zpk(F_z, F_p, F_k) 19 F = F_zpk.asSS.mimo("FBNS.out", "FBNS.in") 20 if not normalize: 21 return F 22 F, scale = ssutil.normalize_gain(F, norm=1, return_scale=True) 23 if as_zpk: 24 return F_zpk * scale 25 if return_scale: 26 return scale 27 else: 28 return F
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.FBNSSS_DARMThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- FBNSSS_Fit(gain=1, return_name=False, return_scale=False)[source]¶
code
docstring
""" """
1def FBNSSS_Fit(gain=1, return_name=False, return_scale = False): 2 3 if return_name: 4 name = "FOM BNS" 5 return name 6 7 if gain != 1: 8 NotImplementedError("This function does not support gain scaling") 9 10 BNS_zpk = file_io.load(fjoin('ExampleModels_newFOM/BNS_FOM.yml')) 11 print(BNS_zpk['z']) 12 F_z = np.array(BNS_zpk["z"], dtype=np.complex128) 13 #BNS_zpk["p"].append(BNS_zpk["p"][-1]) 14 F_p = np.array(BNS_zpk["p"], dtype=np.complex128) 15 F_k = BNS_zpk["k"] 16 17 #print(len(F_z)) 18 #print(len(F_p)) 19 F_mod = SISO.zpk(F_z, F_p, F_k).asSS 20 F_iod = {"FBNS.in": 0, "FBNS.out": 0} 21 F = ssutil.wieldSS(F_mod.A, F_mod.B, F_mod.C, F_mod.D, iod=F_iod) 22 F, scale = ssutil.normalize_gain(F, norm=1, return_scale=True) 23 if return_scale: 24 return scale 25 else: 26 return F
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.FBNSSS_FitThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- FBNSSS_Hand(return_name=False, return_scale=False, as_zpk=False)[source]¶
code
docstring
""" """
1def FBNSSS_Hand(return_name=False, return_scale = False, as_zpk=False): 2 3 if return_name: 4 name = "FOM BNS (Hand Fit)" 5 return name 6 7 BNS_zpk = file_io.load(fjoin('ExampleModels_newFOM/BNS_FOM_handfit.yml')) 8 F_z = np.array(BNS_zpk["z"], dtype=np.complex128) 9 F_p = np.array(BNS_zpk["p"], dtype=np.complex128) 10 F_k = BNS_zpk["k"] 11 12 F_zpk = SISO.zpk(F_z, F_p, F_k) 13 F = F_zpk.asSS.mimo("FBNS.out", "FBNS.in") 14 F, scale = ssutil.normalize_gain(F, norm=1, return_scale=True) 15 if as_zpk: 16 return F_zpk * scale 17 if return_scale: 18 return scale 19 else: 20 return F
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.FBNSSS_HandThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- FBNSsimpSS(return_name=False, lo_ord=4, return_scale=False, as_zpk=False)[source]¶
This is a pytest needing documentation
code
1def FBNSsimpSS(return_name=False, lo_ord=4, return_scale=False, as_zpk = False): 2 if return_name: 3 name = "FOM BNS Simple" 4 return name 5 6 BNS_zpk = file_io.load(fjoin('FOMs/FBNSsimp_FOM.yml')) 7 print(BNS_zpk['z']) 8 F_z = np.array(BNS_zpk["z"], dtype=np.complex128) 9 F_p = np.array(BNS_zpk["p"], dtype=np.complex128) 10 F_k = BNS_zpk["k"] 11 12 F_zpk = SISO.zpk(F_z, F_p, F_k) 13 F = F_zpk.asSS.mimo("FBNS.out", "FBNS.in") 14 F, scale = ssutil.normalize_gain(F, norm=1, return_scale=True) 15 if as_zpk: 16 return F_zpk * scale 17 if return_scale: 18 return scale 19 else: 20 return F
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.FBNSsimpSSThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- FFlatSS(gain=1, return_name=False)[source]¶
This is a pytest needing documentation
code
1def FFlatSS(gain=1, return_name=False): 2 if return_name: 3 name = "FOM Flat" 4 return name 5 6 return SISO.zpk([], [], gain).asSS.mimo("F2.out", "F2.in")
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.FFlatSSThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- addSS(namespace='T', dt=0.0001, sub=False, outSufx=None)[source]¶
Create a state space model for an adder. It has two inputs and one output.
- Parameters:
- Returns:
Returns the local name space for the function including the state space model as mod, input output dictionary as iod, and namespace.
- Return type:
wield.bunch
code
docstring
"""Create a state space model for an adder. It has two inputs and one output. Args: namespace (string): The namespace to use for the model i.e. the letter that comes at the beginning of the input and output names. Defaults to 'T'. dt (float, optional): The time step. Defaults to 1e-4. sub (bool, optional): If true, the model will be a subtractor. Defaults to False. Returns: wield.bunch: Returns the local name space for the function including the state space model as `mod`, input output dictionary as `iod`, and namespace. """
1def addSS(namespace='T', dt=1e-4, sub=False, outSufx = None): 2 3 A = np.zeros([0,0]) # Construct the A state matrix 4 B = np.zeros([2,0]) # Construct the B state matrix 5 C = np.zeros([0,1]) # Construct the C state matrix 6 if sub: 7 D = np.array([[1, -1]]) # Construct the D state matrix for a subtractor 8 else: 9 D = np.array([[1, 1]]) # Construct the D state matrix 10 if outSufx == None: 11 iod = {namespace+'.in.1': 0, namespace+'.in.2': 1, namespace+'.out': 0} # Input output dictionary 12 else: 13 iod = {namespace+'.in.1': 0, namespace+'.in.2': 1, namespace+'.out.'+outSufx: 0} # Input output dictionary 14 return ssutil.wieldSS(A, B, C, D, iod=iod)
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.addSSThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- delayDrive(namespace='D', Sp=None, delay=0.001, order=1, numins=1, dt=0.0001)[source]¶
This is a pytest needing documentation
code
1def delayDrive(namespace='D', Sp=None, delay=1e-3, order=1, numins=1, dt=1e-4): 2 D = delaySS(namespace=namespace, delay=delay, order=order, numins=numins, dt=dt) 3 4 if Sp is None or Sp == 1: 5 #assert(False) 6 return D 7 8 #rename the input for pending merge 9 D.iod[namespace + '.in.2'] = D.iod[namespace + '.in'] 10 del D.iod[namespace + '.in'] 11 12 #check that it only has 1 input and one output (THIS IS A HACKY WAY TO TEST) 13 assert(len(Sp.iod) == 2) 14 15 print(Sp.iod) 16 Sp.iod.clear() 17 Sp.iod[namespace + '.in'] = 0 18 Sp.iod[namespace + '.out.1'] = 0 19 print(Sp.iod) 20 21 Dx = ssutil.multiconnect([Sp, D], [[namespace+'.in.2', namespace+'.out.1']]) 22 print(Dx.iod) 23 return Dx
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.delayDriveThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- delaySS(namespace='D', delay=0.001, order=1, numins=1, dt=0.0001)[source]¶
Create a state space model for the delay block. It has one input and one output.
- Parameters:
namespace (str, optional) – The namespace for the delay block. Defaults to ‘D’.
delay (_type_, optional) – The delay in seconds. Defaults to 1e-3.
order (int, optional) – Order of the filter. Defaults to 1.
numins (int, optional) – Number of inputs. Defaults to 1.
dt (_type_, optional) – The discretization time step. Defaults to 1e-4.
- Returns:
Returns the local name space for the function including the state space model as mod, input output dictionary as iod, and namespace.
- Return type:
wield.bunch
code
docstring
"""Create a state space model for the delay block. It has one input and one output. Args: namespace (str, optional): The namespace for the delay block. Defaults to 'D'. delay (_type_, optional): The delay in seconds. Defaults to 1e-3. order (int, optional): Order of the filter. Defaults to 1. numins (int, optional): Number of inputs. Defaults to 1. dt (_type_, optional): The discretization time step. Defaults to 1e-4. Returns: wield.bunch: Returns the local name space for the function including the state space model as `mod`, input output dictionary as `iod`, and namespace. """
1def delaySS(namespace='D', delay=1e-3, order=1, numins=1, dt=1e-4): 2 3 if delay==0: 4 print('Delay is zero, using nullSS') 5 D_mod = nullSS().mod 6 else: 7 # take the poles of this normalized bessel filter (delay=1s) 8 z, p, k = scipy.signal.besselap(order, norm="delay") 9 10 # now rescale for desired delay 11 roots = p / delay * 2 12 if order % 2 == 0: 13 k = 1 14 else: 15 k = -1 16 17 18 D_mod = SISO.zpk(-roots.conjugate(), roots, k).ss 19 # D_res = control.zpk(-roots.conjugate(), roots, k) 20 # D_mod = control.tf2ss(D_res) 21 22 B_blocked = D_mod.B 23 D_blocked = D_mod.D 24 for ii in range(numins-1): 25 B_blocked = np.block([[B_blocked, D_mod.B]]) 26 D_blocked = np.block([[D_blocked, D_mod.D]]) 27 28 mod = control.ss(D_mod.A, B_blocked, D_mod.C, D_blocked) # Create the system 29 mod_dis = control.c2d(mod, dt) # Discretize the system 30 iod = dict({namespace+'.in': 0, namespace+'.out': 0}) # Input output dictionary 31 for ii in range(numins-1): 32 iod[namespace+'.in.'+str(ii+1)] = ii+1 33 34 return Bunch(locals())
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.delaySSThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- nullSS(namespace='N', gain=1)[source]¶
Create a state space model for the null block. It has one input and one output.
- Parameters:
- Returns:
Returns Wield MIMO statespace
- Return type:
MIMO Statespace
code
docstring
"""Create a state space model for the null block. It has one input and one output. Args: namespace (str, optional): The namespace to use for the model i.e. the letter that comes at the beginning of the input and output names. Defaults to 'N'. gain (float, optional): The gain of the null block. Defaults to 1. Returns: MIMO Statespace: Returns Wield MIMO statespace """
1def nullSS(namespace='N', gain=1): 2 3 4 A = np.zeros([0,0]) # Construct the A state matrix 5 B = np.zeros([1,0]) # Construct the B state matrix 6 C = np.zeros([0,1]) # Construct the C state matrix 7 D = np.array([[gain]]) # Construct the D state matrix 8 iod = dict({namespace+'.in': 0, namespace+'.out': 0}) # Input output dictionary 9 return ssutil.wieldSS(A, B, C, D, iod=iod)
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.nullSSThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.
- test_Make_ADY(folder)[source]¶
This is the main function that is called to create the model for the ASC DHARD Y.
code
docstring
""" This is the main function that is called to create the model for the ASC DHARD Y. """
1@pytest.mark.parametrize( 2 'folder', [ 3 'ExampleModels_working', 4 'ExampleModels_working_F3', 5 'ExampleModels_newFOM', 6 'ExampleModels_newFOM_F3', 7 'ExampleModels_DARMFOM', 8 'ExampleModels_DARMFOM_F3', 9 ] 10) 11@pytest.mark.gitlabCI 12@pytest.mark.ADY 13def test_Make_ADY(folder): 14 15 use_old_balancing = False 16 # not helpful it seems 17 use_alt_balancing = False 18 19 if use_old_balancing: 20 from wield.control.utilities import algorithm_choice 21 # This fix is needed since updating several wield.controls algorithms 22 algorithm_choice.algorithm_adjust_default('zpk2ss', 'zpk2ss_chain_poly_nobal', 200) 23 24 S = ssutil.loadSys(fjoin(folder, 'ADY_E_from_fit.mat')) 25 S = S.balance(which='ABC') 26 if use_old_balancing: 27 S = ssutil.balance_sys_gain(S, verbose=True) 28 if use_alt_balancing: 29 S = ssutil.balance_sys_gain(S, method='bfsqrt', verbose=True) 30 S = S.schur_form() 31 32 O = ssutil.loadSys(fjoin(folder, 'ADY_M_from_fit.mat')) 33 # O = nullSS(namespace='O', gain=5e-5) 34 print('O.A: ', O.A) 35 O = O.balance(which='ABC') 36 if use_old_balancing: 37 O = ssutil.balance_sys_gain(O, verbose=True) 38 if use_alt_balancing: 39 O = ssutil.balance_sys_gain(O, method='bfsqrt', verbose=True) 40 O = O.schur_form() 41 42 # TODO - make solver handle unobserved modes 43 # can be tested by adding one here 44 # the plant of the working folder has a nontrivial statespace for some reason even though 45 # it has a flat response with no poles or zeros 46 # this ensures an un-observable mode that the solver DOES NOT LIKE 47 O = O.siso('O.out', 'O.in').asZPK.asSS.mimo('O.out', 'O.in') 48 49 P_fname = 'ADY_plant_from_fit.mat' 50 P = ssutil.loadSys(fjoin(folder, P_fname)) 51 P = P.balance(which='ABC') 52 #if use_old_balancing: 53 # P = ssutil.balance_sys_gain(P, verbose=True) 54 if use_alt_balancing: 55 P = ssutil.balance_sys_gain(P, method='bfsqrt', verbose=True) 56 P = P.schur_form() 57 58 # print("plant shape:") 59 # P.print_nonzero() 60 61 # this rescale is still helping the solver (it shouldn't!) 62 w2_rescale = 1e6 63 if use_old_balancing: 64 w2_rescale = 1e6 65 66 S = (w2_rescale * S.siso('S.out', 'S.in')).mimo('S.out', 'S.in') 67 O = (w2_rescale * O.siso('O.out', 'O.in')).mimo('O.out', 'O.in') 68 69 if '_newFOM' in folder or '_newFOM_F3' in folder: 70 FBNS_func = FBNSSS_Hand 71 FBNS = FBNS_func() 72 FBNS_zpk = FBNS_func(as_zpk=True) 73 FBNS_scale = FBNS_func(return_scale=True) 74 75 elif 'DARMFOM' in folder: 76 FBNS_func = FBNSSS_DARM 77 FBNS = FBNS_func() 78 FBNS_zpk = FBNS_func(as_zpk=True) 79 FBNS_scale = FBNS_func(return_scale=True) 80 81 else: 82 FBNS_func = FBNSsimpSS 83 FBNS = FBNS_func() 84 FBNS_zpk = FBNS_func(as_zpk=True) 85 FBNS_scale = FBNS_func(return_scale=True) 86 87 omega_limits = [1e-2, 1e4] 88 axB = ssutil.bode(FBNS.siso('FBNS.out', 'FBNS.in'), omega_limits=omega_limits, label='Simple FBNS') 89 axB = ssutil.bode(FBNSSS_Hand().siso('FBNS.out', 'FBNS.in'), omega_limits=omega_limits, axB=axB, label='Hand Fit FBNS') 90 axB = ssutil.bode(FBNSSS_Fit().siso('FBNS.out', 'FBNS.in'), omega_limits=omega_limits, axB=axB, label='FBNS From Data') 91 axB.save(tjoin('BNS_FOMS_Comp.pdf')) 92 axB.save(tjoin('BNS_FOMS_Comp.png')) 93 94 print("OBS STATESPACE-----------------------------------------------------------") 95 print(O.print_nonzero()) 96 print("ZP: ", O.siso('O.out', 'O.in').asZPK.zeros, O.siso('O.out', 'O.in').asZPK.poles) 97 print("/OBS STATESPACE-----------------------------------------------------------") 98 99 print("SEI STATESPACE-----------------------------------------------------------") 100 print(S.print_nonzero()) 101 print("/SEI STATESPACE-----------------------------------------------------------") 102 103 print("FOM STATESPACE-----------------------------------------------------------") 104 if use_old_balancing: 105 FBNS = ssutil.balance_sys_gain(FBNS, verbose=True) 106 print(FBNS.print_nonzero()) 107 print("/FOM STATESPACE-----------------------------------------------------------") 108 109 FFlat = FFlatSS() 110 if use_old_balancing: 111 FFlat = ssutil.balance_sys_gain(FFlat, verbose=True) 112 113 # Inject the coupling into the BNS FOM, normalize it to Hinf=1 and then collect its scale 114 Coup = ssutil.loadSys(fjoin(folder, 'A2L_coupling_with_cal.mat')) # This is the Angle to length coupling it would be multiplied by the BNS FOM 115 if use_old_balancing: 116 Coup = ssutil.balance_sys_gain(Coup, verbose=True) 117 if use_alt_balancing: 118 Coup = ssutil.balance_sys_gain(Coup, method='bfsqrt', verbose=True) 119 Coup = Coup.schur_form() 120 # Coup = SISO.zpk([], [], 1e-14).asSS.mimo('COUP.out', 'COUP.in') 121 122 FBNS_orig = FBNS 123 FBNS = ssutil.multiconnect([Coup, FBNS], [['FBNS.in', 'COUP.out']]) 124 #FBNS = ssutil.truncate_io(FBNS, ['COUP.in'], ['FBNS.out', 'COUP.out']) #commented out to display DARM Spectrum 125 FBNS = ssutil.rename_io(FBNS, 'COUP.out', 'FBNS.DARM.out') # to see DARM Spectrum 126 FBNS = ssutil.rename_io(FBNS, 'FBNS.in', 'FBNS.noC.in') # add a bypass coup for the FBNS 127 FBNS = ssutil.rename_io(FBNS, 'COUP.in', 'FBNS.in') 128 129 FBNS_Trash, Coup_scale = ssutil.normalize_gain(ssutil.truncate_io(FBNS, ['FBNS.in'], ['FBNS.out']), norm=1, return_scale=True, method='fq_resp') 130 del FBNS_Trash 131 FBNS = ssutil.scale_io(FBNS, 'FBNS.out', Coup_scale) # using this to scale preserves the DARM.out output 132 # TODO, comment this for breakage test and uncomment for typical operation 133 #FBNS = ssutil.scale_io(FBNS, 'FBNS.noC.in', 1/Coup_scale) # using this to scale preserves the DARM.out output 134 FBNS = ssutil.scale_io(FBNS, 'FBNS.noC.in', 1/Coup_scale * 1/FBNS_scale) # using this to scale preserves the DARM.out output 135 136 omega_limits_noise = [1e-1, 1e3] 137 axN = ssutil.bode(ssutil.asSISO(ssutil.truncate_io(FBNS, ['FBNS.noC.in'], ['FBNS.out'])), omega_limits=omega_limits_noise, label='FBNS Scaled') 138 axN = ssutil.bode(ssutil.asSISO(FBNS_func(normalize=False)), axB=axN, omega_limits=omega_limits_noise, linestyle='--',label='Unscaled BNS') 139 axN.save(tjoin('FBNS_bode_after_scl.png')) 140 axN.save(tjoin('FBNS_bode_after_scl.pdf')) 141 142 # FBNS_alt = Coup.siso('COUP.out', 'COUP.in') * FBNS.siso('FBNS.out', 'FBNS.in') 143 144 print("FOM STATESPACE-with Coupling---------------------------------------------") 145 print(FBNS.inputs) 146 print(FBNS.print_nonzero()) 147 print("/FOM STATESPACE-with coupling---------------------------------------------") 148 149 FBNS_scale = FBNS_scale * Coup_scale 150 np.savetxt(fjoin(folder, 'FBNS_scale.txt'), [FBNS_scale]) 151 print('FBNS scale', FBNS_scale) 152 153 current_range = np.loadtxt(fjoin(folder, 'FBNS_Current_range.txt')) # Saved by the normalization in the make function 154 io_scales = Bunch( 155 FBNS = FBNS_scale, # will need to apply this to the BNS FOM 156 w2_rescale = w2_rescale, # will need to divide by this on both FOMs 157 # will need to be applied only to the Flat fom since the A2L_coupling_with_cal includes it as a factor 158 ct2rad = 5.2e-11, # Calibration from https://alog.ligo-wa.caltech.edu/aLOG/index.php?callRep=69551 159 strain2m = 1/3995, # Representing the 4km arm length. Strain is h = dL/L where L = 3995 m. The coupling is "I" is 160 # in rad to displacement so we need to convert it to strain for the BNS FOM which is in strain 161 current_range = current_range, 162 coup_scale = Coup_scale, 163 ) 164 io_scales.RMS_cal_F1 = 1/io_scales.FBNS * io_scales.strain2m / io_scales.w2_rescale 165 io_scales.RMS_cal_F2 = io_scales.ct2rad / io_scales.w2_rescale 166 file_io.save(fjoin(folder, 'io_scales.yml'), dict(io_scales)) 167 168 omega_limits = [1e-2, 1e4] 169 170 omega_limits_noise = [1e-1, 1e3] 171 axN = ssutil.bode(ssutil.asSISO(S), omega_limits=omega_limits_noise, label='Seismic') 172 axN = ssutil.bode(ssutil.asSISO(O), axB=axN, omega_limits=omega_limits_noise, label='Meas. Noise') 173 axN = ssutil.bode(ssutil.asSISO(P), axB=axN, omega_limits=omega_limits_noise, label='Plant') 174 axN = ssutil.bode(ssutil.asSISO(S.siso('S.out', 'S.in') * P.siso('P.out', 'P.in')), axB=axN, omega_limits=omega_limits_noise, label='S*P') 175 axN.save(tjoin('Noise_bode.png')) 176 axN.save(tjoin('Noise_bode.pdf')) 177 178 179 # control.bode(S.mod, dB=False, Hz=True, omega_limits=omega_limits, label='Seismic') 180 # control.bode(O.mod, dB=False, Hz=True, omega_limits=omega_limits, label='Meas. Noise') 181 # control.bode(P.mod, dB=False, Hz=True, omega_limits=omega_limits, label='Plant') 182 # control.bode((S.siso('S.out', 'S.in') * P.siso('P.out', 'P.in')).mimo('out', 'in').mod, dB=False, Hz=True, omega_limits=omega_limits, label='S*P') 183 # plt.legend() 184 # plt.savefig(tjoin('Noise_bode.pdf'), bbox_inches='tight') 185 # plt.savefig(tjoin('Noise_bode.png'), bbox_inches='tight', dpi=300) 186 # plt.close() 187 188 omega_limits_fom = np.array([1e-1, 1e5])*2*np.pi 189 axFOM = ssutil.bode(FBNS.siso('FBNS.out', 'FBNS.in'), omega_limits=omega_limits_fom, label='FBNS') 190 axFOM = ssutil.bode(FFlat.siso(iodutil.listoutputs(FFlat)[0], iodutil.listinputs(FFlat)[0]), axB=axFOM, omega_limits=omega_limits_fom, label='FFlat') 191 axFOM.save(tjoin('FOM_bode.pdf')) 192 axFOM.save(tjoin('FOM_bode.png')) 193 # control.bode(FBNS.mod, dB=True, Hz=True, omega_limits=omega_limits, label='FBNS') 194 # control.bode(FFlat.mod, dB=True, Hz=True, omega_limits=omega_limits, label='FFlat') 195 # plt.legend() 196 # plt.savefig(tjoin('FOM_bode.pdf')) 197 # plt.savefig(tjoin('FOM_bode.png')) 198 # plt.close() 199 200 #make the SO 201 #conlist =[['T_SO.in.1', 'O.out'], ['T_SO.in.2','S.out']] 202 #T_SO = addSS(namespace='T_SO', sub=True) 203 #SO = ssutil.multiconnect([S, O, T_SO], conlist) 204 #SO = ssutil.truncate_io(SO, ['O.in', 'S.in'], ['T_SO.out', 'S.out']) 205 #SO = ssutil.rename_io(SO, 'T_SO.out', 'O.out') 206 207 #control.bode(SO.mod[SO.iod['S.out'], SO.iod['S.in']], dB=True, Hz=True, omega_limits=omega_limits, label='S to S') 208 #control.bode(SO.mod[SO.iod['O.out'], SO.iod['O.in']], dB=True, Hz=True, omega_limits=omega_limits, label='O to O') 209 #control.bode(SO.mod[SO.iod['O.out'], SO.iod['S.in']], dB=True, Hz=True, omega_limits=omega_limits, label='S to O', linestyle='--', linewidth=5) 210 #control.bode(S.mod, dB=True, Hz=True, omega_limits=[1e-2, 1e3], label='Orig. S', linestyle='dotted', linewidth=4) 211 #control.bode(O.mod, dB=True, Hz=True, omega_limits=[1e-2, 1e3], label='Orig. O', linestyle='dotted', linewidth=4) 212 #plt.legend(fontsize=8) 213 #plt.savefig(tjoin('SO_bode.pdf')) 214 #plt.close() 215 SPOFF_kw = {} 216 if '_F3' in folder: 217 extras = 'F3_withP' 218 SPOFF_kw['include_F1'] = False 219 FBNS_eff_in = 'F3.in' 220 FBNS_eff_out = 'F3.out' 221 else: 222 extras = None 223 FBNS_eff_in = 'FBNS.in' 224 FBNS_eff_out = 'FBNS.out' 225 226 # TODO, this will break the solve to use noC.in. but debugging breakage 227 SPOFF = ssutil.makeSPOFF( 228 S, P, O, 229 FBNS, 230 FFlat, 231 diagnostic=True, 232 extras=extras, 233 balance=use_old_balancing, 234 # F1in='FBNS.noC.in', 235 F1in='FBNS.in', 236 F1out='FBNS.out', 237 **SPOFF_kw 238 ) 239 SPOFF = SPOFF.topological_sort() 240 SPOFF = SPOFF.balance() 241 # SPOFF = SPOFF.schur_form() 242 243 #print('SPOFF', SPOFF.iod) 244 #SPOFF = ssutil.balance_sys_gain(SPOFF) 245 print("SPOFF STATESPACE-----------------------------------------------------------") 246 try_block_diagonalize = False 247 if try_block_diagonalize: 248 SPOFF = SPOFF.schur_form() 249 print(SPOFF.print_nonzero()) 250 251 sr = np.zeros(SPOFF.ss.Nstates, dtype=float) 252 SPOFF_b2 = SPOFF.balance(which='A', Dr=sr) 253 SPOFF_b2 = SPOFF 254 255 from wield.control.ss_bare.ssprint import print_dense_nonzero_A, print_dense_nonzero, nz_int 256 def flog2(arr): 257 #arr = np.asarray(arr) 258 #mant, exp = np.frexp(arr) 259 exp = np.round(np.log2(abs(arr))) 260 return exp 261 sc = np.block([[flog2(sr)]]) 262 print("scaling?") 263 print(print_dense_nonzero_A(sc, scaling=nz_int)) 264 Tr = np.zeros_like(SPOFF_b2.A) 265 SPOFF_b2 = SPOFF_b2.block_diagonalize(condition_number=1e6, Tright=Tr) 266 print("after balance2") 267 print(SPOFF_b2.print_nonzero()) 268 print("Transfer Matrix") 269 print(print_dense_nonzero_A(Tr)) 270 # SPOFF = SPOFF_b2 271 print("POLES") 272 print(SPOFF_b2.p) 273 print("/SPOFF STATESPACE-----------------------------------------------------------") 274 omega_limits=[1e-2, 1e3] 275 276 axB = mplfigB(Nrows=2) 277 F_Hz = np.geomspace(1e-2, 20, 1000) 278 with SISObode.multi_bode(axB=axB, F_Hz = F_Hz) as bode: 279 bode(P['P.out', 'P.in'], label='P alone', linewidth=2, color='dodgerblue') 280 bode(SPOFF['P.out', 'P.in'], label='P to P in SPOFF', color='orange') 281 bode(SPOFF['P.out', 'S.in'], label='S to P', color='green') 282 bode(SPOFF['S.out', 'S.in'], label='S to S', linestyle='dotted', linewidth=4, color='green') 283 bode(SPOFF['P.out', 'SA.in'], linestyle='--', label='P Recombined', linewidth=4, color='dodgerblue') 284 bode(SPOFF['S.out', 'SA.in'], label='P that moved to S', color='dodgerblue', linestyle='dotted', linewidth=6) 285 bode(SPOFF['G.out', 'S.in'], label='Orig. S (from SPOFF)', color='red') 286 bode(S['S.out', 'S.in'], label='Orig. S alone', linestyle='dotted', linewidth=4, color='red') 287 axB.ax1.legend(fontsize=5) 288 axB.save(tjoin('SPOFF_diagnostic_bode.pdf')) 289 axB.save(tjoin('SPOFF_diagnostic_bode.png')) 290 291 axB = mplfigB(Nrows=2) 292 F_Hz = np.geomspace(1e-2, 20, 1000) 293 with SISObode.multi_bode(axB=axB, F_Hz = F_Hz) as bode: 294 bode(sys=SPOFF['P.out', 'P.in'], label='P to P') 295 bode(sys=SPOFF['P.out', 'S.in'], label='S to P') 296 bode(sys=SPOFF['S.out', 'S.in'], label='S to S', linestyle=':', linewidth=2) 297 bode(sys=S['S.out', 'S.in'], label='S to S (orig)', linestyle=':', linewidth=2) 298 bode(sys=SPOFF['T.out', 'O.in'], label='O to Meas. Out') 299 bode(sys=SPOFF['T.out', 'S.in'], label='S to Meas. Out') 300 301 axB.ax1.legend(fontsize=5) 302 axB.save(tjoin('SPOFF_bode.pdf')) 303 axB.save(tjoin('SPOFF_bode.png')) 304 305 #print('SPOFF', SPOFF.iod) 306 #print(SPOFF['T.out', 'S.in']._zp[1]) 307 308 #truncate_inputs = ['P.in', 'S.in', 'O.in', 'T.in.1', 'T.in.2', 'FBNS.in', 'F2.in', 'Zinf.in'] 309 #truncate_outputs = ['P.out', 'O.out', 'S.out', 'T.out', 'FBNS.out', 'F2.out'] 310 #SPOFF = ssutil.truncate_io(SPOFF, truncate_inputs, truncate_outputs) 311 312 control.bode(SPOFF.mod[SPOFF.iod['F2.out'], SPOFF.iod['P.in']], dB=True, Hz=True, omega_limits=omega_limits, label='P to Flat FOM') 313 control.bode(SPOFF.mod[SPOFF.iod[FBNS_eff_out], SPOFF.iod['P.in']], dB=True, Hz=True, omega_limits=omega_limits, label='P to BNS FOM') 314 control.bode(SPOFF.mod[SPOFF.iod['P.out'], SPOFF.iod['S.in']], dB=True, Hz=True, omega_limits=omega_limits, label='S to P') 315 control.bode(SPOFF.mod[SPOFF.iod['S.out'], SPOFF.iod['S.in']], dB=True, Hz=True, omega_limits=omega_limits, label='S to S', linestyle='dotted', linewidth=4) 316 control.bode(SPOFF.mod[SPOFF.iod['T.out'], SPOFF.iod['O.in']], dB=True, Hz=True, omega_limits=omega_limits, label='O to Meas. Out') 317 control.bode(SPOFF.mod[SPOFF.iod['T.out'], SPOFF.iod['S.in']], dB=True, Hz=True, omega_limits=omega_limits, label='S to Meas. Out') 318 plt.legend(fontsize=5) 319 plt.savefig(tjoin('SPOFF_all_bode.pdf')) 320 plt.savefig(tjoin('SPOFF_all_bode.png')) 321 plt.close() 322 323 # THIS MODIFIES THE ORIGINAL SYSTEM!!!!! WHAT - LEE 324 #SPOFF_bal = ssutil.balance_sys_gain(SPOFF) 325 326 axFOM_S = ssutil.bode(SPOFF.siso(FBNS_eff_out, FBNS_eff_in), omega_limits=omega_limits_fom, label='FBNS', color='red') 327 axFOM_S = ssutil.bode(SPOFF.siso(iodutil.listoutputs(FFlat)[0], iodutil.listinputs(FFlat)[0]), axB=axFOM_S, omega_limits=omega_limits_fom, label='FFlat', color='dodgerblue') 328 #axFOM_S = ssutil.bode(SPOFF_bal.siso(FBNS_eff_out, FBNS_eff_in), omega_limits=omega_limits_fom, axB=axFOM_S, label='FBNS SPOFF bal', color='green') 329 #axFOM_S = ssutil.bode(SPOFF_bal.siso(iodutil.listoutputs(FFlat)[0], iodutil.listinputs(FFlat)[0]), axB=axFOM_S, omega_limits=omega_limits_fom, label='FFlat SPOFF bal', color='green') 330 axFOM_S = ssutil.bode(FBNS.siso('FBNS.out', 'FBNS.in'), axB=axFOM_S, omega_limits=omega_limits_fom, label='FBNS orig.', linestyle='dotted', color='red', linewidth=4) 331 axFOM_S = ssutil.bode(FBNS_orig.siso('FBNS.out', 'FBNS.in'), axB=axFOM_S, omega_limits=omega_limits_fom, label='FBNS orig.s', linestyle='dotted', color='purple', linewidth=4) 332 axFOM_S = ssutil.bode(Coup.siso('COUP.out', 'COUP.in'), axB=axFOM_S, omega_limits=omega_limits_fom, label='FBNS orig.s', linestyle='-', color='magenta', linewidth=4) 333 axFOM_S = ssutil.bode(FBNS_zpk, axB=axFOM_S, omega_limits=omega_limits_fom, label='FBNS orig_zpk.', linestyle='dotted', color='orange', linewidth=4) 334 axFOM_S = ssutil.bode(FFlat.siso(iodutil.listoutputs(FFlat)[0], iodutil.listinputs(FFlat)[0]), axB=axFOM_S, omega_limits=omega_limits_fom, label='FFlat orig.', color='dodgerblue', linestyle='dotted', linewidth=4) 335 axFOM_S.save(tjoin('FOM_bode_from_SPOFF.pdf')) 336 axFOM_S.save(tjoin('FOM_bode_from_SPOFF.png')) 337 338 #SPOFF = ssutil.balance_sys_gain(SPOFF) 339 340 P_load2 = ssutil.loadSys(fjoin(folder, P_fname)) 341 # assert(np.allclose(P_load2.A, P.A)) 342 # assert(np.allclose(P_load2.B, P.B)) 343 # assert(np.allclose(P_load2.C, P.C)) 344 # assert(np.allclose(P_load2.D, P.D)) 345 346 print("SYS?") 347 SPOFF.print_nonzero() 348 349 ssutil.savesys(SPOFF, tjoin('ADY_Sanex.mat')) 350 ssutil.savesys(P, tjoin('ADY_plant.mat')) 351 352 ssutil.savesys(SPOFF, fjoin(folder, 'ADY_Sanex.mat')) 353 ssutil.savesys(P, fjoin(folder, 'ADY_plant.mat')) 354 355 return
pytest information
This code is wrapped in a pytest function using conventions detailed in pytest_conventions. The full name of this test, as known by the documentation, is:
test.ASC_SOLVER.T_make_sys_ADY.test_Make_ADYThe full name is useful when building documentation, to link a reference to this page using
:func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.test_Make_ADY[ExampleModels_newFOM_F3]
output
status: failed duration: 0.026s captured errors: folder = 'ExampleModels_newFOM_F3' @pytest.mark.parametrize( 'folder', [ 'ExampleModels_working', 'ExampleModels_working_F3', 'ExampleModels_newFOM', 'ExampleModels_newFOM_F3', 'ExampleModels_DARMFOM', 'ExampleModels_DARMFOM_F3', ] ) @pytest.mark.gitlabCI @pytest.mark.ADY def test_Make_ADY(folder): """ This is the main function that is called to create the model for the ASC DHARD Y. """ use_old_balancing = False # not helpful it seems use_alt_balancing = False if use_old_balancing: from wield.control.utilities import algorithm_choice # This fix is needed since updating several wield.controls algorithms algorithm_choice.algorithm_adjust_default('zpk2ss', 'zpk2ss_chain_poly_nobal', 200) S = ssutil.loadSys(fjoin(folder, 'ADY_E_from_fit.mat')) > S = S.balance(which='ABC') /builds/buzz/test/ASC_SOLVER/T_make_sys_ADY.py:286: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = MIMOStateSpace with inputs ['S.in'], outputs ['S.out'], and 16 dimensional states kwargs = {'which': 'ABC'} def balance(self, **kwargs): return self.__build_similar__( > ss=self.ss.balanceA(**kwargs), ) E TypeError: BareStateSpace.balanceA() got an unexpected keyword argument 'which' /wield/wield-control/src/wield/control/ss_bare/ss.py:1680: TypeErrortest_Make_ADY[ExampleModels_newFOM]
output
status: failed duration: 0.002s captured errors: folder = 'ExampleModels_newFOM' @pytest.mark.parametrize( 'folder', [ 'ExampleModels_working', 'ExampleModels_working_F3', 'ExampleModels_newFOM', 'ExampleModels_newFOM_F3', 'ExampleModels_DARMFOM', 'ExampleModels_DARMFOM_F3', ] ) @pytest.mark.gitlabCI @pytest.mark.ADY def test_Make_ADY(folder): """ This is the main function that is called to create the model for the ASC DHARD Y. """ use_old_balancing = False # not helpful it seems use_alt_balancing = False if use_old_balancing: from wield.control.utilities import algorithm_choice # This fix is needed since updating several wield.controls algorithms algorithm_choice.algorithm_adjust_default('zpk2ss', 'zpk2ss_chain_poly_nobal', 200) S = ssutil.loadSys(fjoin(folder, 'ADY_E_from_fit.mat')) > S = S.balance(which='ABC') /builds/buzz/test/ASC_SOLVER/T_make_sys_ADY.py:286: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = MIMOStateSpace with inputs ['S.in'], outputs ['S.out'], and 16 dimensional states kwargs = {'which': 'ABC'} def balance(self, **kwargs): return self.__build_similar__( > ss=self.ss.balanceA(**kwargs), ) E TypeError: BareStateSpace.balanceA() got an unexpected keyword argument 'which' /wield/wield-control/src/wield/control/ss_bare/ss.py:1680: TypeErrortest_Make_ADY[ExampleModels_working_F3]
output
status: failed duration: 0.018s captured errors: folder = 'ExampleModels_working_F3' @pytest.mark.parametrize( 'folder', [ 'ExampleModels_working', 'ExampleModels_working_F3', 'ExampleModels_newFOM', 'ExampleModels_newFOM_F3', 'ExampleModels_DARMFOM', 'ExampleModels_DARMFOM_F3', ] ) @pytest.mark.gitlabCI @pytest.mark.ADY def test_Make_ADY(folder): """ This is the main function that is called to create the model for the ASC DHARD Y. """ use_old_balancing = False # not helpful it seems use_alt_balancing = False if use_old_balancing: from wield.control.utilities import algorithm_choice # This fix is needed since updating several wield.controls algorithms algorithm_choice.algorithm_adjust_default('zpk2ss', 'zpk2ss_chain_poly_nobal', 200) S = ssutil.loadSys(fjoin(folder, 'ADY_E_from_fit.mat')) > S = S.balance(which='ABC') /builds/buzz/test/ASC_SOLVER/T_make_sys_ADY.py:286: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = MIMOStateSpace with inputs ['S.in'], outputs ['S.out'], and 16 dimensional states kwargs = {'which': 'ABC'} def balance(self, **kwargs): return self.__build_similar__( > ss=self.ss.balanceA(**kwargs), ) E TypeError: BareStateSpace.balanceA() got an unexpected keyword argument 'which' /wield/wield-control/src/wield/control/ss_bare/ss.py:1680: TypeErrortest_Make_ADY[ExampleModels_DARMFOM_F3]
output
status: failed duration: 0.014s captured errors: folder = 'ExampleModels_DARMFOM_F3' @pytest.mark.parametrize( 'folder', [ 'ExampleModels_working', 'ExampleModels_working_F3', 'ExampleModels_newFOM', 'ExampleModels_newFOM_F3', 'ExampleModels_DARMFOM', 'ExampleModels_DARMFOM_F3', ] ) @pytest.mark.gitlabCI @pytest.mark.ADY def test_Make_ADY(folder): """ This is the main function that is called to create the model for the ASC DHARD Y. """ use_old_balancing = False # not helpful it seems use_alt_balancing = False if use_old_balancing: from wield.control.utilities import algorithm_choice # This fix is needed since updating several wield.controls algorithms algorithm_choice.algorithm_adjust_default('zpk2ss', 'zpk2ss_chain_poly_nobal', 200) S = ssutil.loadSys(fjoin(folder, 'ADY_E_from_fit.mat')) > S = S.balance(which='ABC') /builds/buzz/test/ASC_SOLVER/T_make_sys_ADY.py:286: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = MIMOStateSpace with inputs ['S.in'], outputs ['S.out'], and 16 dimensional states kwargs = {'which': 'ABC'} def balance(self, **kwargs): return self.__build_similar__( > ss=self.ss.balanceA(**kwargs), ) E TypeError: BareStateSpace.balanceA() got an unexpected keyword argument 'which' /wield/wield-control/src/wield/control/ss_bare/ss.py:1680: TypeErrortest_Make_ADY[ExampleModels_working]
output
status: failed duration: 0.022s captured errors: folder = 'ExampleModels_working' @pytest.mark.parametrize( 'folder', [ 'ExampleModels_working', 'ExampleModels_working_F3', 'ExampleModels_newFOM', 'ExampleModels_newFOM_F3', 'ExampleModels_DARMFOM', 'ExampleModels_DARMFOM_F3', ] ) @pytest.mark.gitlabCI @pytest.mark.ADY def test_Make_ADY(folder): """ This is the main function that is called to create the model for the ASC DHARD Y. """ use_old_balancing = False # not helpful it seems use_alt_balancing = False if use_old_balancing: from wield.control.utilities import algorithm_choice # This fix is needed since updating several wield.controls algorithms algorithm_choice.algorithm_adjust_default('zpk2ss', 'zpk2ss_chain_poly_nobal', 200) S = ssutil.loadSys(fjoin(folder, 'ADY_E_from_fit.mat')) > S = S.balance(which='ABC') /builds/buzz/test/ASC_SOLVER/T_make_sys_ADY.py:286: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = MIMOStateSpace with inputs ['S.in'], outputs ['S.out'], and 16 dimensional states kwargs = {'which': 'ABC'} def balance(self, **kwargs): return self.__build_similar__( > ss=self.ss.balanceA(**kwargs), ) E TypeError: BareStateSpace.balanceA() got an unexpected keyword argument 'which' /wield/wield-control/src/wield/control/ss_bare/ss.py:1680: TypeErrortest_Make_ADY[ExampleModels_DARMFOM]
output
status: failed duration: 0.017s captured errors: folder = 'ExampleModels_DARMFOM' @pytest.mark.parametrize( 'folder', [ 'ExampleModels_working', 'ExampleModels_working_F3', 'ExampleModels_newFOM', 'ExampleModels_newFOM_F3', 'ExampleModels_DARMFOM', 'ExampleModels_DARMFOM_F3', ] ) @pytest.mark.gitlabCI @pytest.mark.ADY def test_Make_ADY(folder): """ This is the main function that is called to create the model for the ASC DHARD Y. """ use_old_balancing = False # not helpful it seems use_alt_balancing = False if use_old_balancing: from wield.control.utilities import algorithm_choice # This fix is needed since updating several wield.controls algorithms algorithm_choice.algorithm_adjust_default('zpk2ss', 'zpk2ss_chain_poly_nobal', 200) S = ssutil.loadSys(fjoin(folder, 'ADY_E_from_fit.mat')) > S = S.balance(which='ABC') /builds/buzz/test/ASC_SOLVER/T_make_sys_ADY.py:286: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = MIMOStateSpace with inputs ['S.in'], outputs ['S.out'], and 16 dimensional states kwargs = {'which': 'ABC'} def balance(self, **kwargs): return self.__build_similar__( > ss=self.ss.balanceA(**kwargs), ) E TypeError: BareStateSpace.balanceA() got an unexpected keyword argument 'which' /wield/wield-control/src/wield/control/ss_bare/ss.py:1680: TypeError