class Power_CellVoltage(ExplicitComponent): """ Compute the output voltage of the solar panels. """ def __init__(self, n, filename=None): super(Power_CellVoltage, self).__init__() self.n = n if not filename: fpath = os.path.dirname(os.path.realpath(__file__)) filename = fpath + '/data/Power/curve.dat' dat = np.genfromtxt(filename) nT, nA, nI = dat[:3] nT = int(nT) nA = int(nA) nI = int(nI) T = dat[3:3 + nT] A = dat[3 + nT:3 + nT + nA] I = dat[3 + nT + nA:3 + nT + nA + nI] # noqa: E741 V = dat[3 + nT + nA + nI:].reshape((nT, nA, nI), order='F') self.MBI = MBI(V, [T, A, I], [6, 6, 15], [3, 3, 3]) self.x = np.zeros((84 * n, 3), order='F') self.xV = self.x.reshape((n, 7, 12, 3), order='F') self.dV_dL = np.zeros((n, 12), order='F') self.dV_dT = np.zeros((n, 12, 5), order='F') self.dV_dA = np.zeros((n, 7, 12), order='F') self.dV_dI = np.zeros((n, 12), order='F') def setup(self): n = self.n # Inputs self.add_input('LOS', np.zeros((n)), units=None, desc='Line of Sight over Time') self.add_input('temperature', np.zeros((5, n)), units='degK', desc='Temperature of solar cells over time') self.add_input( 'exposedArea', np.zeros((7, 12, n)), units='m**2', desc='Exposed area to sun for each solar cell over time') self.add_input('Isetpt', np.zeros((12, n)), units='A', desc='Currents of the solar panels') # Outputs self.add_output('V_sol', np.zeros((12, n)), units='V', desc='Output voltage of solar panel over time') def setx(self, inputs): temperature = inputs['temperature'] LOS = inputs['LOS'] exposedArea = inputs['exposedArea'] Isetpt = inputs['Isetpt'] for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): self.xV[:, c, p, 0] = temperature[i, :] self.xV[:, c, p, 1] = LOS * exposedArea[c, p, :] self.xV[:, c, p, 2] = Isetpt[p, :] def compute(self, inputs, outputs): """ Calculate outputs. """ self.setx(inputs) self.raw = self.MBI.evaluate(self.x)[:, 0].reshape((self.n, 7, 12), order='F') outputs['V_sol'] = np.zeros((12, self.n)) for c in range(7): outputs['V_sol'] += self.raw[:, c, :].T def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ exposedArea = inputs['exposedArea'] LOS = inputs['LOS'] self.raw1 = self.MBI.evaluate(self.x, 1)[:, 0].reshape((self.n, 7, 12), order='F') self.raw2 = self.MBI.evaluate(self.x, 2)[:, 0].reshape((self.n, 7, 12), order='F') self.raw3 = self.MBI.evaluate(self.x, 3)[:, 0].reshape((self.n, 7, 12), order='F') self.dV_dL[:] = 0.0 self.dV_dT[:] = 0.0 self.dV_dA[:] = 0.0 self.dV_dI[:] = 0.0 for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): self.dV_dL[:, p] += self.raw2[:, c, p] * exposedArea[c, p, :] self.dV_dT[:, p, i] += self.raw1[:, c, p] self.dV_dA[:, c, p] += self.raw2[:, c, p] * LOS self.dV_dI[:, p] += self.raw3[:, c, p] def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): """ Matrix-vector product with the Jacobian. """ dV_sol = d_outputs['V_sol'] if mode == 'fwd': if 'LOS' in d_inputs: dV_sol += self.dV_dL.T * d_inputs['LOS'] if 'temperature' in d_inputs: for p in range(12): i = 4 if p < 4 else (p % 4) dV_sol[ p, :] += self.dV_dT[:, p, i] * d_inputs['temperature'][i, :] if 'Isetpt' in d_inputs: dV_sol += self.dV_dI.T * d_inputs['Isetpt'] if 'exposedArea' in d_inputs: for p in range(12): dV_sol[p, :] += \ np.sum(self.dV_dA[:, :, p] * d_inputs['exposedArea'][:, p, :].T, 1) else: for p in range(12): i = 4 if p < 4 else (p % 4) if 'LOS' in d_inputs: d_inputs['LOS'] += self.dV_dL[:, p] * dV_sol[p, :] if 'temperature' in d_inputs: d_inputs['temperature'][ i, :] += self.dV_dT[:, p, i] * dV_sol[p, :] if 'Isetpt' in d_inputs: d_inputs['Isetpt'][p, :] += self.dV_dI[:, p] * dV_sol[p, :] if 'exposedArea' in d_inputs: dexposedArea = d_inputs['exposedArea'] for c in range(7): dexposedArea[c, p, :] += self.dV_dA[:, c, p] * dV_sol[p, :]
class Solar_ExposedArea(Component): '''Exposed area calculation for a given solar cell p: panel ID [0,11] c: cell ID [0,6] a: fin angle [0,90] z: azimuth [0,360] e: elevation [0,180] LOS: line of sight with the sun [0,1] ''' # Inputs finAngle = Float(0., iotype="in", copy=None) def __init__(self, n, raw1=None, raw2=None): super(Solar_ExposedArea, self).__init__() if raw1 is None: raw1 = np.genfromtxt('CADRE/data/Solar/Area10.txt') if raw2 is None: raw2 = np.loadtxt("CADRE/data/Solar/Area_all.txt") self.n = n self.nc = 7 self.np = 12 # Inputs self.add('azimuth', Array(np.zeros((n,)), size=(n,), dtype=np.float, iotype='in')) self.add('elevation', Array(np.zeros((n,)), size=(n,), dtype=np.float, iotype='in')) # Outputs self.add('exposedArea', Array(np.zeros((self.nc, self.np, self.n)), size=(self.nc, self.np, self.n), dtype=np.float, iotype='out', low=-5e-3, high=1.834e-1)) self.na = 10 self.nz = 73 self.ne = 37 angle = np.zeros(self.na) azimuth = np.zeros(self.nz) elevation = np.zeros(self.ne) index = 0 for i in range(self.na): angle[i] = raw1[index] index += 1 for i in range(self.nz): azimuth[i] = raw1[index] index += 1 index -= 1 azimuth[self.nz-1] = 2.0*np.pi for i in range(self.ne): elevation[i] = raw1[index] index += 1 angle[0] = 0.0 angle[-1] = np.pi/2.0 azimuth[0] = 0.0 azimuth[-1] = 2*np.pi elevation[0] = 0.0 elevation[-1] = np.pi counter = 0 data = np.zeros((self.na, self.nz, self.ne, self.np*self.nc)) flat_size = self.na*self.nz*self.ne for p in range(self.np): for c in range(self.nc): data[:, :, :, counter] = \ raw2[7*p+c][119:119+flat_size].reshape((self.na, self.nz, self.ne)) counter += 1 self.MBI = MBI(data, [angle, azimuth, elevation], [4, 10, 8], [4, 4, 4]) self.x = np.zeros((self.n, 3)) self.Jfin = None self.Jaz = None self.Jel = None def setx(self): """ Sets our state array""" result = fixangles(self.n, self.azimuth, self.elevation) self.x[:, 0] = self.finAngle self.x[:, 1] = result[0] self.x[:, 2] = result[1] def linearize(self): """ Calculate and save derivatives. (i.e., Jacobian) """ self.Jfin = self.MBI.evaluate(self.x, 1).reshape(self.n, 7, 12, order='F') self.Jaz = self.MBI.evaluate(self.x, 2).reshape(self.n, 7, 12, order='F') self.Jel = self.MBI.evaluate(self.x, 3).reshape(self.n, 7, 12, order='F') def execute(self): """ Calculate output. """ self.setx() P = self.MBI.evaluate(self.x).T self.exposedArea = P.reshape(7, 12, self.n, order='F') def apply_deriv(self, arg, result): """ Matrix-vector product with the Jacobian. """ if 'exposedArea' in result: for c in range(7): if 'finAngle' in arg: result['exposedArea'][c, :, :] += \ self.Jfin[:, c, :].T*arg['finAngle'] if 'azimuth' in arg: result['exposedArea'][c, :, :] += \ self.Jaz[:, c, :].T*arg['azimuth'] if 'elevation' in arg: result['exposedArea'][c, :, :] += \ self.Jel[:, c, :].T*arg['elevation'] def apply_derivT(self, arg, result): """ Matrix-vector product with the transpose of the Jacobian. """ if 'exposedArea' in arg: for c in range(7): # incoming arg is often sparse, so check it first if len(np.nonzero(arg['exposedArea'][c, :, :])[0]) == 0: continue if 'finAngle' in result: result['finAngle'] += \ np.sum(self.Jfin[:, c, :].T*arg['exposedArea'][c, :, :]) if 'azimuth' in result: result['azimuth'] += \ np.sum(self.Jaz[:, c, :].T*arg['exposedArea'][c, :, :], 0) if 'elevation' in result: result['elevation'] += \ np.sum(self.Jel[:, c, :].T*arg['exposedArea'][c, :, :], 0)
class Solar_ExposedArea(Component): """Exposed area calculation for a given solar cell p: panel ID [0,11] c: cell ID [0,6] a: fin angle [0,90] z: azimuth [0,360] e: elevation [0,180] LOS: line of sight with the sun [0,1] """ def __init__(self, n, raw1=None, raw2=None): super(Solar_ExposedArea, self).__init__() if raw1 is None: fpath = os.path.dirname(os.path.realpath(__file__)) raw1 = np.genfromtxt(fpath + '/data/Solar/Area10.txt') if raw2 is None: fpath = os.path.dirname(os.path.realpath(__file__)) raw2 = np.loadtxt(fpath + "/data/Solar/Area_all.txt") self.n = n self.nc = 7 self.np = 12 # Inputs self.add_param('finAngle', 0.0, units="rad", desc="Fin angle of solar panel") self.add_param('azimuth', np.zeros((n, )), units='rad', desc="Azimuth angle of the sun in the body-fixed frame " "over time") self.add_param('elevation', np.zeros((n, )), units='rad', desc='Elevation angle of the sun in the body-fixed ' 'frame over time') # Outputs self.add_output('exposedArea', np.zeros((self.nc, self.np, self.n)), desc="Exposed area to sun for each solar cell over time", units='m**2', low=-5e-3, high=1.834e-1) self.na = 10 self.nz = 73 self.ne = 37 angle = np.zeros(self.na) azimuth = np.zeros(self.nz) elevation = np.zeros(self.ne) index = 0 for i in range(self.na): angle[i] = raw1[index] index += 1 for i in range(self.nz): azimuth[i] = raw1[index] index += 1 index -= 1 azimuth[self.nz - 1] = 2.0 * np.pi for i in range(self.ne): elevation[i] = raw1[index] index += 1 angle[0] = 0.0 angle[-1] = np.pi / 2.0 azimuth[0] = 0.0 azimuth[-1] = 2 * np.pi elevation[0] = 0.0 elevation[-1] = np.pi counter = 0 data = np.zeros((self.na, self.nz, self.ne, self.np * self.nc)) flat_size = self.na * self.nz * self.ne for p in range(self.np): for c in range(self.nc): data[:, :, :, counter] = \ raw2[7 * p + c][119:119 + flat_size].reshape((self.na, self.nz, self.ne)) counter += 1 self.MBI = MBI(data, [angle, azimuth, elevation], [4, 10, 8], [4, 4, 4]) self.x = np.zeros((self.n, 3)) self.Jfin = None self.Jaz = None self.Jel = None def solve_nonlinear(self, params, unknowns, resids): """ Calculate output. """ self.setx(params) P = self.MBI.evaluate(self.x).T unknowns['exposedArea'] = P.reshape(7, 12, self.n, order='F') def setx(self, params): """ Sets our state array""" result = fixangles(self.n, params['azimuth'], params['elevation']) self.x[:, 0] = params['finAngle'] self.x[:, 1] = result[0] self.x[:, 2] = result[1] def jacobian(self, params, unknowns, resids): """ Calculate and save derivatives. (i.e., Jacobian) """ self.Jfin = self.MBI.evaluate(self.x, 1).reshape(self.n, 7, 12, order='F') self.Jaz = self.MBI.evaluate(self.x, 2).reshape(self.n, 7, 12, order='F') self.Jel = self.MBI.evaluate(self.x, 3).reshape(self.n, 7, 12, order='F') def apply_linear(self, params, unknowns, dparams, dunknowns, dresids, mode): """ Matrix-vector product with the Jacobian. """ deA = dresids['exposedArea'] if mode == 'fwd': for c in range(7): if 'finAngle' in dparams: deA[c, :, :] += \ self.Jfin[:, c, :].T * dparams['finAngle'] if 'azimuth' in dparams: deA[c, :, :] += \ self.Jaz[:, c, :].T * dparams['azimuth'] if 'elevation' in dparams: deA[c, :, :] += \ self.Jel[:, c, :].T * dparams['elevation'] else: for c in range(7): # incoming arg is often sparse, so check it first if len(np.nonzero(dresids['exposedArea'][c, :, :])[0]) == 0: continue if 'finAngle' in dparams: dparams['finAngle'] += \ np.sum( self.Jfin[:, c, :].T * deA[c, :, :]) if 'azimuth' in dparams: dparams['azimuth'] += \ np.sum( self.Jaz[:, c, :].T * deA[c, :, :], 0) if 'elevation' in dparams: dparams['elevation'] += \ np.sum( self.Jel[:, c, :].T * deA[c, :, :], 0)
class Comm_GainPattern(ExplicitComponent): """ Determines transmitter gain based on an external az-el map. """ def __init__(self, n, rawG_file=None): super(Comm_GainPattern, self).__init__() self.n = n if not rawG_file: fpath = os.path.dirname(os.path.realpath(__file__)) rawG_file = fpath + '/data/Comm/Gain.txt' rawGdata = np.genfromtxt(rawG_file) rawG = (10 ** (rawGdata / 10.0)).reshape((361, 361), order='F') pi = np.pi az = np.linspace(0, 2 * pi, 361) el = np.linspace(0, 2 * pi, 361) self.MBI = MBI(rawG, [az, el], [15, 15], [4, 4]) self.x = np.zeros((self.n, 2), order='F') def setup(self): n = self.n # Inputs self.add_input('azimuthGS', np.zeros(n), units='rad', desc='Azimuth angle from satellite to ground station in ' 'Earth-fixed frame over time') self.add_input('elevationGS', np.zeros(n), units='rad', desc='Elevation angle from satellite to ground station ' 'in Earth-fixed frame over time') # Outputs self.add_output('gain', np.zeros(n), units=None, desc='Transmitter gain over time') def compute(self, inputs, outputs): """ Calculate outputs. """ result = fixangles(self.n, inputs['azimuthGS'], inputs['elevationGS']) self.x[:, 0] = result[0] self.x[:, 1] = result[1] outputs['gain'] = self.MBI.evaluate(self.x)[:, 0] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ self.dg_daz = self.MBI.evaluate(self.x, 1)[:, 0] self.dg_del = self.MBI.evaluate(self.x, 2)[:, 0] def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): """ Matrix-vector product with the Jacobian. """ dgain = d_outputs['gain'] if mode == 'fwd': if 'azimuthGS' in d_inputs: dgain += self.dg_daz * d_inputs['azimuthGS'] if 'elevationGS' in d_inputs: dgain += self.dg_del * d_inputs['elevationGS'] else: if 'azimuthGS' in d_inputs: d_inputs['azimuthGS'] += self.dg_daz * dgain if 'elevationGS' in d_inputs: d_inputs['elevationGS'] += self.dg_del * dgain
class Power_CellVoltage(ExplicitComponent): """ Compute the output voltage of the solar panels. """ def __init__(self, n, filename=None): super(Power_CellVoltage, self).__init__() self.n = n if not filename: fpath = os.path.dirname(os.path.realpath(__file__)) filename = fpath + '/data/Power/curve.dat' dat = np.genfromtxt(filename) nT, nA, nI = dat[:3] nT = int(nT) nA = int(nA) nI = int(nI) T = dat[3:3 + nT] A = dat[3 + nT:3 + nT + nA] I = dat[3 + nT + nA:3 + nT + nA + nI] # noqa: E741 V = dat[3 + nT + nA + nI:].reshape((nT, nA, nI), order='F') self.MBI = MBI(V, [T, A, I], [6, 6, 15], [3, 3, 3]) self.x = np.zeros((84 * n, 3), order='F') self.xV = self.x.reshape((n, 7, 12, 3), order='F') self.dV_dL = np.zeros((n, 12), order='F') self.dV_dT = np.zeros((n, 12, 5), order='F') self.dV_dA = np.zeros((n, 7, 12), order='F') self.dV_dI = np.zeros((n, 12), order='F') def setup(self): n = self.n # Inputs self.add_input('LOS', np.zeros((n)), units=None, desc='Line of Sight over Time') self.add_input('temperature', np.zeros((5, n)), units='degK', desc='Temperature of solar cells over time') self.add_input('exposedArea', np.zeros((7, 12, n)), units='m**2', desc='Exposed area to sun for each solar cell over time') self.add_input('Isetpt', np.zeros((12, n)), units='A', desc='Currents of the solar panels') # Outputs self.add_output('V_sol', np.zeros((12, n)), units='V', desc='Output voltage of solar panel over time') def setx(self, inputs): temperature = inputs['temperature'] LOS = inputs['LOS'] exposedArea = inputs['exposedArea'] Isetpt = inputs['Isetpt'] for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): self.xV[:, c, p, 0] = temperature[i, :] self.xV[:, c, p, 1] = LOS * exposedArea[c, p, :] self.xV[:, c, p, 2] = Isetpt[p, :] def compute(self, inputs, outputs): """ Calculate outputs. """ self.setx(inputs) self.raw = self.MBI.evaluate(self.x)[:, 0].reshape((self.n, 7, 12), order='F') outputs['V_sol'] = np.zeros((12, self.n)) for c in range(7): outputs['V_sol'] += self.raw[:, c, :].T def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ exposedArea = inputs['exposedArea'] LOS = inputs['LOS'] self.raw1 = self.MBI.evaluate(self.x, 1)[:, 0].reshape((self.n, 7, 12), order='F') self.raw2 = self.MBI.evaluate(self.x, 2)[:, 0].reshape((self.n, 7, 12), order='F') self.raw3 = self.MBI.evaluate(self.x, 3)[:, 0].reshape((self.n, 7, 12), order='F') self.dV_dL[:] = 0.0 self.dV_dT[:] = 0.0 self.dV_dA[:] = 0.0 self.dV_dI[:] = 0.0 for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): self.dV_dL[:, p] += self.raw2[:, c, p] * exposedArea[c, p, :] self.dV_dT[:, p, i] += self.raw1[:, c, p] self.dV_dA[:, c, p] += self.raw2[:, c, p] * LOS self.dV_dI[:, p] += self.raw3[:, c, p] def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): """ Matrix-vector product with the Jacobian. """ dV_sol = d_outputs['V_sol'] if mode == 'fwd': if 'LOS' in d_inputs: dV_sol += self.dV_dL.T * d_inputs['LOS'] if 'temperature' in d_inputs: for p in range(12): i = 4 if p < 4 else (p % 4) dV_sol[p, :] += self.dV_dT[:, p, i] * d_inputs['temperature'][i, :] if 'Isetpt' in d_inputs: dV_sol += self.dV_dI.T * d_inputs['Isetpt'] if 'exposedArea' in d_inputs: for p in range(12): dV_sol[p, :] += \ np.sum(self.dV_dA[:, :, p] * d_inputs['exposedArea'][:, p, :].T, 1) else: for p in range(12): i = 4 if p < 4 else (p % 4) if 'LOS' in d_inputs: d_inputs['LOS'] += self.dV_dL[:, p] * dV_sol[p, :] if 'temperature' in d_inputs: d_inputs['temperature'][i, :] += self.dV_dT[:, p, i] * dV_sol[p, :] if 'Isetpt' in d_inputs: d_inputs['Isetpt'][p, :] += self.dV_dI[:, p] * dV_sol[p, :] if 'exposedArea' in d_inputs: dexposedArea = d_inputs['exposedArea'] for c in range(7): dexposedArea[c, p, :] += self.dV_dA[:, c, p] * dV_sol[p, :]
class PowerCellVoltage(ExplicitComponent): """ Compute the output voltage of the solar panels. """ def initialize(self): fpath = os.path.dirname(os.path.realpath(__file__)) self.options.declare('num_nodes', types=(int, ), desc="Number of time points.") self.options.declare( 'filename', fpath + '/../data/Power/curve.dat', desc="File containing surrogate model for voltage.") def setup(self): nn = self.options['num_nodes'] filename = self.options['filename'] dat = np.genfromtxt(filename) nT, nA, nI = dat[:3] nT = int(nT) nA = int(nA) nI = int(nI) T = dat[3:3 + nT] A = dat[3 + nT:3 + nT + nA] I = dat[3 + nT + nA:3 + nT + nA + nI] # noqa: E741 V = dat[3 + nT + nA + nI:].reshape((nT, nA, nI), order='F') self.MBI = MBI(V, [T, A, I], [6, 6, 15], [3, 3, 3]) self.x = np.zeros((84 * nn, 3), order='F') self.xV = self.x.reshape((nn, 7, 12, 3), order='F') # Inputs self.add_input('LOS', np.zeros((nn, )), units=None, desc='Line of Sight over Time') self.add_input('temperature', np.zeros((nn, 5)), units='degK', desc='Temperature of solar cells over time') self.add_input( 'exposed_area', np.zeros((nn, 7, 12)), units='m**2', desc='Exposed area to sun for each solar cell over time') self.add_input('Isetpt', np.zeros((nn, 12)), units='A', desc='Currents of the solar panels') # Outputs self.add_output('V_sol', np.zeros((nn, 12)), units='V', desc='Output voltage of solar panel over time') rows = np.arange(nn * 12) cols = np.tile(np.repeat(0, 12), nn) + np.repeat(np.arange(nn), 12) self.declare_partials('V_sol', 'LOS', rows=rows, cols=cols) row = np.tile(np.repeat(0, 5), 12) + np.repeat(np.arange(12), 5) rows = np.tile(row, nn) + np.repeat(12 * np.arange(nn), 60) col = np.tile(np.arange(5), 12) cols = np.tile(col, nn) + np.repeat(5 * np.arange(nn), 60) self.declare_partials('V_sol', 'temperature', rows=rows, cols=cols) row = np.tile(np.arange(12), 7) rows = np.tile(row, nn) + np.repeat(12 * np.arange(nn), 84) cols = np.arange(nn * 7 * 12) self.declare_partials('V_sol', 'exposed_area', rows=rows, cols=cols) row_col = np.arange(nn * 12) self.declare_partials('V_sol', 'Isetpt', rows=row_col, cols=row_col) def setx(self, inputs): temperature = inputs['temperature'] LOS = inputs['LOS'] exposed_area = inputs['exposed_area'] Isetpt = inputs['Isetpt'] for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): self.xV[:, c, p, 0] = temperature[:, i] self.xV[:, c, p, 1] = LOS * exposed_area[:, c, p] self.xV[:, c, p, 2] = Isetpt[:, p] def compute(self, inputs, outputs): """ Calculate outputs. """ nn = self.options['num_nodes'] self.setx(inputs) self.raw = self.MBI.evaluate(self.x)[:, 0].reshape((nn, 7, 12), order='F') outputs['V_sol'] = np.zeros((nn, 12)) for c in range(7): outputs['V_sol'] += self.raw[:, c, :] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ nn = self.options['num_nodes'] exposed_area = inputs['exposed_area'] LOS = inputs['LOS'] raw1 = self.MBI.evaluate(self.x, 1)[:, 0].reshape((nn, 7, 12), order='F') raw2 = self.MBI.evaluate(self.x, 2)[:, 0].reshape((nn, 7, 12), order='F') raw3 = self.MBI.evaluate(self.x, 3)[:, 0].reshape((nn, 7, 12), order='F') dV_dL = np.empty((nn, 12)) dV_dT = np.zeros((nn, 12, 5)) dV_dA = np.zeros((nn, 7, 12)) dV_dI = np.empty((nn, 12)) for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): dV_dL[:, p] += raw2[:, c, p] * exposed_area[:, c, p] dV_dT[:, p, i] += raw1[:, c, p] dV_dA[:, c, p] += raw2[:, c, p] * LOS dV_dI[:, p] += raw3[:, c, p] partials['V_sol', 'LOS'] = dV_dL.flatten() partials['V_sol', 'temperature'] = dV_dT.flatten() partials['V_sol', 'exposed_area'] = dV_dA.flatten() partials['V_sol', 'Isetpt'] = dV_dI.flatten()
class Solar_ExposedArea(Component): '''Exposed area calculation for a given solar cell p: panel ID [0,11] c: cell ID [0,6] a: fin angle [0,90] z: azimuth [0,360] e: elevation [0,180] LOS: line of sight with the sun [0,1] ''' # Inputs finAngle = Float(0., iotype="in", units="rad", desc="Fin angle of solar panel", copy=None) def __init__(self, n, raw1=None, raw2=None): super(Solar_ExposedArea, self).__init__() if raw1 is None: fpath = os.path.dirname(os.path.realpath(__file__)) raw1 = np.genfromtxt(fpath + '/data/Solar/Area10.txt') if raw2 is None: fpath = os.path.dirname(os.path.realpath(__file__)) raw2 = np.loadtxt(fpath + "/data/Solar/Area_all.txt") self.n = n self.nc = 7 self.np = 12 # Inputs self.add('azimuth', Array(np.zeros((n,)), size=(n,), dtype=np.float, units='rad', desc='Azimuth angle of the sun in the body-fixed frame over time', iotype='in')) self.add('elevation', Array(np.zeros((n,)), size=(n,), dtype=np.float, units='rad', desc='Elevation angle of the sun in the body-fixed frame over time', iotype='in')) # Outputs self.add('exposedArea', Array(np.zeros((self.nc, self.np, self.n)), size=(self.nc, self.np, self.n), dtype=np.float, iotype='out', desc="Exposed area to sun for each solar cell over time", units='m**2', low=-5e-3, high=1.834e-1)) self.na = 10 self.nz = 73 self.ne = 37 angle = np.zeros(self.na) azimuth = np.zeros(self.nz) elevation = np.zeros(self.ne) index = 0 for i in range(self.na): angle[i] = raw1[index] index += 1 for i in range(self.nz): azimuth[i] = raw1[index] index += 1 index -= 1 azimuth[self.nz - 1] = 2.0 * np.pi for i in range(self.ne): elevation[i] = raw1[index] index += 1 angle[0] = 0.0 angle[-1] = np.pi / 2.0 azimuth[0] = 0.0 azimuth[-1] = 2 * np.pi elevation[0] = 0.0 elevation[-1] = np.pi counter = 0 data = np.zeros((self.na, self.nz, self.ne, self.np * self.nc)) flat_size = self.na * self.nz * self.ne for p in range(self.np): for c in range(self.nc): data[:, :, :, counter] = \ raw2[7 * p + c][119:119 + flat_size].reshape((self.na, self.nz, self.ne)) counter += 1 self.MBI = MBI(data, [angle, azimuth, elevation], [4, 10, 8], [4, 4, 4]) self.x = np.zeros((self.n, 3)) self.Jfin = None self.Jaz = None self.Jel = None def list_deriv_vars(self): input_keys = ('azimuth', 'elevation', 'finAngle',) output_keys = ('exposedArea',) return input_keys, output_keys def setx(self): """ Sets our state array""" result = fixangles(self.n, self.azimuth, self.elevation) self.x[:, 0] = self.finAngle self.x[:, 1] = result[0] self.x[:, 2] = result[1] def provideJ(self): """ Calculate and save derivatives (i.e., Jacobian). """ self.Jfin = self.MBI.evaluate(self.x, 1).reshape(self.n, 7, 12, order='F') self.Jaz = self.MBI.evaluate(self.x, 2).reshape(self.n, 7, 12, order='F') self.Jel = self.MBI.evaluate(self.x, 3).reshape(self.n, 7, 12, order='F') def execute(self): """ Calculate output. """ self.setx() P = self.MBI.evaluate(self.x).T self.exposedArea = P.reshape(7, 12, self.n, order='F') def apply_deriv(self, arg, result): """ Matrix-vector product with the Jacobian. """ if 'exposedArea' in result: for c in range(7): if 'finAngle' in arg: result['exposedArea'][c, :, :] += \ self.Jfin[:, c, :].T * arg['finAngle'] if 'azimuth' in arg: result['exposedArea'][c, :, :] += \ self.Jaz[:, c, :].T * arg['azimuth'] if 'elevation' in arg: result['exposedArea'][c, :, :] += \ self.Jel[:, c, :].T * arg['elevation'] def apply_derivT(self, arg, result): """ Matrix-vector product with the transpose of the Jacobian. """ if 'exposedArea' in arg: for c in range(7): # incoming arg is often sparse, so check it first if len(np.nonzero(arg['exposedArea'][c, :, :])[0]) == 0: continue if 'finAngle' in result: result['finAngle'] += \ np.sum( self.Jfin[:, c, :].T * arg['exposedArea'][c, :, :]) if 'azimuth' in result: result['azimuth'] += \ np.sum( self.Jaz[:, c, :].T * arg['exposedArea'][c, :, :], 0) if 'elevation' in result: result['elevation'] += \ np.sum( self.Jel[:, c, :].T * arg['exposedArea'][c, :, :], 0)
class Solar_ExposedArea(Component): """Exposed area calculation for a given solar cell p: panel ID [0,11] c: cell ID [0,6] a: fin angle [0,90] z: azimuth [0,360] e: elevation [0,180] LOS: line of sight with the sun [0,1] """ def __init__(self, n, raw1=None, raw2=None): super(Solar_ExposedArea, self).__init__() if raw1 is None: fpath = os.path.dirname(os.path.realpath(__file__)) raw1 = np.genfromtxt(fpath + '/data/Solar/Area10.txt') if raw2 is None: fpath = os.path.dirname(os.path.realpath(__file__)) raw2 = np.loadtxt(fpath + "/data/Solar/Area_all.txt") self.n = n self.nc = 7 self.np = 12 # Inputs self.add_param('finAngle', 0.0, units="rad", desc="Fin angle of solar panel") self.add_param('azimuth', np.zeros((n, )), units='rad', desc="Azimuth angle of the sun in the body-fixed frame " "over time") self.add_param('elevation', np.zeros((n, )), units='rad', desc='Elevation angle of the sun in the body-fixed ' 'frame over time') # Outputs self.add_output( 'exposedArea', np.zeros((self.nc, self.np, self.n)), desc="Exposed area to sun for each solar cell over time", units='m**2', low=-5e-3, high=1.834e-1) self.na = 10 self.nz = 73 self.ne = 37 angle = np.zeros(self.na) azimuth = np.zeros(self.nz) elevation = np.zeros(self.ne) index = 0 for i in range(self.na): angle[i] = raw1[index] index += 1 for i in range(self.nz): azimuth[i] = raw1[index] index += 1 index -= 1 azimuth[self.nz - 1] = 2.0 * np.pi for i in range(self.ne): elevation[i] = raw1[index] index += 1 angle[0] = 0.0 angle[-1] = np.pi / 2.0 azimuth[0] = 0.0 azimuth[-1] = 2 * np.pi elevation[0] = 0.0 elevation[-1] = np.pi counter = 0 data = np.zeros((self.na, self.nz, self.ne, self.np * self.nc)) flat_size = self.na * self.nz * self.ne for p in range(self.np): for c in range(self.nc): data[:, :, :, counter] = \ raw2[7 * p + c][119:119 + flat_size].reshape((self.na, self.nz, self.ne)) counter += 1 self.MBI = MBI(data, [angle, azimuth, elevation], [4, 10, 8], [4, 4, 4]) self.x = np.zeros((self.n, 3)) self.Jfin = None self.Jaz = None self.Jel = None def solve_nonlinear(self, params, unknowns, resids): """ Calculate output. """ self.setx(params) P = self.MBI.evaluate(self.x).T unknowns['exposedArea'] = P.reshape(7, 12, self.n, order='F') def setx(self, params): """ Sets our state array""" result = fixangles(self.n, params['azimuth'], params['elevation']) self.x[:, 0] = params['finAngle'] self.x[:, 1] = result[0] self.x[:, 2] = result[1] def jacobian(self, params, unknowns, resids): """ Calculate and save derivatives. (i.e., Jacobian) """ self.Jfin = self.MBI.evaluate(self.x, 1).reshape(self.n, 7, 12, order='F') self.Jaz = self.MBI.evaluate(self.x, 2).reshape(self.n, 7, 12, order='F') self.Jel = self.MBI.evaluate(self.x, 3).reshape(self.n, 7, 12, order='F') def apply_linear(self, params, unknowns, dparams, dunknowns, dresids, mode): """ Matrix-vector product with the Jacobian. """ deA = dresids['exposedArea'] if mode == 'fwd': for c in range(7): if 'finAngle' in dparams: deA[c, :, :] += \ self.Jfin[:, c, :].T * dparams['finAngle'] if 'azimuth' in dparams: deA[c, :, :] += \ self.Jaz[:, c, :].T * dparams['azimuth'] if 'elevation' in dparams: deA[c, :, :] += \ self.Jel[:, c, :].T * dparams['elevation'] else: for c in range(7): # incoming arg is often sparse, so check it first if len(np.nonzero(dresids['exposedArea'][c, :, :])[0]) == 0: continue if 'finAngle' in dparams: dparams['finAngle'] += \ np.sum( self.Jfin[:, c, :].T * deA[c, :, :]) if 'azimuth' in dparams: dparams['azimuth'] += \ np.sum( self.Jaz[:, c, :].T * deA[c, :, :], 0) if 'elevation' in dparams: dparams['elevation'] += \ np.sum( self.Jel[:, c, :].T * deA[c, :, :], 0)
class Comm_GainPattern(ExplicitComponent): """ Determines transmitter gain based on an external az-el map. """ def __init__(self, n, rawG_file=None): super(Comm_GainPattern, self).__init__() self.n = n if not rawG_file: fpath = os.path.dirname(os.path.realpath(__file__)) rawG_file = fpath + '/data/Comm/Gain.txt' rawGdata = np.genfromtxt(rawG_file) rawG = (10**(rawGdata / 10.0)).reshape((361, 361), order='F') pi = np.pi az = np.linspace(0, 2 * pi, 361) el = np.linspace(0, 2 * pi, 361) self.MBI = MBI(rawG, [az, el], [15, 15], [4, 4]) self.MBI.seterr('raise') self.x = np.zeros((self.n, 2), order='F') def setup(self): n = self.n # Inputs self.add_input( 'azimuthGS', np.zeros(n), units='rad', desc='Azimuth angle from satellite to ground station in ' 'Earth-fixed frame over time') self.add_input('elevationGS', np.zeros(n), units='rad', desc='Elevation angle from satellite to ground station ' 'in Earth-fixed frame over time') # Outputs self.add_output('gain', np.zeros(n), units=None, desc='Transmitter gain over time') row_col = np.arange(n) self.declare_partials('gain', 'elevationGS', rows=row_col, cols=row_col) self.declare_partials('gain', 'azimuthGS', rows=row_col, cols=row_col) def compute(self, inputs, outputs): """ Calculate outputs. """ result = fixangles(self.n, inputs['azimuthGS'], inputs['elevationGS']) self.x[:, 0] = result[0] self.x[:, 1] = result[1] outputs['gain'] = self.MBI.evaluate(self.x)[:, 0] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ partials['gain', 'azimuthGS'] = self.MBI.evaluate(self.x, 1)[:, 0] partials['gain', 'elevationGS'] = self.MBI.evaluate(self.x, 2)[:, 0]
class Comm_GainPattern(Component): ''' Determines transmitter gain based on an external az-el map. ''' def __init__(self, n, rawG=None): super(Comm_GainPattern, self).__init__() self.n = n if rawG is None: fpath = os.path.dirname(os.path.realpath(__file__)) rawGdata = np.genfromtxt(fpath + '/data/Comm/Gain.txt') rawG = (10 ** (rawGdata / 10.0)).reshape((361, 361), order='F') # Inputs self.add_param('azimuthGS', np.zeros(n), units="rad", desc="Azimuth angle from satellite to ground station in " "Earth-fixed frame over time") self.add_param('elevationGS', np.zeros(n), units="rad", desc="Elevation angle from satellite to ground station " "in Earth-fixed frame over time") # Outputs self.add_output('gain', np.zeros(n), units="unitless", desc="Transmitter gain over time") pi = np.pi az = np.linspace(0, 2 * pi, 361) el = np.linspace(0, 2 * pi, 361) self.MBI = MBI(rawG, [az, el], [15, 15], [4, 4]) self.x = np.zeros((self.n, 2), order='F') def solve_nonlinear(self, params, unknowns, resids): """ Calculate output. """ result = fixangles(self.n, params['azimuthGS'], params['elevationGS']) self.x[:, 0] = result[0] self.x[:, 1] = result[1] unknowns['gain'] = self.MBI.evaluate(self.x)[:, 0] def linearize(self, params, unknowns, resids): """ Calculate and save derivatives. (i.e., Jacobian) """ self.dg_daz = self.MBI.evaluate(self.x, 1)[:, 0] self.dg_del = self.MBI.evaluate(self.x, 2)[:, 0] def apply_linear(self, params, unknowns, dparams, dunknowns, dresids, mode): """ Matrix-vector product with the Jacobian. """ dgain = dresids['gain'] if mode == 'fwd': if 'azimuthGS' in dparams: dgain += self.dg_daz * dparams['azimuthGS'] if 'elevationGS' in dparams: dgain += self.dg_del * dparams['elevationGS'] else: if 'azimuthGS' in dparams: dparams['azimuthGS'] += self.dg_daz * dgain if 'elevationGS' in dparams: dparams['elevationGS'] += self.dg_del * dgain
class CommGainPatternComp(ExplicitComponent): """ Determines transmitter gain based on an external az-el map. """ # # def __init__(self, num_nodes, rawG_file=None): # super(CommGainPatternComp, self).__init__(num_nodes=num_nodes) # # if not rawG_file: # fpath = os.path.dirname(os.path.realpath(__file__)) # rawG_file = fpath + '/data/Comm/Gain.txt' # # rawGdata = np.genfromtxt(rawG_file) # rawG = (10 ** (rawGdata / 10.0)).reshape((361, 361), order='F') # # pi = np.pi # az = np.linspace(0, 2 * pi, 361) # el = np.linspace(0, 2 * pi, 361) # # self.MBI = MBI(rawG, [az, el], [15, 15], [4, 4]) # self.x = np.zeros((self.n, 2), order='F') def initialize(self): dir_path = os.path.dirname(os.path.realpath(__file__)) parent_path = os.path.abspath(os.path.join(dir_path, os.pardir)) rawG_file = os.path.join(parent_path, 'data/Comm/Gain.txt') self.options.declare('num_nodes', types=(int, )) self.options.declare('rawG_file', types=(str, ), default=rawG_file) def setup(self): nn = self.options['num_nodes'] rawGdata = np.genfromtxt(self.options['rawG_file']) rawG = (10**(rawGdata / 10.0)).reshape((361, 361), order='F') pi = np.pi az = np.linspace(0, 2 * pi, 361) el = np.linspace(0, 2 * pi, 361) self.MBI = MBI(rawG, [az, el], [15, 15], [4, 4]) self.MBI.seterr('raise') self.x = np.zeros((nn, 2), order='F') # Inputs self.add_input( 'azimuthGS', np.zeros(nn), units='rad', desc='Azimuth angle from satellite to ground station in ' 'Earth-fixed frame over time') self.add_input('elevationGS', np.zeros(nn), units='rad', desc='Elevation angle from satellite to ground station ' 'in Earth-fixed frame over time') # Outputs self.add_output('gain', np.zeros(nn), units=None, desc='Transmitter gain over time') row_col = np.arange(nn) self.declare_partials('gain', 'elevationGS', rows=row_col, cols=row_col) self.declare_partials('gain', 'azimuthGS', rows=row_col, cols=row_col) def compute(self, inputs, outputs): """ Calculate outputs. """ result = fixangles(self.options['num_nodes'], inputs['azimuthGS'], inputs['elevationGS']) self.x[:, 0] = result[0] self.x[:, 1] = result[1] outputs['gain'] = self.MBI.evaluate(self.x)[:, 0] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ partials['gain', 'azimuthGS'] = self.MBI.evaluate(self.x, 1)[:, 0] partials['gain', 'elevationGS'] = self.MBI.evaluate(self.x, 2)[:, 0]
class Power_CellVoltage(Component): """Compute the output voltage of the solar panels. """ def __init__(self, n, dat=None): super(Power_CellVoltage, self).__init__() self.n = n if dat is None: fpath = os.path.dirname(os.path.realpath(__file__)) dat = np.genfromtxt(fpath + '/data/Power/curve.dat') # Inputs self.add_param('LOS', np.zeros((n)), units='unitless', desc="Line of Sight over Time") self.add_param('temperature', np.zeros((5, n)), units="degK", desc="Temperature of solar cells over time") self.add_param('exposedArea', np.zeros((7, 12, n)), units="m**2", desc="Exposed area to sun for each solar cell over time") self.add_param('Isetpt', np.zeros((12, n)), units="A", desc="Currents of the solar panels") # Outputs self.add_output('V_sol', np.zeros((12, n)), units="V", desc="Output voltage of solar panel over time") nT, nA, nI = dat[:3] T = dat[3:3 + nT] A = dat[3 + nT:3 + nT + nA] I = dat[3 + nT + nA:3 + nT + nA + nI] V = dat[3 + nT + nA + nI:].reshape((nT, nA, nI), order='F') self.MBI = MBI(V, [T, A, I], [6, 6, 15], [3, 3, 3]) self.x = np.zeros((84 * self.n, 3), order='F') self.xV = self.x.reshape((self.n, 7, 12, 3), order='F') self.dV_dL = np.zeros((self.n, 12), order='F') self.dV_dT = np.zeros((self.n, 12, 5), order='F') self.dV_dA = np.zeros((self.n, 7, 12), order='F') self.dV_dI = np.zeros((self.n, 12), order='F') def setx(self, params): temperature = params['temperature'] LOS = params['LOS'] exposedArea = params['exposedArea'] Isetpt = params['Isetpt'] for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): self.xV[:, c, p, 0] = temperature[i, :] self.xV[:, c, p, 1] = LOS * exposedArea[c, p, :] self.xV[:, c, p, 2] = Isetpt[p, :] def solve_nonlinear(self, params, unknowns, resids): """ Calculate output. """ self.setx(params) self.raw = self.MBI.evaluate(self.x)[:, 0].reshape((self.n, 7, 12), order='F') unknowns['V_sol'] = np.zeros((12, self.n)) for c in range(7): unknowns['V_sol'] += self.raw[:, c, :].T def linearize(self, params, unknowns, resids): """ Calculate and save derivatives. (i.e., Jacobian) """ exposedArea = params['exposedArea'] LOS = params['LOS'] self.raw1 = self.MBI.evaluate(self.x, 1)[:, 0].reshape((self.n, 7, 12), order='F') self.raw2 = self.MBI.evaluate(self.x, 2)[:, 0].reshape((self.n, 7, 12), order='F') self.raw3 = self.MBI.evaluate(self.x, 3)[:, 0].reshape((self.n, 7, 12), order='F') self.dV_dL[:] = 0.0 self.dV_dT[:] = 0.0 self.dV_dA[:] = 0.0 self.dV_dI[:] = 0.0 for p in range(12): i = 4 if p < 4 else (p % 4) for c in range(7): self.dV_dL[:, p] += self.raw2[:, c, p] * exposedArea[c, p,:] self.dV_dT[:, p, i] += self.raw1[:, c, p] self.dV_dA[:, c, p] += self.raw2[:, c, p] * LOS self.dV_dI[:, p] += self.raw3[:, c, p] def apply_linear(self, params, unknowns, dparams, dunknowns, dresids, mode): """ Matrix-vector product with the Jacobian. """ dV_sol = dresids['V_sol'] if mode == 'fwd': if 'LOS' in dparams: dV_sol += self.dV_dL.T * dparams['LOS'] if 'temperature' in dparams: for p in range(12): i = 4 if p < 4 else (p % 4) dV_sol[p, :] += self.dV_dT[:, p, i] * dparams['temperature'][i,:] if 'Isetpt' in dparams: dV_sol += self.dV_dI.T * dparams['Isetpt'] if 'exposedArea' in dparams: for p in range(12): dV_sol[p, :] += \ np.sum(self.dV_dA[:,:, p] * dparams['exposedArea'][:, p,:].T, 1) else: for p in range(12): i = 4 if p < 4 else (p % 4) if 'LOS' in dparams: dparams['LOS'] += self.dV_dL[:, p] * dV_sol[p,:] if 'temperature' in dparams: dparams['temperature'][i,:] += self.dV_dT[:, p, i] * dV_sol[p,:] if 'Isetpt' in dparams: dparams['Isetpt'][p,:] += self.dV_dI[:, p] * dV_sol[p,:] if 'exposedArea' in dparams: dexposedArea = dparams['exposedArea'] for c in range(7): dexposedArea[c, p, :] += self.dV_dA[:, c, p] * dV_sol[p,:]
class Solar_ExposedArea(ExplicitComponent): """ Exposed area calculation for a given solar cell p: panel ID [0,11] c: cell ID [0,6] a: fin angle [0,90] z: azimuth [0,360] e: elevation [0,180] LOS: line of sight with the sun [0,1] """ def __init__(self, n, raw1_file=None, raw2_file=None): super(Solar_ExposedArea, self).__init__() self.n = n self.raw1_file = raw1_file self.raw2_file = raw2_file def setup(self): n = self.n raw1_file = self.raw1_file raw2_file = self.raw2_file fpath = os.path.dirname(os.path.realpath(__file__)) if not raw1_file: raw1_file = fpath + '/data/Solar/Area10.txt' if not raw2_file: raw2_file = fpath + '/data/Solar/Area_all.txt' raw1 = np.genfromtxt(raw1_file) raw2 = np.loadtxt(raw2_file) nc = self.nc = 7 self.np = 12 self.na = 10 self.nz = 73 self.ne = 37 angle = np.zeros(self.na) azimuth = np.zeros(self.nz) elevation = np.zeros(self.ne) index = 0 for i in range(self.na): angle[i] = raw1[index] index += 1 for i in range(self.nz): azimuth[i] = raw1[index] index += 1 index -= 1 azimuth[self.nz - 1] = 2.0 * np.pi for i in range(self.ne): elevation[i] = raw1[index] index += 1 angle[0] = 0.0 angle[-1] = np.pi / 2.0 azimuth[0] = 0.0 azimuth[-1] = 2 * np.pi elevation[0] = 0.0 elevation[-1] = np.pi counter = 0 data = np.zeros((self.na, self.nz, self.ne, self.np * self.nc)) flat_size = self.na * self.nz * self.ne for p in range(self.np): for c in range(nc): data[:, :, :, counter] = \ raw2[nc * p + c][119:119 + flat_size].reshape((self.na, self.nz, self.ne)) counter += 1 self.MBI = MBI(data, [angle, azimuth, elevation], [4, 10, 8], [4, 4, 4]) self.MBI.seterr('raise') self.x = np.zeros((self.n, 3)) self.Jfin = None self.Jaz = None self.Jel = None # Inputs self.add_input('finAngle', 0.0, units='rad', desc='Fin angle of solar panel') self.add_input( 'azimuth', np.zeros((n, )), units='rad', desc='Azimuth angle of the sun in the body-fixed frame over time') self.add_input( 'elevation', np.zeros((n, )), units='rad', desc='Elevation angle of the sun in the body-fixed frame over time' ) # Outputs self.add_output( 'exposedArea', np.zeros((n, self.nc, self.np)), desc='Exposed area to sun for each solar cell over time', units='m**2', lower=-5e-3, upper=1.834e-1) self.declare_partials('exposedArea', 'finAngle') nn = self.nc * self.np rows = np.tile(np.arange(nn), n) + np.repeat(nn * np.arange(n), nn) cols = np.tile(np.repeat(0, nn), n) + np.repeat(np.arange(n), nn) self.declare_partials('exposedArea', 'azimuth', rows=rows, cols=cols) self.declare_partials('exposedArea', 'elevation', rows=rows, cols=cols) def compute(self, inputs, outputs): """ Calculate outputs. """ self.setx(inputs) P = self.MBI.evaluate(self.x) outputs['exposedArea'] = P.reshape(self.n, self.nc, self.np, order='F') def setx(self, inputs): """ Sets our state array """ result = fixangles(self.n, inputs['azimuth'], inputs['elevation']) self.x[:, 0] = inputs['finAngle'] self.x[:, 1] = result[0] self.x[:, 2] = result[1] def compute_partials(self, inputs, partials): """ Calculate and save derivatives. (i.e., Jacobian) """ Jfin = self.MBI.evaluate(self.x, 1).reshape(self.n, self.nc, self.np, order='F') Jaz = self.MBI.evaluate(self.x, 2).reshape(self.n, self.nc, self.np, order='F') Jel = self.MBI.evaluate(self.x, 3).reshape(self.n, self.nc, self.np, order='F') partials['exposedArea', 'finAngle'] = Jfin.flatten() partials['exposedArea', 'azimuth'] = Jaz.flatten() partials['exposedArea', 'elevation'] = Jel.flatten()