def test_bogus(self): # now try some bogus expressions try: ex = ExprEvaluator('abcd.efg', self.top) ex.evaluate() except AttributeError, err: self.assertEqual(str(err), "can't evaluate expression 'abcd.efg': : object has no attribute 'abcd.efg'")
def test_reparse_on_scope_change(self): self.top.comp.x = 99.5 self.top.comp.y = -3.14 ex = ExprEvaluator('comp.x', self.top) self.assertEqual(99.5, ex.evaluate()) self.assertEqual(new_text(ex), "scope.get('comp.x')") ex.scope = self.top.a try: ex.set(0.5) except AttributeError as err: self.assertEqual(str(err), "a: object has no attribute 'comp.x'") else: self.fail("AttributeError expected") self.assertEqual(new_text(ex), "scope.get('comp.x')") self.assertEqual(99.5, ex.evaluate(self.top)) # set scope back to self.top self.assertEqual(new_text(ex), "scope.get('comp.x')") ex.text = 'comp.y' try: ex.evaluate(self.top.a) except AttributeError as err: self.assertEqual( str(err), "can't evaluate expression 'comp.y': a: 'A' object has no attribute 'comp'" ) else: self.fail("AttributeError expected") ex.scope = self.top ex.set(11.1) self.assertEqual(11.1, self.top.comp.y) self.assertEqual(new_text(ex), "scope.get('comp.y')")
def test_reparse_on_scope_change(self): self.top.comp.x = 99.5 self.top.comp.y = -3.14 ex = ExprEvaluator('comp.x', self.top) self.assertEqual(99.5, ex.evaluate()) self.assertEqual(new_text(ex), "scope.get('comp.x')") ex.scope = self.top.a try: ex.set(0.5) except AttributeError as err: self.assertEqual(str(err), "a: object has no attribute 'comp.x'") else: self.fail("AttributeError expected") self.assertEqual(new_text(ex), "scope.get('comp.x')") self.assertEqual(99.5, ex.evaluate(self.top)) # set scope back to self.top self.assertEqual(new_text(ex), "scope.get('comp.x')") ex.text = 'comp.y' try: ex.evaluate(self.top.a) except AttributeError as err: self.assertEqual(str(err), "can't evaluate expression 'comp.y':" " a: 'A' object has no attribute 'comp'") else: self.fail("AttributeError expected") ex.scope = self.top ex.set(11.1) self.assertEqual(11.1, self.top.comp.y) self.assertEqual(new_text(ex), "scope.get('comp.y')")
def test_no_scope(self): ex = ExprEvaluator('abs(-3)+int(2.3)+math.floor(5.4)') self.assertEqual(ex.evaluate(), 10.0) ex.text = 'comp.x' try: ex.evaluate() except Exception, err: self.assertEqual(str(err), "can't evaluate expression 'comp.x': expression has no scope")
def test_bogus(self): # now try some bogus expressions try: ex = ExprEvaluator('abcd.efg', self.top) ex.evaluate() except AttributeError, err: self.assertEqual(str(err), "can't evaluate expression 'abcd.efg':" " : 'Assembly' object has no attribute 'abcd'")
def test_bogus(self): # now try some bogus expressions try: ex = ExprEvaluator('abcd.efg', self.top) ex.evaluate() except AttributeError, err: self.assertEqual(str(err), "can't evaluate expression 'abcd.efg':" " : name 'abcd' is not defined")
def test_no_scope(self): ex = ExprEvaluator('abs(-3)+int(2.3)+math.floor(5.4)') self.assertEqual(ex.evaluate(), 10.0) ex.text = 'comp.x' try: ex.evaluate() except Exception, err: self.assertEqual(str(err), "can't evaluate expression 'comp.x':" " 'NoneType' object has no attribute 'get'")
def test_bogus(self): # now try some bogus expressions try: ex = ExprEvaluator('abcd.efg', self.top) ex.evaluate() except AttributeError, err: self.assertEqual( str(err), "can't evaluate expression 'abcd.efg':" " : name 'abcd' is not defined")
def test_slice(self): ex = ExprEvaluator('a1d[1::2]', self.top.a) self.assertTrue(all(numpy.array([2.,4.,6.]) == ex.evaluate())) ex.text = 'a1d[2:4]' self.assertTrue(all(numpy.array([3.,4.]) == ex.evaluate())) ex.text = 'a1d[2:]' self.assertTrue(all(numpy.array([3.,4.,5.,6.]) == ex.evaluate())) ex.text = 'a1d[::-1]' self.assertTrue(all(numpy.array([6.,5.,4.,3.,2.,1.]) == ex.evaluate())) ex.text = 'a1d[:2]' self.assertTrue(all(numpy.array([1.,2.]) == ex.evaluate()))
def test_slice(self): ex = ExprEvaluator('a1d[1::2]', self.top.a) self.assertTrue(all(array([2., 4., 6.]) == ex.evaluate())) ex.text = 'a1d[2:4]' self.assertTrue(all(array([3., 4.]) == ex.evaluate())) ex.text = 'a1d[2:]' self.assertTrue(all(array([3., 4., 5., 6.]) == ex.evaluate())) ex.text = 'a1d[::-1]' self.assertTrue(all(array([6., 5., 4., 3., 2., 1.]) == ex.evaluate())) ex.text = 'a1d[:2]' self.assertTrue(all(array([1., 2.]) == ex.evaluate()))
def test_no_scope(self): ex = ExprEvaluator('abs(-3)+int(2.3)+math.floor(5.4)') self.assertEqual(ex.evaluate(), 10.0) ex.text = 'comp.x' try: ex.evaluate() except Exception, err: self.assertEqual( str(err), "can't evaluate expression 'comp.x': expression has no scope")
class Constraint(object): """ Object that stores info for a single constraint. """ def __init__(self, lhs, comparator, rhs, scaler, adder, scope=None): self.lhs = ExprEvaluator(lhs, scope=scope) if not self.lhs.check_resolve(): raise ValueError("Constraint '%s' has an invalid left-hand-side." \ % ' '.join([lhs, comparator, rhs])) self.comparator = comparator self.rhs = ExprEvaluator(rhs, scope=scope) if not self.rhs.check_resolve(): raise ValueError("Constraint '%s' has an invalid right-hand-side." \ % ' '.join([lhs, comparator, rhs])) if not isinstance(scaler, float): raise ValueError("Scaler parameter should be a float") self.scaler = scaler if scaler <= 0.0: raise ValueError("Scaler parameter should be a float > 0") if not isinstance(adder, float): raise ValueError("Adder parameter should be a float") self.adder = adder def evaluate(self, scope): """Returns a tuple of the form (lhs, rhs, comparator, is_violated).""" lhs = (self.lhs.evaluate(scope) + self.adder)*self.scaler rhs = (self.rhs.evaluate(scope) + self.adder)*self.scaler return (lhs, rhs, self.comparator, not _ops[self.comparator](lhs, rhs)) def evaluate_gradient(self, scope, stepsize=1.0e-6, wrt=None): """Returns the gradient of the constraint eq/inep as a tuple of the form (lhs, rhs, comparator, is_violated).""" lhs = self.lhs.evaluate_gradient(scope=scope, stepsize=stepsize, wrt=wrt) for key, value in lhs.iteritems(): lhs[key] = (value + self.adder)*self.scaler rhs = self.rhs.evaluate_gradient(scope=scope, stepsize=stepsize, wrt=wrt) for key, value in rhs.iteritems(): rhs[key] = (value + self.adder)*self.scaler return (lhs, rhs, self.comparator, not _ops[self.comparator](lhs, rhs)) def get_referenced_compnames(self): return self.lhs.get_referenced_compnames().union(self.rhs.get_referenced_compnames()) def __str__(self): return ' '.join([self.lhs.text, self.comparator, self.rhs.text])
def test_ext_slice(self): #Convoluted mess to test all cases of 3 x 3 x 3 array #where inner arrays are 2D identity matrices #Should cover all cases for k in xrange(3): expr = 'ext1[{0}, :, :]'.format(k) expr = ExprEvaluator(expr, self.top.a) comp = (eye(3) == expr.evaluate()).all() self.assertTrue(comp) expr = 'ext1[:, {0}, :]'.format(k) expr = ExprEvaluator(expr, self.top.a) comp = (tile(roll(array([1., 0., 0.]), k), (3, 1)) == expr.evaluate()).all() self.assertTrue(comp) expr = 'ext1[:, :, {0}]'.format(k) expr = ExprEvaluator(expr, self.top.a) comp = (tile(roll(array([1., 0., 0.]), k), (3, 1)) == expr.evaluate()).all() self.assertTrue(comp) for j in xrange(3): expr = 'ext1[:, {0}, {1}]'.format(j, k) expr = ExprEvaluator(expr, self.top.a) if j == k: comp = all(array([1., 1., 1.]) == expr.evaluate()) self.assertTrue(comp) else: comp = all(array([0., 0., 0.]) == expr.evaluate()) self.assertTrue(comp) expr = 'ext1[{0}, :, {1}]'.format(j, k) expr = ExprEvaluator(expr, self.top.a) arr = array([1., 0., 0.]) comp = all(roll(arr, k) == expr.evaluate()) self.assertTrue(comp) expr = 'ext1[{0}, {1}, :]'.format(j, k) expr = ExprEvaluator(expr, self.top.a) arr = array([1., 0., 0.]) comp = all(roll(arr, k) == expr.evaluate()) self.assertTrue(comp) for i in xrange(3): expr = 'ext1[{0}, {1}, {2}]'.format(i, j, k) expr = ExprEvaluator(expr, self.top.a) if j == k: comp = all(array([1.]) == expr.evaluate()) self.assertTrue(comp) else: comp = all(array([0.]) == expr.evaluate()) self.assertTrue(comp)
def _create(self, target, low, high, scaler, adder, start, fd_step, key, scope): """ Create one Parameter or ArrayParameter. """ try: expreval = ExprEvaluator(target, scope) except Exception as err: raise err.__class__("Can't add parameter: %s" % err) if not expreval.is_valid_assignee(): raise ValueError("Can't add parameter: '%s' is not a" " valid parameter expression" % expreval.text) try: val = expreval.evaluate() except Exception as err: val = None # Let Parameter code sort out why. name = key[0] if isinstance(key, tuple) else key if isinstance(val, ndarray): return ArrayParameter(target, low=low, high=high, scaler=scaler, adder=adder, start=start, fd_step=fd_step, name=name, scope=scope, _expreval=expreval, _val=val, _allowed_types=self._allowed_types) else: return Parameter(target, low=low, high=high, scaler=scaler, adder=adder, start=start, fd_step=fd_step, name=name, scope=scope, _expreval=expreval, _val=val, _allowed_types=self._allowed_types)
class Constraint(object): """ Object that stores info for a single constraint. """ def __init__(self, lhs, comparator, rhs, scaler, adder, scope=None): self.lhs = ExprEvaluator(lhs, scope=scope) if not self.lhs.check_resolve(): raise ValueError("Constraint '%s' has an invalid left-hand-side." \ % ' '.join([lhs, comparator, rhs])) self.comparator = comparator self.rhs = ExprEvaluator(rhs, scope=scope) if not self.rhs.check_resolve(): raise ValueError("Constraint '%s' has an invalid right-hand-side." \ % ' '.join([lhs, comparator, rhs])) if not isinstance(scaler, float): raise ValueError("Scaler parameter should be a float") self.scaler = scaler if scaler <= 0.0: raise ValueError("Scaler parameter should be a float > 0") if not isinstance(adder, float): raise ValueError("Adder parameter should be a float") self.adder = adder def evaluate(self, scope): """Returns a tuple of the form (lhs, rhs, comparator, is_violated).""" lhs = (self.lhs.evaluate(scope) + self.adder) * self.scaler rhs = (self.rhs.evaluate(scope) + self.adder) * self.scaler return (lhs, rhs, self.comparator, not _ops[self.comparator](lhs, rhs)) def get_referenced_compnames(self): return self.lhs.get_referenced_compnames().union( self.rhs.get_referenced_compnames()) def __str__(self): return ' '.join([self.lhs.text, self.comparator, self.rhs.text])
def test_property(self): ex = ExprEvaluator('some_prop', self.top.a) self.assertEqual(ex.evaluate(), 7)
class SimEconomy(Driver): """ Simulation of vehicle performance over a given velocity profile. Such a simulation can be used to mimic the EPA city and highway driving tests. This is a specialized simulation driver whose workflow should consist of a Vehicle assembly, and whose connections are as follows: Connections Parameters: [ velocity (Float), throttle (Float), current_gear (Enum) ] Objectives: [ acceleration (Float), fuel burn (Float), overspeed (Bool), underspeed (Bool) ] Connection Inputs velocity_str: str Variable location for vehicle velocity. throttle_str: str Variable location for vehicle throttle position. gear_str: str Variable location for vehicle gear position. acceleration_str: str Variable location for vehicle acceleration. fuel_burn_str: str Variable location for vehicle fuel burn. overspeed_str: str Variable location for vehicle overspeed. underspeed_str: str Variable location for vehicle underspeed. Simulation Inputs profilename: str Name of the file that contains profile (csv format) end_speed: float Ending speed for the simulation (default 60 mph) timestep: float Simulation time step (default .01) Outputs fuel_economy: float Fuel economy over the simulated profile. """ velocity_str = Str(iotype='in', desc='Location of vehicle input: velocity.') throttle_str = Str(iotype='in', desc='Location of vehicle input: throttle.') gear_str = Str(iotype='in', desc='Location of vehicle input: current_gear.') acceleration_str = Str(iotype='in', desc='Location of vehicle output: acceleration.') fuel_burn_str = Str(iotype='in', desc='Location of vehicle output: fuel_burn.') overspeed_str = Str(iotype='in', desc='Location of vehicle output: overspeed.') underspeed_str = Str(iotype='in', desc='Location of vehicle output: underspeed.') profilename = Str('', iotype='in', \ desc='Name of the file that contains profile (csv)') # These can be used to adjust driving style. throttle_min = Float(.07, iotype='in', desc='Minimum throttle position') throttle_max = Float(1.0, iotype='in', desc='Maximum throttle position') shiftpoint1 = Float(10.0, iotype='in', \ desc='Always in first gear below this speed') tolerance = Float(0.01, iotype='in', desc='Convergence tolerance for Bisection solution') fuel_economy = Float(0.0, iotype='out', units='s', desc='Simulated fuel economy over profile') def __init__(self, *args, **kwargs): super(SimEconomy, self).__init__(*args, **kwargs) self._velocity_str_expr = None self._throttle_str_expr = None self._gear_str_expr = None self._acceleration_str_expr = None self._fuel_burn_str_expr = None self._overspeed_str_expr = None self._underspeed_str_expr = None def _velocity_str_changed(self, oldval, newval): self._velocity_str_expr = ExprEvaluator(newval, scope=self.parent) def _throttle_str_changed(self, oldval, newval): self._throttle_str_expr = ExprEvaluator(newval, scope=self.parent) def _gear_str_changed(self, oldval, newval): self._gear_str_expr = ExprEvaluator(newval, scope=self.parent) def _acceleration_str_changed(self, oldval, newval): self._acceleration_str_expr = ExprEvaluator(newval, scope=self.parent) def _fuel_burn_str_changed(self, oldval, newval): self._fuel_burn_str_expr = ExprEvaluator(newval, scope=self.parent) def _overspeed_str_changed(self, oldval, newval): self._overspeed_str_expr = ExprEvaluator(newval, scope=self.parent) def _underspeed_str_changed(self, oldval, newval): self._underspeed_str_expr = ExprEvaluator(newval, scope=self.parent) def execute(self): """ Simulate the vehicle over a velocity profile.""" # Set initial throttle, gear, and velocity throttle = 1.0 gear = 1 time1 = 0.0 velocity1 = 0.0 profile_stream = resource_stream('openmdao.examples.enginedesign', self.profilename) profile_reader = reader(profile_stream, delimiter=',') distance = 0.0 fuelburn = 0.0 self._gear_str_expr.set(gear) for row in profile_reader: time2 = float(row[0]) velocity2 = float(row[1]) converged = 0 command_accel = (velocity2 - velocity1) / (time2 - time1) #------------------------------------------------------------ # Choose the correct Gear #------------------------------------------------------------ # First, if speed is less than 10 mph, put it in first gear. # Note: some funky gear ratios might not like this. # So, it's a hack for now. if velocity1 < self.shiftpoint1: gear = 1 self._gear_str_expr.set(gear) # Find out min and max accel in current gear. throttle = self.throttle_min self._velocity_str_expr.set(velocity1) self._throttle_str_expr.set(throttle) gear = self._findgear(velocity1, throttle, gear) acceleration = self._acceleration_str_expr.evaluate(self.parent) accel_min = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') # Upshift if commanded accel is less than closed-throttle accel # The net effect of this will often be a shift to a higher gear # when the vehicle stops accelerating, which is reasonable. # Note, this isn't a While loop, because we don't want to shift # to 5th every time we slow down. if command_accel < accel_min and gear < 5 and \ velocity1 > self.shiftpoint1: gear += 1 self._gear_str_expr.set(gear) gear = self._findgear(velocity1, throttle, gear) acceleration = self._acceleration_str_expr.evaluate( self.parent) accel_min = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') throttle = self.throttle_max self._throttle_str_expr.set(throttle) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate(self.parent) accel_max = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') # Downshift if commanded accel > wide-open-throttle accel while command_accel > accel_max and gear > 1: gear -= 1 self._gear_str_expr.set(gear) gear = self._findgear(velocity1, throttle, gear) acceleration = self._acceleration_str_expr.evaluate( self.parent) accel_max = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') # If engine cannot accelerate quickly enough to match profile, # then raise exception if command_accel > accel_max: self.raise_exception("Vehicle is unable to achieve " \ "acceleration required to match EPA driving profile.", RuntimeError) #------------------------------------------------------------ # Bisection solution to find correct Throttle position #------------------------------------------------------------ # Deceleration at closed throttle throttle = self.throttle_min self._throttle_str_expr.set(throttle) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate(self.parent) if command_accel >= accel_min: min_acc = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') max_acc = accel_max min_throttle = self.throttle_min max_throttle = self.throttle_max new_throttle = .5 * (min_throttle + max_throttle) # Numerical solution to find throttle that matches accel while not converged: throttle = new_throttle self._throttle_str_expr.set(throttle) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate( self.parent) new_acc = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') if abs(command_accel - new_acc) < self.tolerance: converged = 1 else: if new_acc < command_accel: min_throttle = new_throttle min_acc = new_acc step = (command_accel - min_acc) / (max_acc - new_acc) new_throttle = min_throttle + \ step*(max_throttle-min_throttle) else: max_throttle = new_throttle step = (command_accel - min_acc) / (new_acc - min_acc) new_throttle = min_throttle + \ step*(max_throttle-min_throttle) max_acc = new_acc distance += .5 * (velocity2 + velocity1) * (time2 - time1) burn_rate = self._fuel_burn_str_expr.evaluate(self.parent) fuelburn += burn_rate * (time2 - time1) velocity1 = velocity2 time1 = time2 #print "T = %f, V = %f, Acc = %f" % (time1, velocity1, #command_accel) #print gear, accel_min, accel_max # Convert liter to gallon and sec/hr to hr/hr distance = convert_units(distance, 'mi*s/h', 'mi') fuelburn = convert_units(fuelburn, 'L', 'galUS') self.fuel_economy = distance / fuelburn def _findgear(self, velocity, throttle, gear): """ Finds the nearest gear in the appropriate range for the currently commanded vehicle state (throttle, velocity). This is intended to be called recursively. """ self.run_iteration() overspeed = self._overspeed_str_expr.evaluate(self.parent) underspeed = self._underspeed_str_expr.evaluate(self.parent) if overspeed: gear += 1 if gear > 4: self.raise_exception("Transmission gearing cannot " \ "achieve acceleration and speed required by EPA " \ "test.", RuntimeError) elif underspeed: gear -= 1 # Note, no check needed for low gearing -- we allow underspeed # while in first gear. else: return gear self._gear_str_expr.set(gear) gear = self._findgear(velocity, throttle, gear) return gear
class SimAcceleration(Driver): """ Simulation of vehicle acceleration performance. This is a specialized simulation driver whose workflow should consist of a Vehicle assembly, and whose connections are as follows: Connection Inputs velocity_str: str Variable location for vehicle velocity. throttle_str: str Variable location for vehicle throttle position. gear_str: str Variable location for vehicle gear position. acceleration_str: str Variable location for vehicle acceleration. overspeed_str: str Variable location for vehicle overspeed. Simulation Inputs end_speed: float Ending speed for the simulation (default 60 mph) timestep: float Simulation time step (default .01) Outputs accel_time: float Time to perform the acceleration test. """ velocity_str = Str(iotype='in', desc='Location of vehicle input: velocity.') throttle_str = Str(iotype='in', desc='Location of vehicle input: throttle.') gear_str = Str(iotype='in', desc='Location of vehicle input: current_gear.') acceleration_str = Str(iotype='in', desc='Location of vehicle output: acceleration.') overspeed_str = Str(iotype='in', desc='Location of vehicle output: overspeed.') end_speed = Float(60.0, iotype='in', units='mi/h', desc='Simulation final speed') timestep = Float(0.1, iotype='in', units='s', desc='Simulation time step size') accel_time = Float(0.0, iotype='out', units='s', desc = 'Acceleration time') def __init__(self): super(SimAcceleration, self).__init__() self._velocity_str_expr = None self._throttle_str_expr = None self._gear_str_expr = None self._acceleration_str_expr = None self._overspeed_str_expr = None def _velocity_str_changed(self, oldval, newval): self._velocity_str_expr = ExprEvaluator(newval, scope=self.parent) def _throttle_str_changed(self, oldval, newval): self._throttle_str_expr = ExprEvaluator(newval, scope=self.parent) def _gear_str_changed(self, oldval, newval): self._gear_str_expr = ExprEvaluator(newval, scope=self.parent) def _acceleration_str_changed(self, oldval, newval): self._acceleration_str_expr = ExprEvaluator(newval, scope=self.parent) def _overspeed_str_changed(self, oldval, newval): self._overspeed_str_expr = ExprEvaluator(newval, scope=self.parent) def execute(self): """ Simulate the vehicle model at full throttle.""" # Set initial throttle, gear, and velocity time = 0.0 velocity = 0.0 throttle = 1.0 gear = 1 while velocity < self.end_speed: self._velocity_str_expr.set(velocity) self._throttle_str_expr.set(throttle) self._gear_str_expr.set(gear) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate(self.parent) overspeed = self._overspeed_str_expr.evaluate(self.parent) # If the next gear can produce more torque, let's shift. if gear < 5: self._gear_str_expr.set(gear+1) self.run_iteration() acceleration2 = self._acceleration_str_expr.evaluate(self.parent) if acceleration2 > acceleration: gear += 1 acceleration = acceleration2 overspeed = self._overspeed_str_expr.evaluate(self.parent) # If RPM goes over MAX RPM, shift gears # (i.e.: shift at redline) if overspeed: gear += 1 self._gear_str_expr.set(gear) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate(self.parent) overspeed = self._overspeed_str_expr.evaluate(self.parent) if overspeed: self.raise_exception("Gearing problem in Accel test.", RuntimeError) acceleration = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') if acceleration <= 0.0: self.raise_exception("Vehicle could not reach maximum speed "+\ "in Acceleration test.", RuntimeError) velocity += (acceleration*self.timestep) time += self.timestep self.accel_time = time
def test_set_evaluate(self): ex = ExprEvaluator('comp.x', self.top) self.assertEqual(3.14, ex.evaluate()) ex.set(75.4) self.assertEqual(75.4, self.top.comp.x) self.top.comp.contlist = [A(), A(), A()] self.top.comp.contlist[1].a1d = [4] * 5 ex = ExprEvaluator('comp.contlist[1].a1d[3]', self.top) self.assertEqual(ex.evaluate(), 4) ex.set(123) self.assertEqual(ex.evaluate(), 123) ex = ExprEvaluator("comp.contlist[1].some_funct(3,5,'sub')", self.top) self.assertEqual(ex.evaluate(), -2) ex = ExprEvaluator("comp.get_cont(1).some_funct(3,5,'add')", self.top) self.assertEqual(ex.evaluate(), 8) ex = ExprEvaluator("comp.get_cont(1).a1d[2]", self.top) self.assertEqual(ex.evaluate(), 4) ex = ExprEvaluator("a2d[1][0]", self.top.a) self.assertEqual(ex.evaluate(), 2.) ex.set(7.) self.assertEqual(self.top.a.a2d[1][0], 7.) ex = ExprEvaluator("a2d[1,0]", self.top.a) self.assertEqual(ex.evaluate(), 7.) ex.set(11.) self.assertEqual(self.top.a.a2d[1][0], 11.) ex = ExprEvaluator("a2d[1]", self.top.a) self.assertTrue(all(ex.evaluate() == array([11., 3.]))) ex.set([0.1, 0.2]) self.assertTrue(all(self.top.a.a2d[1] == array([0.1, 0.2]))) self.top.comp.cont = A() ex = ExprEvaluator("comp.cont.a2d[1][0]", self.top) self.assertEqual(ex.evaluate(), 2.) ex.set(7.) self.assertEqual(self.top.comp.cont.a2d[1][0], 7.) ex = ExprEvaluator("comp.cont.a2d[1,0]", self.top) self.assertEqual(ex.evaluate(), 7.) ex.set(11.) self.assertEqual(self.top.comp.cont.a2d[1][0], 11.) # try a numpy function try: import numpy except ImportError: pass else: ex = ExprEvaluator("numpy.eye(2)", self.top.a) val = ex.evaluate() self.assertTrue((val == numpy.eye(2)).all()) ex = ExprEvaluator("comp.get_cont(1).a1d", self.top) self.assertEqual(list(ex.evaluate()), [4, 4, 4, 123, 4]) ex = ExprEvaluator("comp.get_attrib('get_cont')(1).a1d", self.top) self.assertEqual(list(ex.evaluate()), [4, 4, 4, 123, 4])
def __init__(self, target, parent, high=None, low=None, scaler=None, adder=None, start=None, fd_step=None, scope=None, name=None): self._metadata = None if scaler is None and adder is None: self._transform = self._do_nothing self._untransform = self._do_nothing else: if scaler is None: scaler = 1.0 else: try: scaler = float(scaler) except (TypeError, ValueError): msg = "Bad value given for parameter's 'scaler' attribute." parent.raise_exception(msg, ValueError) if adder is None: adder = 0.0 else: try: adder = float(adder) except (TypeError, ValueError): msg = "Bad value given for parameter's 'adder' attribute." parent.raise_exception(msg, ValueError) self.low = low self.high = high self.start = start self.scaler = scaler self.adder = adder self.fd_step = fd_step if name is not None: self.name = name else: self.name = target try: expreval = ExprEvaluator(target, scope) except Exception as err: parent.raise_exception("Can't add parameter: %s" % str(err), type(err)) if not expreval.is_valid_assignee(): parent.raise_exception("Can't add parameter: '%s' is not a valid parameter expression" % expreval.text, ValueError) self._expreval = expreval try: # metadata is in the form (varname, metadata), so use [1] to get # the actual metadata dict metadata = self.get_metadata()[1] except AttributeError: parent.raise_exception("Can't add parameter '%s' because it doesn't exist." % target, AttributeError) if 'iotype' in metadata and metadata['iotype'] == 'out': parent.raise_exception("Can't add parameter '%s' because '%s' is an output." % (target, target), RuntimeError) try: # So, our traits might not have a vartypename? self.vartypename = metadata['vartypename'] except KeyError: self.vartypename = None try: val = expreval.evaluate() except Exception as err: parent.raise_exception("Can't add parameter because I can't evaluate '%s'." % target, ValueError) self.valtypename = type(val).__name__ if self.vartypename == 'Enum': return # it's an Enum, so no need to set high or low if not isinstance(val, real_types) and not isinstance(val, int_types): parent.raise_exception("The value of parameter '%s' must be a real or integral type, but its type is '%s'." % (target,type(val).__name__), ValueError) meta_low = metadata.get('low') # this will be None if 'low' isn't there if meta_low is not None: if low is None: self.low = self._untransform(meta_low) elif low < self._untransform(meta_low): parent.raise_exception("Trying to add parameter '%s', " "but the lower limit supplied (%s) exceeds the " "built-in lower limit (%s)." % (target, low, meta_low), ValueError) else: if low is None: parent.raise_exception("Trying to add parameter '%s', " "but no lower limit was found and no " "'low' argument was given. One or the " "other must be specified." % target,ValueError) meta_high = metadata.get('high') # this will be None if 'low' isn't there if meta_high is not None: if high is None: self.high = self._untransform(meta_high) elif high > self._untransform(meta_high): parent.raise_exception("Trying to add parameter '%s', " "but the upper limit supplied (%s) exceeds the " "built-in upper limit (%s)." % (target, high, meta_high), ValueError) else: if high is None: parent.raise_exception("Trying to add parameter '%s', " "but no upper limit was found and no " "'high' argument was given. One or the " "other must be specified." % target,ValueError) if self.low > self.high: parent.raise_exception("Parameter '%s' has a lower bound (%s) that exceeds its upper bound (%s)" % (target, self.low, self.high), ValueError)
class SimEconomy(Driver): """ Simulation of vehicle performance over a given velocity profile. Such a simulation can be used to mimic the EPA city and highway driving tests. This is a specialized simulation driver whose workflow should consist of a Vehicle assembly, and whose connections are as follows: Connections Parameters: [ velocity (Float), throttle (Float), current_gear (Enum) ] Objectives: [ acceleration (Float), fuel burn (Float), overspeed (Bool), underspeed (Bool) ] Connection Inputs velocity_str: str Variable location for vehicle velocity. throttle_str: str Variable location for vehicle throttle position. gear_str: str Variable location for vehicle gear position. acceleration_str: str Variable location for vehicle acceleration. fuel_burn_str: str Variable location for vehicle fuel burn. overspeed_str: str Variable location for vehicle overspeed. underspeed_str: str Variable location for vehicle underspeed. Simulation Inputs profilename: str Name of the file that contains profile (csv format) end_speed: float Ending speed for the simulation (default 60 mph) timestep: float Simulation time step (default .01) Outputs fuel_economy: float Fuel economy over the simulated profile. """ velocity_str = Str(iotype='in', desc='Location of vehicle input: velocity.') throttle_str = Str(iotype='in', desc='Location of vehicle input: throttle.') gear_str = Str(iotype='in', desc='Location of vehicle input: current_gear.') acceleration_str = Str(iotype='in', desc='Location of vehicle output: acceleration.') fuel_burn_str = Str(iotype='in', desc='Location of vehicle output: fuel_burn.') overspeed_str = Str(iotype='in', desc='Location of vehicle output: overspeed.') underspeed_str = Str(iotype='in', desc='Location of vehicle output: underspeed.') profilename = Str('', iotype='in', \ desc='Name of the file that contains profile (csv)') # These can be used to adjust driving style. throttle_min = Float(.07, iotype='in', desc='Minimum throttle position') throttle_max = Float(1.0, iotype='in', desc='Maximum throttle position') shiftpoint1 = Float(10.0, iotype='in', \ desc='Always in first gear below this speed') tolerance = Float(0.01, iotype='in', desc='Convergence tolerance for Bisection solution') fuel_economy = Float(0.0, iotype='out', units='s', desc = 'Simulated fuel economy over profile') def __init__(self, *args, **kwargs): super(SimEconomy, self).__init__(*args, **kwargs) self._velocity_str_expr = None self._throttle_str_expr = None self._gear_str_expr = None self._acceleration_str_expr = None self._fuel_burn_str_expr = None self._overspeed_str_expr = None self._underspeed_str_expr = None def _velocity_str_changed(self, oldval, newval): self._velocity_str_expr = ExprEvaluator(newval, scope=self.parent) def _throttle_str_changed(self, oldval, newval): self._throttle_str_expr = ExprEvaluator(newval, scope=self.parent) def _gear_str_changed(self, oldval, newval): self._gear_str_expr = ExprEvaluator(newval, scope=self.parent) def _acceleration_str_changed(self, oldval, newval): self._acceleration_str_expr = ExprEvaluator(newval, scope=self.parent) def _fuel_burn_str_changed(self, oldval, newval): self._fuel_burn_str_expr = ExprEvaluator(newval, scope=self.parent) def _overspeed_str_changed(self, oldval, newval): self._overspeed_str_expr = ExprEvaluator(newval, scope=self.parent) def _underspeed_str_changed(self, oldval, newval): self._underspeed_str_expr = ExprEvaluator(newval, scope=self.parent) def execute(self): """ Simulate the vehicle over a velocity profile.""" # Set initial throttle, gear, and velocity throttle = 1.0 gear = 1 time1 = 0.0 velocity1 = 0.0 profile_stream = resource_stream('openmdao.examples.enginedesign', self.profilename) profile_reader = reader(profile_stream, delimiter=',') distance = 0.0 fuelburn = 0.0 self._gear_str_expr.set(gear) for row in profile_reader: time2 = float(row[0]) velocity2 = float(row[1]) converged = 0 command_accel = (velocity2-velocity1)/(time2-time1) #------------------------------------------------------------ # Choose the correct Gear #------------------------------------------------------------ # First, if speed is less than 10 mph, put it in first gear. # Note: some funky gear ratios might not like this. # So, it's a hack for now. if velocity1 < self.shiftpoint1: gear = 1 self._gear_str_expr.set(gear) # Find out min and max accel in current gear. throttle = self.throttle_min self._velocity_str_expr.set(velocity1) self._throttle_str_expr.set(throttle) gear = self._findgear(velocity1, throttle, gear) acceleration = self._acceleration_str_expr.evaluate(self.parent) accel_min = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') # Upshift if commanded accel is less than closed-throttle accel # The net effect of this will often be a shift to a higher gear # when the vehicle stops accelerating, which is reasonable. # Note, this isn't a While loop, because we don't want to shift # to 5th every time we slow down. if command_accel < accel_min and gear < 5 and \ velocity1 > self.shiftpoint1: gear += 1 self._gear_str_expr.set(gear) gear = self._findgear(velocity1, throttle, gear) acceleration = self._acceleration_str_expr.evaluate(self.parent) accel_min = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') throttle = self.throttle_max self._throttle_str_expr.set(throttle) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate(self.parent) accel_max = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') # Downshift if commanded accel > wide-open-throttle accel while command_accel > accel_max and gear > 1: gear -= 1 self._gear_str_expr.set(gear) gear = self._findgear(velocity1, throttle, gear) acceleration = self._acceleration_str_expr.evaluate(self.parent) accel_max = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') # If engine cannot accelerate quickly enough to match profile, # then raise exception if command_accel > accel_max: self.raise_exception("Vehicle is unable to achieve " \ "acceleration required to match EPA driving profile.", RuntimeError) #------------------------------------------------------------ # Bisection solution to find correct Throttle position #------------------------------------------------------------ # Deceleration at closed throttle throttle = self.throttle_min self._throttle_str_expr.set(throttle) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate(self.parent) if command_accel >= accel_min: min_acc = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') max_acc = accel_max min_throttle = self.throttle_min max_throttle = self.throttle_max new_throttle = .5*(min_throttle + max_throttle) # Numerical solution to find throttle that matches accel while not converged: throttle = new_throttle self._throttle_str_expr.set(throttle) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate(self.parent) new_acc = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') if abs(command_accel-new_acc) < self.tolerance: converged = 1 else: if new_acc < command_accel: min_throttle = new_throttle min_acc = new_acc step = (command_accel-min_acc)/(max_acc-new_acc) new_throttle = min_throttle + \ step*(max_throttle-min_throttle) else: max_throttle = new_throttle step = (command_accel-min_acc)/(new_acc-min_acc) new_throttle = min_throttle + \ step*(max_throttle-min_throttle) max_acc = new_acc distance += .5*(velocity2+velocity1)*(time2-time1) burn_rate = self._fuel_burn_str_expr.evaluate(self.parent) fuelburn += burn_rate*(time2-time1) velocity1 = velocity2 time1 = time2 #print "T = %f, V = %f, Acc = %f" % (time1, velocity1, #command_accel) #print gear, accel_min, accel_max # Convert liter to gallon and sec/hr to hr/hr distance = convert_units(distance, 'mi*s/h', 'mi') fuelburn = convert_units(fuelburn, 'L', 'galUS') self.fuel_economy = distance/fuelburn def _findgear(self, velocity, throttle, gear): """ Finds the nearest gear in the appropriate range for the currently commanded vehicle state (throttle, velocity). This is intended to be called recursively. """ self.run_iteration() overspeed = self._overspeed_str_expr.evaluate(self.parent) underspeed = self._underspeed_str_expr.evaluate(self.parent) if overspeed: gear += 1 if gear > 4: self.raise_exception("Transmission gearing cannot " \ "achieve acceleration and speed required by EPA " \ "test.", RuntimeError) elif underspeed: gear -= 1 # Note, no check needed for low gearing -- we allow underspeed # while in first gear. else: return gear self._gear_str_expr.set(gear) gear = self._findgear(velocity, throttle, gear) return gear
class Constraint2Sided(Constraint): """ Object that stores info for a double-sided constraint. """ def __init__(self, lhs, center, rhs, comparator, scope): self.lhs = ExprEvaluator(lhs, scope=scope) unresolved_vars = self.lhs.get_unresolved() if unresolved_vars: msg = "Left hand side of constraint '{0}' has invalid variables {1}" expression = ' '.join((lhs, comparator, center, comparator, rhs)) raise ExprEvaluator._invalid_expression_error(unresolved_vars, expr=expression, msg=msg) self.center = ExprEvaluator(center, scope=scope) unresolved_vars = self.center.get_unresolved() if unresolved_vars: msg = "Center of constraint '{0}' has invalid variables {1}" expression = ' '.join((lhs, comparator, center, comparator, rhs)) raise ExprEvaluator._invalid_expression_error(unresolved_vars, expr=expression, msg=msg) self.rhs = ExprEvaluator(rhs, scope=scope) unresolved_vars = self.rhs.get_unresolved() if unresolved_vars: msg = "Right hand side of constraint '{0}' has invalid variables {1}" expression = ' '.join((lhs, comparator, center, comparator, rhs)) raise ExprEvaluator._invalid_expression_error(unresolved_vars, expr=expression, msg=msg) self.comparator = comparator self.pcomp_name = None self._size = None # Linear flag: constraints are nonlinear by default self.linear = False self.low = self.lhs.evaluate() self.high = self.rhs.evaluate() def activate(self, driver): """Make this constraint active by creating the appropriate connections in the dependency graph. """ if self.pcomp_name is None: scope = self.lhs.scope refs = list(self.center.ordered_refs()) pseudo_class = PseudoComponent # look for a<var1<b if len(refs) == 1 and self.center.text == refs[0]: pseudo_class = SimpleEQ0PComp pseudo = pseudo_class(scope, self.center, pseudo_type='constraint', subtype='inequality', exprobject=self) self.pcomp_name = pseudo.name scope.add(pseudo.name, pseudo) getattr(scope, pseudo.name).make_connections(scope, driver) def _combined_expr(self): """Only need the center expression """ return self.center def copy(self): """ Returns a copy of our self. """ return Constraint2Sided(str(self.lhs), str(self.center), str(self.rhs), self.comparator, scope=self.lhs.scope) def get_referenced_compnames(self): """Returns a set of names of each component referenced by this constraint. """ return self.center.get_referenced_compnames() def get_referenced_varpaths(self, copy=True, refs=False): """Returns a set of names of each component referenced by this constraint. """ return self.center.get_referenced_varpaths(copy=copy, refs=refs) def __str__(self): return ' '.join( (str(self.lhs), str(self.center), str(self.rhs), self.comparator)) def __eq__(self, other): if not isinstance(other, Constraint2Sided): return False return (self.lhs, self.center, self.comparator, self.rhs) == \ (other.lhs, self.center, other.comparator, other.rhs)
class Constraint2Sided(Constraint): """ Object that stores info for a double-sided constraint. """ def __init__(self, lhs, center, rhs, comparator, scope, jacs=None): self.lhs = ExprEvaluator(lhs, scope=scope) unresolved_vars = self.lhs.get_unresolved() self._pseudo = None self.pcomp_name = None if unresolved_vars: msg = "Left hand side of constraint '{0}' has invalid variables {1}" expression = ' '.join((lhs, comparator, center, comparator, rhs)) raise ExprEvaluator._invalid_expression_error(unresolved_vars, expr=expression, msg=msg) self.center = ExprEvaluator(center, scope=scope) unresolved_vars = self.center.get_unresolved() if unresolved_vars: msg = "Center of constraint '{0}' has invalid variables {1}" expression = ' '.join((lhs, comparator, center, comparator, rhs)) raise ExprEvaluator._invalid_expression_error(unresolved_vars, expr=expression, msg=msg) self.rhs = ExprEvaluator(rhs, scope=scope) unresolved_vars = self.rhs.get_unresolved() if unresolved_vars: msg = "Right hand side of constraint '{0}' has invalid variables {1}" expression = ' '.join((lhs, comparator, center, comparator, rhs)) raise ExprEvaluator._invalid_expression_error(unresolved_vars, expr=expression, msg=msg) self.comparator = comparator self._size = None # Linear flag: constraints are nonlinear by default self.linear = False self.low = self.lhs.evaluate() self.high = self.rhs.evaluate() # User-defined jacobian function self.jacs = jacs self._create_pseudo() def _create_pseudo(self): """Create our pseudo component.""" scope = self.lhs.scope refs = list(self.center.ordered_refs()) pseudo_class = PseudoComponent # look for a<var1<b if len(refs) == 1 and self.center.text == refs[0]: pseudo_class = SimpleEQ0PComp self._pseudo = pseudo_class(scope, self.center, pseudo_type='constraint', subtype='inequality', exprobject=self) self.pcomp_name = self._pseudo.name def _combined_expr(self): """Only need the center expression """ return self.center def copy(self): """ Returns a copy of our self. """ return Constraint2Sided(str(self.lhs), str(self.center), str(self.rhs), self.comparator, scope=self.lhs.scope, jacs=self.jacs) def get_referenced_compnames(self): """Returns a set of names of each component referenced by this constraint. """ return self.center.get_referenced_compnames() def get_referenced_varpaths(self, copy=True, refs=False): """Returns a set of names of each component referenced by this constraint. """ return self.center.get_referenced_varpaths(copy=copy, refs=refs) def name_changed(self, old, new): """Update expressions if necessary when an object is renamed.""" self.rhs.name_changed(old, new) self.lhs.name_changed(old, new) self.center.name_changed(old, new) def __str__(self): return ' '.join((str(self.lhs), str(self.center), str(self.rhs), self.comparator)) def __eq__(self, other): if not isinstance(other, Constraint2Sided): return False return (self.lhs, self.center, self.comparator, self.rhs) == \ (other.lhs, self.center, other.comparator, other.rhs)
def __init__(self, target, parent, high=None, low=None, scaler=None, adder=None, fd_step=None, scope=None): self._metadata = None if scaler is None and adder is None: self._transform = self._do_nothing self._untransform = self._do_nothing else: if scaler is None: scaler = 1.0 else: try: scaler = float(scaler) except TypeError: parent.raise_exception("bad scaler", TypeError) if adder is None: adder = 0.0 else: try: adder = float(adder) except TypeError: parent.raise_exception("bad adder", TypeError) self.low = low self.high = high self.scaler = scaler self.adder = adder self.fd_step = fd_step try: expreval = ExprEvaluator(target, scope) except Exception as err: parent.raise_exception("Can't add parameter: %s" % str(err), type(err)) if not expreval.is_valid_assignee(): parent.raise_exception( "Can't add parameter: '%s' is not a valid parameter expression" % expreval.text, ValueError ) self._expreval = expreval try: # metadata is in the form [(varname, metadata)], so use [0][1] to get # the actual metadata dict (since we're a Parameter we'll only be # referencing one variable. metadata = self.get_metadata()[0][1] except AttributeError: parent.raise_exception("Can't add parameter '%s' because it doesn't exist." % target, AttributeError) try: self.vartypename = metadata["vartypename"] except KeyError: self.vartypename = None try: val = expreval.evaluate() except Exception as err: parent.raise_exception("Can't add parameter because I can't evaluate '%s'." % target, ValueError) if self.vartypename != "Enum" and not isinstance(val, (float, float32, float64, int, int32, int64)): parent.raise_exception( "The value of parameter '%s' must be of type float or int, but its type is '%s'." % (target, type(val).__name__), ValueError, ) self.valtypename = type(val).__name__ meta_low = metadata.get("low") # this will be None if 'low' isn't there if low is None: self.low = meta_low else: if meta_low is not None and low < self._transform(meta_low): parent.raise_exception( "Trying to add parameter '%s', " "but the lower limit supplied (%s) exceeds the " "built-in lower limit (%s)." % (target, low, meta_low), ValueError, ) self.low = low meta_high = metadata.get("high") # this will be None if 'high' isn't there if high is None: self.high = meta_high else: # high is not None if meta_high is not None and high > self._transform(meta_high): parent.raise_exception( "Trying to add parameter '%s', " "but the upper limit supplied (%s) exceeds the " "built-in upper limit (%s)." % (target, high, meta_high), ValueError, ) self.high = high if self.vartypename == "Enum": return # it's an Enum, so no need to set high or low else: if self.low is None: parent.raise_exception( "Trying to add parameter '%s', " "but no lower limit was found and no " "'low' argument was given. One or the " "other must be specified." % target, ValueError, ) if self.high is None: parent.raise_exception( "Trying to add parameter '%s', " "but no upper limit was found and no " "'high' argument was given. One or the " "other must be specified." % target, ValueError, ) if low is None: self.low = self._transform(self.low) if high is None: self.high = self._transform(self.high) if self.low > self.high: parent.raise_exception( "Parameter '%s' has a lower bound (%s) that exceeds its upper bound (%s)" % (target, self.low, self.high), ValueError, )
def test_set_evaluate(self): ex = ExprEvaluator('comp.x', self.top) self.assertEqual(3.14, ex.evaluate()) ex.set(75.4) self.assertEqual(75.4, self.top.comp.x) self.top.comp.contlist = [A(), A(), A()] self.top.comp.contlist[1].a1d = [4]*5 ex = ExprEvaluator('comp.contlist[1].a1d[3]', self.top) self.assertEqual(ex.evaluate(), 4) ex.set(123) self.assertEqual(ex.evaluate(), 123) ex = ExprEvaluator("comp.contlist[1].some_funct(3,5,'sub')", self.top) self.assertEqual(ex.evaluate(), -2) ex = ExprEvaluator("comp.get_cont(1).some_funct(3,5,'add')", self.top) self.assertEqual(ex.evaluate(), 8) ex = ExprEvaluator("comp.get_cont(1).a1d[2]", self.top) self.assertEqual(ex.evaluate(), 4) ex = ExprEvaluator("a2d[1][0]", self.top.a) self.assertEqual(ex.evaluate(), 2.) ex.set(7.) self.assertEqual(self.top.a.a2d[1][0], 7.) ex = ExprEvaluator("a2d[1,0]", self.top.a) self.assertEqual(ex.evaluate(), 7.) ex.set(11.) self.assertEqual(self.top.a.a2d[1][0], 11.) ex = ExprEvaluator("a2d[1]", self.top.a) self.assertTrue(all(ex.evaluate() == numpy.array([11.,3.]))) ex.set([0.1,0.2]) self.assertTrue(all(self.top.a.a2d[1] == numpy.array([0.1,0.2]))) self.top.comp.cont = A() ex = ExprEvaluator("comp.cont.a2d[1][0]", self.top) self.assertEqual(ex.evaluate(), 2.) ex.set(7.) self.assertEqual(self.top.comp.cont.a2d[1][0], 7.) ex = ExprEvaluator("comp.cont.a2d[1,0]", self.top) self.assertEqual(ex.evaluate(), 7.) ex.set(11.) self.assertEqual(self.top.comp.cont.a2d[1][0], 11.) ex = ExprEvaluator("comp.get_cont(1).a1d", self.top) self.assertTrue(all(ex.evaluate() == numpy.array([4,4,4,123,4]))) ex = ExprEvaluator("comp.get_attr('get_cont')(1).a1d", self.top) self.assertTrue(all(ex.evaluate() == numpy.array([4,4,4,123,4]))) # try an expression that's a simple assignment ex = ExprEvaluator("f = 10.333", self.top.a) self.assertEqual(ex.evaluate(), None) self.assertEqual(self.top.a.f, 10.333)
class Constraint(object): """ Object that stores info for a single constraint. """ def __init__(self, lhs, comparator, rhs, scaler, adder, scope=None): self.lhs = ExprEvaluator(lhs, scope=scope) if not self.lhs.check_resolve(): raise ValueError("Constraint '%s' has an invalid left-hand-side." \ % ' '.join([lhs, comparator, rhs])) self.comparator = comparator self.rhs = ExprEvaluator(rhs, scope=scope) if not self.rhs.check_resolve(): raise ValueError("Constraint '%s' has an invalid right-hand-side." \ % ' '.join([lhs, comparator, rhs])) if not isinstance(scaler, float): raise ValueError("Scaler parameter should be a float") self.scaler = scaler if scaler <= 0.0: raise ValueError("Scaler parameter should be a float > 0") if not isinstance(adder, float): raise ValueError("Adder parameter should be a float") self.adder = adder def copy(self): return Constraint(self.lhs.text, self.comparator, self.rhs.text, self.scaler, self.adder, scope=self.lhs.scope) def evaluate(self, scope): """Returns a tuple of the form (lhs, rhs, comparator, is_violated).""" lhs = (self.lhs.evaluate(scope) + self.adder) * self.scaler rhs = (self.rhs.evaluate(scope) + self.adder) * self.scaler return (lhs, rhs, self.comparator, not _ops[self.comparator](lhs, rhs)) def evaluate_gradient(self, scope, stepsize=1.0e-6, wrt=None): """Returns the gradient of the constraint eq/inep as a tuple of the form (lhs, rhs, comparator, is_violated).""" lhs = self.lhs.evaluate_gradient(scope=scope, stepsize=stepsize, wrt=wrt) for key, value in lhs.iteritems(): lhs[key] = (value + self.adder) * self.scaler rhs = self.rhs.evaluate_gradient(scope=scope, stepsize=stepsize, wrt=wrt) for key, value in rhs.iteritems(): rhs[key] = (value + self.adder) * self.scaler return (lhs, rhs, self.comparator, not _ops[self.comparator](lhs, rhs)) def get_referenced_compnames(self): return self.lhs.get_referenced_compnames().union( self.rhs.get_referenced_compnames()) def __str__(self): return ' '.join([self.lhs.text, self.comparator, self.rhs.text]) def __eq__(self, other): if not isinstance(other, Constraint): return False return (self.lhs,self.comparator,self.rhs,self.scaler,self.adder) == \ (other.lhs,other.comparator,other.rhs,other.scaler,other.adder)
class SimAcceleration(Driver): """ Simulation of vehicle acceleration performance. This is a specialized simulation driver whose workflow should consist of a Vehicle assembly, and whose connections are as follows: Connection Inputs velocity_str: str Variable location for vehicle velocity. throttle_str: str Variable location for vehicle throttle position. gear_str: str Variable location for vehicle gear position. acceleration_str: str Variable location for vehicle acceleration. overspeed_str: str Variable location for vehicle overspeed. Simulation Inputs end_speed: float Ending speed for the simulation (default 60 mph) timestep: float Simulation time step (default .01) Outputs accel_time: float Time to perform the acceleration test. """ velocity_str = Str(iotype='in', desc='Location of vehicle input: velocity.') throttle_str = Str(iotype='in', desc='Location of vehicle input: throttle.') gear_str = Str(iotype='in', desc='Location of vehicle input: current_gear.') acceleration_str = Str(iotype='in', desc='Location of vehicle output: acceleration.') overspeed_str = Str(iotype='in', desc='Location of vehicle output: overspeed.') end_speed = Float(60.0, iotype='in', units='mi/h', desc='Simulation final speed') timestep = Float(0.1, iotype='in', units='s', desc='Simulation time step size') accel_time = Float(0.0, iotype='out', units='s', desc='Acceleration time') def __init__(self): super(SimAcceleration, self).__init__() self._velocity_str_expr = None self._throttle_str_expr = None self._gear_str_expr = None self._acceleration_str_expr = None self._overspeed_str_expr = None def _velocity_str_changed(self, oldval, newval): self._velocity_str_expr = ExprEvaluator(newval, scope=self.parent) def _throttle_str_changed(self, oldval, newval): self._throttle_str_expr = ExprEvaluator(newval, scope=self.parent) def _gear_str_changed(self, oldval, newval): self._gear_str_expr = ExprEvaluator(newval, scope=self.parent) def _acceleration_str_changed(self, oldval, newval): self._acceleration_str_expr = ExprEvaluator(newval, scope=self.parent) def _overspeed_str_changed(self, oldval, newval): self._overspeed_str_expr = ExprEvaluator(newval, scope=self.parent) def execute(self): """ Simulate the vehicle model at full throttle.""" # Set initial throttle, gear, and velocity time = 0.0 velocity = 0.0 throttle = 1.0 gear = 1 while velocity < self.end_speed: self._velocity_str_expr.set(velocity) self._throttle_str_expr.set(throttle) self._gear_str_expr.set(gear) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate(self.parent) overspeed = self._overspeed_str_expr.evaluate(self.parent) # If the next gear can produce more torque, let's shift. if gear < 5: self._gear_str_expr.set(gear + 1) self.run_iteration() acceleration2 = self._acceleration_str_expr.evaluate( self.parent) if acceleration2 > acceleration: gear += 1 acceleration = acceleration2 overspeed = self._overspeed_str_expr.evaluate(self.parent) # If RPM goes over MAX RPM, shift gears # (i.e.: shift at redline) if overspeed: gear += 1 self._gear_str_expr.set(gear) self.run_iteration() acceleration = self._acceleration_str_expr.evaluate( self.parent) overspeed = self._overspeed_str_expr.evaluate(self.parent) if overspeed: self.raise_exception("Gearing problem in Accel test.", RuntimeError) acceleration = convert_units(acceleration, 'm/(s*s)', 'mi/(h*s)') if acceleration <= 0.0: self.raise_exception("Vehicle could not reach maximum speed "+\ "in Acceleration test.", RuntimeError) velocity += (acceleration * self.timestep) time += self.timestep self.accel_time = time
def test_set_evaluate(self): ex = ExprEvaluator('comp.x', self.top) self.assertEqual(3.14, ex.evaluate()) ex.set(75.4) self.assertEqual(75.4, self.top.comp.x) self.top.comp.contlist = [A(), A(), A()] self.top.comp.contlist[1].a1d = [4]*5 ex = ExprEvaluator('comp.contlist[1].a1d[3]', self.top) self.assertEqual(ex.evaluate(), 4) ex.set(123) self.assertEqual(ex.evaluate(), 123) ex = ExprEvaluator("comp.contlist[1].some_funct(3,5,'sub')", self.top) self.assertEqual(ex.evaluate(), -2) ex = ExprEvaluator("comp.get_cont(1).some_funct(3,5,'add')", self.top) self.assertEqual(ex.evaluate(), 8) ex = ExprEvaluator("comp.get_cont(1).a1d[2]", self.top) self.assertEqual(ex.evaluate(), 4) ex = ExprEvaluator("a2d[1][0]", self.top.a) self.assertEqual(ex.evaluate(), 2.) ex.set(7.) self.assertEqual(self.top.a.a2d[1][0], 7.) ex = ExprEvaluator("a2d[1,0]", self.top.a) self.assertEqual(ex.evaluate(), 7.) ex.set(11.) self.assertEqual(self.top.a.a2d[1][0], 11.) ex = ExprEvaluator("a2d[1]", self.top.a) self.assertTrue(all(ex.evaluate() == array([11., 3.]))) ex.set([0.1, 0.2]) self.assertTrue(all(self.top.a.a2d[1] == array([0.1, 0.2]))) self.top.comp.cont = A() ex = ExprEvaluator("comp.cont.a2d[1][0]", self.top) self.assertEqual(ex.evaluate(), 2.) ex.set(7.) self.assertEqual(self.top.comp.cont.a2d[1][0], 7.) ex = ExprEvaluator("comp.cont.a2d[1,0]", self.top) self.assertEqual(ex.evaluate(), 7.) ex.set(11.) self.assertEqual(self.top.comp.cont.a2d[1][0], 11.) # try a numpy function try: import numpy except ImportError: pass else: ex = ExprEvaluator("numpy.eye(2)", self.top.a) val = ex.evaluate() self.assertTrue((val == numpy.eye(2)).all()) ex = ExprEvaluator("comp.get_cont(1).a1d", self.top) self.assertEqual(list(ex.evaluate()), [4, 4, 4, 123, 4]) ex = ExprEvaluator("comp.get_attrib('get_cont')(1).a1d", self.top) self.assertEqual(list(ex.evaluate()), [4, 4, 4, 123, 4])
def __init__(self, target, high=None, low=None, scaler=None, adder=None, start=None, fd_step=None, scope=None, name=None): self._metadata = None if scaler is None and adder is None: self._transform = self._do_nothing self._untransform = self._do_nothing else: if scaler is None: scaler = 1.0 else: try: scaler = float(scaler) except (TypeError, ValueError): raise ValueError( "Bad value given for parameter's 'scaler' attribute.") if adder is None: adder = 0.0 else: try: adder = float(adder) except (TypeError, ValueError): raise ValueError( "Bad value given for parameter's 'adder' attribute.") self.low = low self.high = high self.start = start self.scaler = scaler self.adder = adder self.fd_step = fd_step if name is not None: self.name = name else: self.name = target try: expreval = ExprEvaluator(target, scope) except Exception as err: raise err.__class__("Can't add parameter: %s" % str(err)) if not expreval.is_valid_assignee(): raise ValueError( "Can't add parameter: '%s' is not a valid parameter expression" % expreval.text) self._expreval = expreval try: # metadata is in the form (varname, metadata), so use [1] to get # the actual metadata dict metadata = self.get_metadata()[1] except AttributeError: raise AttributeError( "Can't add parameter '%s' because it doesn't exist." % target) if 'iotype' in metadata and metadata['iotype'] == 'out': raise RuntimeError( "Can't add parameter '%s' because '%s' is an output." % (target, target)) try: # So, our traits might not have a vartypename? self.vartypename = metadata['vartypename'] except KeyError: self.vartypename = None try: val = expreval.evaluate() except Exception as err: raise ValueError( "Can't add parameter because I can't evaluate '%s'." % target) self.valtypename = type(val).__name__ if self.vartypename == 'Enum': return # it's an Enum, so no need to set high or low if not isinstance(val, real_types) and not isinstance(val, int_types): raise ValueError( "The value of parameter '%s' must be a real or integral type, but its type is '%s'." % (target, type(val).__name__)) meta_low = metadata.get( 'low') # this will be None if 'low' isn't there if meta_low is not None: if low is None: self.low = self._untransform(meta_low) elif low < self._untransform(meta_low): raise ValueError( "Trying to add parameter '%s', " "but the lower limit supplied (%s) exceeds the " "built-in lower limit (%s)." % (target, low, meta_low)) else: if low is None: raise ValueError("Trying to add parameter '%s', " "but no lower limit was found and no " "'low' argument was given. One or the " "other must be specified." % target) meta_high = metadata.get( 'high') # this will be None if 'low' isn't there if meta_high is not None: if high is None: self.high = self._untransform(meta_high) elif high > self._untransform(meta_high): raise ValueError( "Trying to add parameter '%s', " "but the upper limit supplied (%s) exceeds the " "built-in upper limit (%s)." % (target, high, meta_high)) else: if high is None: raise ValueError("Trying to add parameter '%s', " "but no upper limit was found and no " "'high' argument was given. One or the " "other must be specified." % target) if self.low > self.high: raise ValueError( "Parameter '%s' has a lower bound (%s) that exceeds its upper bound (%s)" % (target, self.low, self.high))