Beispiel #1
0
    def add(self, device_id, device_class, pool, miner, algo, region, hashrate,
            gross_mbtc, net_mbtc, device_watts, total_watts):
        if not os.path.exists(self.log_file):
            with open(self.log_file, "w") as f:
                f.write(
                    "timestamp,device_id,device_class,pool,miner,algorithm,region,hashrate,gross_mbtc,net_mbtc,device_watts,total_watts\n"
                )

        with open(self.log_file, "a+") as f:
            if net_mbtc == 0:
                net_s = ""
            else:
                net_s = "%.2f" % (net_mbtc)

            if '_' in algo:
                hashrate_s = Units().hashrate_str(hashrate)
            else:
                hashrate_s = Units().hashrate_str(hashrate[0])

            f.write("%s,%d,%s,%s,%s,%s,%s,%s,%.2f,%s,%.2f,%.2f\n" %
                    (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                     device_id, device_class, pool, miner, algo, region,
                     hashrate_s, gross_mbtc, net_s, device_watts, total_watts))

        if os.path.getsize(self.log_file) >= (
                Config().get('stats.max_size_mb') * 1024 * 1024):
            self.rotate_logs(self.log_file)
Beispiel #2
0
    def __init__(self, sim, config):
        self.sim = sim
        self.config = config  # Note: this is passed in, and is located at sim.pod.forces.aero in the config file

        # @see http://www.softschools.com/formulas/physics/air_resistance_formula/85/
        self.air_resistance_k = Units.SI(
            self.config.air_density) * self.config.drag_coefficient * Units.SI(
                self.config.drag_area) / 2
Beispiel #3
0
    def test_str_and_repr(self):
        """
        String representations correctly created.
        """
        num = Units(value=0, units='ok')
        expected = '0ok'
        actual = str(num)
        self.assertEqual(expected, actual)

        expected = "Units(value=0, units='ok')"
        actual = num.__repr__()
        self.assertEqual(expected, actual)
        exec('expected = ' + num.__repr__())
        self.assertEqual(expected, num)
Beispiel #4
0
    def get_power_draw_average_time_periods(self):
        data = {}

        for seconds in Config().get('live_data.power_draw_averages'):
            data[seconds] = Units().seconds_to_string(seconds)

        return data
Beispiel #5
0
    def __init__(self, sim, config):
        PollingSensor.__init__(self, sim, config)
        self.logger = logging.getLogger("Accelerometer")

        self.logger.info("Initializing Accelerometer {}".format(self.config.id))
                
        self.data = namedtuple('AccelerometerData', ['t_usec', 'raw_x', 'raw_y', 'raw_z', 'real_x', 'real_y', 'real_z'])

        # Quantities for converting to raw values
        raw_min = self.config.raw_min
        raw_max = self.config.raw_max
        real_min = Units.SI(self.config.real_min)
        real_max = Units.SI(self.config.real_max)

        self.sensor_input_range = (real_min, real_max)
        self.sensor_output_range = (raw_min, raw_max)
Beispiel #6
0
  def get_miner_hashrate_for_algorithm_on_device(self, miner_name, algorithm, device_class):
    calibrated = self.get('%s.%s.%s' % (device_class, miner_name, algorithm))

    if calibrated:
      return Units().hashrate_str(calibrated['hashrate'])

    return " "
Beispiel #7
0
class JoyStick:
	def __init__(self):
		self.converter = Units()
	def moveUp(self, amount):
		return "PR ,{0}".format(self.converter.El_to_encoder(amount,False),)
	def moveDown(self, amount):
		return "PR ,{0}".format(-1*self.converter.El_to_encoder(amount,False),)
	
	def moveRight(self, amount):
		return "PR {0},".format(self.converter.Az_to_encoder(amount,False),)
		
	def moveLeft(self, amount):
		return "PR {0},".format(-1*self.converter.Az_to_encoder(amount,False),)
	def moveAbs(self, Az, El):
		return "PA {0},{1}".format(self.converter.Az_to_encoder(Az), self.converter.El_to_encoder(El))
	def calibrate(self, wanted_Az, wanted_El, current_Az, current_El):
		self.converter.setOffset(wanted_Az, wanted_El, current_Az, current_El)
Beispiel #8
0
    def __init__(self, sim, config):
        self.sim = sim
        self.config = config

        self.name = "F_lateral_stability"
        self.step_listeners = []
        self.data = namedtuple(self.name, ['x', 'y', 'z'])

        self.damping_coefficient = Units.SI(self.config.damping_coefficient)
Beispiel #9
0
 def realnew(klass, h, M, L, K):
   self = object.__new__(klass)
   self.M = M
   self.L = L
   self.K = K
   self.h = h
   self.units = Units(h)
   self.U = self.units
   self.DH = self.units.C / self.units.H0
   self.tH = 1.0 / self.units.H0
   self._cosmology = _cosmology.Cosmology(self.M, self.K, self.L, self.h)
   return self
Beispiel #10
0
    def check_hashrate(self):
        hashrates = Calibration().get_hashrates(self)

        if len(self.algos) == 0:
            return

        miner = self.algos[0]['miner']
        algo = self.algos[0]['algo']

        if not miner in hashrates.keys() or not algo in hashrates[miner].keys(
        ):
            self.log(
                'warning', 'running uncalibrated algorithm %s with miner %s' %
                (algo, miner))
            return

        if self.algos[0]['algo'] in Config().get('algorithms.single'):
            baseline = float(hashrates[miner][algo]['hashrate'])
        else:
            baseline = float(hashrates[miner][algo]['hashrate'][0])

        threshold_pc_value = (
            baseline / 100) * Config().get('hashrate_alert_threshold_percent')

        hr_s = Units().hashrate_str(self.algos[0]['hashrate'][0])
        bl_s = Units().hashrate_str(baseline)

        if self.algos[0]['hashrate'][0] < baseline and (
                baseline - self.algos[0]['hashrate'][0]) >= threshold_pc_value:
            self.log(
                'warning', 'hashrate %d%% below calibrated rate [%s < %s]' %
                (Config().get('hashrate_alert_threshold_percent'), hr_s, bl_s))

        if self.algos[0]['hashrate'][0] > baseline and (
                self.algos[0]['hashrate'][0] - baseline) >= threshold_pc_value:
            self.log(
                'warning', 'hashrate %d%% above calibrated rate [%s > %s]' %
                (Config().get('hashrate_alert_threshold_percent'), hr_s, bl_s))
    def __init__(self, sim, config):
        PollingSensor.__init__(self, sim, config)
        self.logger = logging.getLogger("LaserOptoSensor")

        self.logger.info("Initializing Laser Opto Sensor {}".format(
            self.config.id))

        # Get model info (min/max, raw values, etc.)
        self.model = self.sim.config.sensors.models[self.config.model]
        # Set ranges for mapping real to raw and vice versa
        self.real_range = [
            Units.SI(self.model.real_min),
            Units.SI(self.model.real_max)
        ]
        self.raw_range = [self.model.raw_min, self.model.raw_max]

        # Get the height offset for this sensor?
        self.he_height_offset = Units.SI(self.config.he_height_offset)
        self.measurement_offset = self.he_height_offset - Units.SI(
            self.model.internal_offset)

        # Data types
        self.data = namedtuple('LaserOptoSensorData', ('t_usec', 'height'))
Beispiel #12
0
 def parseFile(self, file):
     self.results = {}
     file = open(file,"r")
     try:
         for entry in file:
             entry = entry.strip()
             cols = entry.split("^")
             id = cols[0].strip("~")
             unit = cols[1].strip("~")
             unit = Units.getUnitForLabel(unit)
             label = cols[3].strip("~")
             val = Nutrient(label, unit, id)
             self.results[id] = val
     except:
         return None
     return self.results
Beispiel #13
0
    def __init__(self, sim, config):
        Sensor.__init__(self, sim, config)

        self.logger = logging.getLogger("PollingSensor")

        # Configuration

        # Grab the fixed timestep from the sim. If we wanted to use a variable timestep we would need to do the next calculations in the lerp function
        self.sampling_rate = Units.SI(self.config.sampling_rate)  # Hz

        # @see self._add_noise() and numpy.random.normal
        self.noise_center = self.config.noise.center or 0.0
        self.noise_scale = self.config.noise.scale or 0.0

        # Volatile
        #self.buffer = RingBuffer(config.buffer_size, config.dtype)   # @todo: How to specify dtype in configuration? There should be a string rep of dtype I think 
        self.buffer = None     # Note: we depend on our listeners to handle any buffering/saving/sending of sensor values. Buffer is cleard after each step.
        self.sample_times = None
        self.next_start = 0.0
        self.step_lerp_pcts = None  # Set during step
Beispiel #14
0
 def new_controller(self):
     '''
     Inits controller. Usage: New Simulation
     '''
     
     self.universe = Universe()
     
     # Holds the startpoint universe
     self.copy_universe = None
     
     # Folder where to save files and Default file name
     self.file_name = "test.xml"
     self.folder = "files/"
     self.filePath = None
     
     self.units = Units()
     
     self.pref_dict = {}
     
     self.timer_time = 10
     self.steps_between_paint = 1
    def set(self, **kwargs):
        """
        set() [public]
        Purpose:    Sets station plot variables (such as temperature, dewpoint, etc.)
        Parameters:    Key-value pairs (station variable to value, e.g. tmpf=50.
        Returns:    [nothing]
        """

        re_value_string = re.compile("^(\\-?[\\d]+\\.?[\\d]*)[\\s]*([\\w\\d\\- ]+)$")

        for attr, value in kwargs.iteritems():
            if attr in self._valid_attrs:
                re_value_match = re_value_string.match(value)
                if re_value_match is not None:
                    obs_value, obs_units = re_value_match.groups()
                    obs_value = Units.convert(float(obs_value), obs_units, HootPyStationPlot._internal_units[attr])
                    setattr(self, "_%s" % attr, obs_value)
                else:
                    setattr(self, "_%s" % attr, value)
            else:
                fatalError("Attribute %s is not a valid attribute for this type of station plot." % attr)
        return
Beispiel #16
0
    def create_step_samples(self, dt_usec):
        
        # Pod acceleration (x)
        pod_start_accel = self.sim.pod.last_acceleration
        pod_end_accel = self.sim.pod.acceleration
        
        # Create the samples (lerp between the times)
        sample_data = self._lerp(pod_start_accel, pod_end_accel)
        sample_times = sample_times = self._get_sample_times(dt_usec)

        # @todo: apply a rotation matrix to simulate the actual 

        # NOTE: Accel is mounted such that it is rotated 90 degrees in the horizontal plane such that:
        #       +y accel = +x pod reference frame, +x accel = -y pod reference frame
        #       ^ This is the format for the data.
        # @todo: move this to config somehow (tbd)

        # Map real values to sample values

        samples = []
        for i, t in enumerate(sample_times):
            real_x = 0
            real_y = sample_data[i]
            real_z = 9.81  # Accel due to gravity

            # @todo: Apply a rotation matrix? 

            # Map 
            xyz = np.array((real_x, real_y, real_z))
            # Add some noise (in G's)
            xyz += np.random.normal(self.noise_center, Units.SI(self.noise_scale), 3)
            xyz = np.interp(xyz, self.sensor_input_range, self.sensor_output_range)  
            xyz = xyz.astype(int)
            samples.append(self.data(t, xyz[0], xyz[1], xyz[2], real_x, real_y, real_z))

            #samples += self._get_gaussian_noise(samples, self.noise_center, self.noise_scale)            

        return samples
Beispiel #17
0
    def __init__(self, sim, config):

        self.sim = sim
        self.config = config

        # Physical
        # NOTE: @see diagram in http://confluence.rloop.org/display/SD/2.+Determine+Pod+Kinematics
        #       For the track/tube reference frame, x=0 at the start of the track, and x = length at the end.
        #       For the pod, x=0 is ahead and below the pod, with x+ being toward the read of the pod.
        self.length = Units.SI(
            config.length
        )  # meters -- Length from pod start position to end of track

        # Reference for the reflective stripes
        self.reflective_strip_width = Units.SI(
            config.reflective_strip_width)  # meters (4 inches)
        self.reflective_pattern_interval = Units.SI(
            config.reflective_pattern_interval)  # meters (100 feet)
        self.reflective_pattern_spacing = Units.SI(
            config.reflective_pattern_spacing
        )  # meters -- distance between stripes in a pattern

        self.track_gap_width = Units.SI(
            config.track_gap_width
        )  # Width of the gap in the subtrack in meters (probably worst scenario, more realistic 1-2 mm)
        self.track_gap_interval = Units.SI(
            config.track_gap_interval
        )  # Interval between the gaps in the subtrack in meters (Length of the aluminium plate)

        # Initialize
        self.reflective_strips = None  # Will be a numpy array after initialization
        self._init_reflective_strips(config.enable_strip_patterns)
        self.reflective_strip_ends = self.reflective_strips + self.reflective_strip_width  # Pre-calc the ends for use in LaserContrastSensor

        self.track_gaps = []
        self._init_track_gaps()
Beispiel #18
0
  def handle_device_update(self, device):
    if (datetime.datetime.now() - device.changed).seconds < (Config().get('calibration.update_calibration_data_after_mins') * 60):
      return

    for algo in device.algos:
      # Max update once a minute
      if algo['calibration_updated_at'] and \
        (time.time() - algo['calibration_updated_at']) < 60:
        continue

      if len(algo['hashrate_readings']) >0:
        readings_a = []
        readings_b = []

        for reading in algo['hashrate_readings']:
          readings_a.append(reading[0])
          readings_b.append(reading[1])

        if '_' in algo['algo']:
          variance, n = self.get_variance(readings_a, readings_b)
        else:
          variance, n = self.get_variance(readings_a)

        if self.is_stable(variance, n):
          calibrated_data = self.get('%s.%s.%s' % (device.dclass, algo['miner'], algo['algo']))

          if '_' in algo['algo']:
            nominal = [self.get_nominal_hashrate_from_range(readings_a), self.get_nominal_hashrate_from_range(readings_b)]
          else:
            nominal = self.get_nominal_hashrate_from_range(readings_a)

          if self.within_update_threshold(nominal, calibrated_data['hashrate']) and \
            self.hashrate_is_visibly_different(nominal, calibrated_data['hashrate']):
              device.log('info', '%s[%s]: new calibrated rate: %s' % (algo['algo'], algo['miner'], Units().hashrate_str(nominal)))

              calibrated_data['hashrate'] = nominal

              self.update_calibration_data(device.dclass, algo['miner'], algo['algo'], nominal, calibrated_data['power_limit'])

              self.set("%s.%s.%s" % (device.dclass, algo['miner'], algo['algo']), calibrated_data)
              algo['calibration_updated_at'] = time.time()
Beispiel #19
0
    def __init__(self, sim, config):
        ForceExerter.__init__(self, sim, config)
        self.name = 'F_lateral_stability'

        self.damping_coefficient = Units.SI(self.config.damping_coefficient)
Beispiel #20
0
class controller(object):
    '''
    Controlls universe
    '''
    
    def __init__(self):
        
        self.new_controller()
        
    def new_controller(self):
        '''
        Inits controller. Usage: New Simulation
        '''
        
        self.universe = Universe()
        
        # Holds the startpoint universe
        self.copy_universe = None
        
        # Folder where to save files and Default file name
        self.file_name = "test.xml"
        self.folder = "files/"
        self.filePath = None
        
        self.units = Units()
        
        self.pref_dict = {}
        
        self.timer_time = 10
        self.steps_between_paint = 1
        
    
    def create_object(self, name, mass, radius):
        '''
        Creates Object and adds it to the current universe
        '''
        uni_object = Uni_Object(name, mass, radius)
        self.universe.add_object(uni_object)
        
        return uni_object
        
    def delete_force(self, uni_object, delete_force_vector):
        '''
        delete force from object
        '''
        
        for i, force_vector in enumerate(uni_object.force_vector_list):
            if delete_force_vector == force_vector:
                
                uni_object.force_vector_list.pop(i)
                
                return True, 'Force removed'
        
        return False, 'Force not found'
        
    def delete_object(self, delete_uni_object):
        '''
        delete object from universe
        '''
        
        for i, uni_object in enumerate(self.universe.object_list):
            if delete_uni_object == uni_object:
                
                self.universe.object_list.pop(i)
                
                return True, 'Object removed'
        
        return False, 'Object not found'
        
    def validate_input(self, input_type, text, no_null = False):
        '''
        If input text is invalid, returns default value
        '''
        
        if input_type == 'string':
            
            if text == "":
                text =  'NONAME'
            
        elif input_type == 'int':
            
            if self.is_int(text):
                text =  int(text)
                
                if no_null:
                    if text == 0:
                        text = 1
            else:
                if no_null:
                    text = 1
                else:
                    text = 0
            
        elif input_type == 'float':
            
            if self.is_float(text):
                text =  float(text)
                
                if no_null:
                    if text == 0:
                        text = 1.1
            else:
                if no_null:
                    text = 1.0
                else:
                    text = 0.0
        
        return text
        
    def is_int(self, s):
        '''
        Tests that given parameter is integer
        @return: Bool (True, if param is integer)
        '''
        try: 
            int(s)
            return True
        except ValueError:
            return False
            
    def is_float(self, s):
        '''
        Tests that given parameter is float
        @return: Bool (True, if param is float)
        '''
        try:
            float(s)
            return True
        except ValueError:
            return False
        
    def create_angle_force(self, uni_object, force, angle2d, angle3d):
        '''
        Creates force vector from force and it's angles
        force,angle_xy,angle,xz => x,y,z (starting from the object location)
        '''
        
        ( x, y, z ) = self.universe.maths.get_vector_xyz(force, angle2d, angle3d)
        force = Force_Vector(x, y, z)
        
        uni_object.add_force_vector(force)
        
        return force
        
    def set_object_angle_speed(self, uni_object, speed, angle2d, angle3d):
        '''
        Sets object speed vector by transforming
        speed,angle_xy,angle,xz => x,y,z (starting from the object location)
        '''
        
        ( x, y, z ) = self.universe.maths.get_vector_xyz(speed, angle2d, angle3d)
        uni_object.set_speed(x, y, z)
        
    def set_force_angle(self, force_vector, force, angle2d, angle3d):
        '''
        Sets force vector by transforming
        speed,angle_xy,angle,xz => x,y,z (starting from the object location)
        '''
        
        ( x, y, z ) = self.universe.maths.get_vector_xyz(force, angle2d, angle3d)
        force_vector.set_force(x, y, z)
        
    def get_object_angle_speed(self, uni_object):
        '''
        Get speed vector in angle form
        '''
        return self.universe.maths.xyz_to_angle(uni_object.speed_x, uni_object.speed_y, uni_object.speed_z)
        
    def get_object_force_speed(self, uni_object):
        '''
        Get object force vector in angle form
        '''
        return self.universe.maths.xyz_to_angle(uni_object.force_x, uni_object.force_y, uni_object.force_z)
    
    def get_force_angle(self, force_vector):
        '''
        Get force vector in angle form
        '''
        return self.universe.maths.xyz_to_angle(force_vector.x, force_vector.y, force_vector.z)
    
    def animate_step(self):
        '''
        Simulates universe one step
        '''

        self.universe.move_objects()
        
    
    def animate(self, obj_num, time):
        '''
        Simulation is executed one year and it returns x-axis values divided by
        initial x-axis value from given object per month.
        
        Also step size is needed
        '''
        

        running = True
        
        self.universe.maths.time = time
        
        status, message = self.set_startpoint()
        
        hour = round(3600.0 / self.universe.maths.time)
        day = round(hour*24.0)
        month = round(day*30.0)
        year = round(day*365.0)
        run_day = 0
        
        message += "\n============="
        
        while running:
            
            if (self.universe.step % day) == 0:
                run_day += 1
                os.system("clear")
                print str(round((100 * self.universe.step / year),2)) + " % "
            
            if (self.universe.step % month) == 0:
                #print "month: " + str(self.controller.universe.step)
                x = self.universe.object_list[obj_num].x / self.copy_universe.object_list[obj_num].x
                x = str(x).replace(".",",")
                message += "\n" + x
            
            if self.universe.step > year:
                running = False
            
            self.animate_step()
            
        message += "\n============="
            
        if status is True:
            message += "\nSimulation done. x-position monthly, over a year"
        return status, message
    
    def set_startpoint(self):
        '''
        Sets startpoint for universe. It copies current in 
        copy_universe
        '''
        
        self.copy_universe = copy.deepcopy(self.universe)
        
        self.copy_universe.step = 0
        self.copy_universe.calc_time = 0
        
        return True, "Startpoint set"
        
    def reverse_startpoint(self):
        '''
        Copies startpoint-universe as the current one.
        If no startpoint-universe is set, then nothing is done.
        '''
        
        if self.copy_universe is not None:
            self.universe = copy.deepcopy(self.copy_universe)
            return True, "Startpoint reversed"
        
        return False, "No saved universe"
        
    def set_filePath(self, filePath):
        '''
        For Qt filepath load/save
        '''
        self.filePath = filePath
        
    def save(self):
        '''
        Saves current simulation in file
        '''
        self.pref_dict['paint'] = {'timer_time' : self.timer_time,
                                    'steps_between_paint' : self.steps_between_paint } 
        
        self.pref_dict['units'] = self.units.save_units()
        s = Dom_Save(self.pref_dict)
        
        s.add_universe(self.universe)
        if  self.copy_universe is not None:
            s.add_universe(self.copy_universe)
        
        if self.filePath is None:
            return s.save_simulation(self.folder + self.file_name)
            
        return s.save_simulation(self.filePath)
        
        
    def load(self):
        '''
        Loads simulation from file
        '''
        l = Dom_Load()
        
        if self.filePath is None:
            filePath = self.folder + self.file_name
        else:
            filePath = self.filePath
        
        (uni_list, self.pref_dict) = l.load_simulation(filePath)
        
        if 'units' in self.pref_dict:
            self.units.load_units(self.pref_dict['units'])
            
        if 'paint' in self.pref_dict:
            self.timer_time = int(self.pref_dict['paint']['timer_time'])
            self.steps_between_paint = int(self.pref_dict['paint']['steps_between_paint'])
        
        if uni_list is not None:
            
            if len(uni_list) == 1:
                self.universe = uni_list[0]
                self.copy_universe = None
            elif len(uni_list) >= 2:
                self.universe = uni_list[0]
                self.copy_universe = uni_list[1]
            else:
                return False, "Not enough universe-objects"
            return True, "Load ok"
                
        return False, "File not found"
            
    def list_files_in_folder(self):
        '''
        Returns files from file-folder
        '''
        
        files = []
        for f in os.listdir(self.folder):
            files.append(f)
            
        return files
        
    def not_empty(self):
        '''
        Finds out if universe is empty and has no objects
        @return: Bool (true, if universe is empty)
        '''
        if len(self.universe.object_list) > 0:
            return True
        return False
Beispiel #21
0
class Army(object):
    def __init__(self, units_config):
        self.units_config = units_config
        self.units = Units(units_config["units"])
        self.allies = Allies(units_config["allies"])
        self.battalions = Battalions(units_config["battalions"])
        self.all = [self.units, self.allies, self.battalions]

    def __str__(self):
        line = []
        for u in self.all:
            s = str(u)
            if s:
                line.append(s)
        return "{}: {}".format(self.points(), ", ".join(line))

    def __repr__(self):
        return str(self.units)

    def __len__(self):
        return len(self.units) + len(self.allies) + len(self.battalions)

    def fullstr(self, rules_config={}):
        points = self.points()
        if rules_config:
            line = [
                ("Points {} [{} to {}]".format(points,
                                               rules_config["points"] - points,
                                               rules_config["points"]))
            ]
        else:
            line = [("Points {}".format(points))]
        line.append(
            "\tWounds: {}, Models: {}, Bravery/Unit: {:.2f}, Save/Wound: {:.2f}+"
            .format(self.wounds(), self.unitsize(),
                    self.avg_bravery_per_unit(), self.avg_save_per_wound()))
        for u in self.all:
            s = u.fullstr()
            if s:
                line.append(s)
        line.append("Roles: {}".format(self.sum_roles_str(rules_config)))
        line.append("")
        return "\n".join(line)

    def __getitem__(self, index):
        for u in self.all:
            if index < len(u):
                return u[index]
            index = index - len(u)
        raise IndexError("index out of range")

    def __setitem__(self, index, item):
        for u in self.all:
            if index < len(u):
                u[index] = item
                return
            index = index - len(u)
        raise IndexError("index out of range")

    def add(self, name, unittype):
        if unittype == "unit":
            self.units.add(name)
        elif unittype == "ally":
            self.allies.add(name)
        elif unittype == "battalion":
            self.battalions.add(name)
        else:
            raise KeyError('Invalid unit type')

    def points(self):
        x = 0
        for u in self.all:
            x = x + u.points()
        return x

    def unitsize(self):
        x = 0
        for u in self.all:
            x = x + u.unitsize()
        return x

    def wounds(self):
        x = 0
        for u in self.all:
            x = x + u.wounds()
        return x

    def _bravery_sum(self):
        x = 0
        for u in self.all:
            x = x + u._bravery_sum()
        return x

    def _save_mul_wounds_sum(self):
        x = 0
        for u in self.all:
            x = x + u._save_mul_wounds_sum()
        return x

    def avg_bravery_per_unit(self):
        count = self.unitsize()
        if count == 0:
            return 0
        return self._bravery_sum() / float(count)

    def avg_save_per_wound(self):
        count = self.wounds()
        if count == 0:
            return 0
        return self._save_mul_wounds_sum() / float(count)

    def sum_roles(self, rules_config={}):
        r = {}
        for rulename, ruleactions in rules_config.get("units", {}).iteritems():
            r[rulename] = 0
        for u in self.all:
            u.sum_roles(r)
        return r

    def sum_roles_str(self, rules_config={}):
        roles = self.sum_roles(rules_config)
        line = []
        for role, count in roles.iteritems():
            rule = rules_config.get("units", {}).get(role, {})
            if rule:
                if rule["max"] == -1:
                    line.append("{} {} [{}+]".format(count, role, rule["min"]))
                else:
                    line.append("{} {} [{}->{}]".format(
                        count, role, rule["min"], rule["max"]))
            else:
                line.append("{} {}".format(count, role))
        return ", ".join(line)

    def __check_min_max(self, constraint, current_value, default_min,
                        default_max, restrict_config, final, showfails):
        con_min = restrict_config.get("min_" + constraint, default_min)
        con_max = restrict_config.get("max_" + constraint, default_max)

        if (current_value > con_max
                and con_max != -1) or (final and current_value < con_min):
            if showfails.value > PrintOption.SILENT.value:
                print "FAIL {}: {} {}->{} : {}".format(constraint,
                                                       current_value, con_min,
                                                       con_max, self)
            return False
        return True

    def is_valid(self,
                 rules_config,
                 restrict_config={},
                 final=True,
                 showfails=PrintOption.SILENT):

        if not self.__check_min_max(
                "points", self.points(), rules_config["points"],
                rules_config["points"], restrict_config, final, showfails):
            return False
        if not self.__check_min_max("wounds", self.wounds(), 0, -1,
                                    restrict_config, final, showfails):
            return False
        if not self.__check_min_max("models", self.unitsize(), 0, -1,
                                    restrict_config, final, showfails):
            return False
        if not self.__check_min_max("allies", self.allies.points(), 0,
                                    rules_config["allies"], restrict_config,
                                    final, showfails):
            return False

        #Default battalions to off until better support added
        if not self.__check_min_max("battalions", self.battalions.num(), 0, 0,
                                    restrict_config, final, showfails):
            return False

        for u in self.all:
            if not u.is_valid(restrict_config, final, showfails):
                return False

        # Check roles
        rules_check = self.sum_roles(rules_config)
        for role, count in rules_check.iteritems():
            # Check role meets min requirements
            if final and count < rules_config["units"][role]["min"]:
                if showfails.value > PrintOption.SILENT.value:
                    print "FAIL Role MIN {} {} {} : {}".format(
                        role, rules_config["units"][role]["min"], count, self)
                return False
            # Check role meets max requirements
            if rules_config["units"][role][
                    "max"] != -1 and count > rules_config["units"][role]["max"]:
                if showfails.value > PrintOption.SILENT.value:
                    print "FAIL Role MAX {} {} {} : {}".format(
                        role, rules_config["units"][role]["max"], count, self)
                return False

        return True
Beispiel #22
0
 def __init__(self, units_config):
     self.units_config = units_config
     self.units = Units(units_config["units"])
     self.allies = Allies(units_config["allies"])
     self.battalions = Battalions(units_config["battalions"])
     self.all = [self.units, self.allies, self.battalions]
Beispiel #23
0
    def start(self,
              device,
              pool_name,
              miner,
              algorithm,
              region,
              quick=False,
              force=False):
        self.miner = miner
        self.device = device
        self.default_profile = Config().get('device_profiles.default')

        Miners().reload_config()

        device.pin = {
            'pool_name': pool_name,
            'miner_name': miner.name,
            'algorithm': algorithm,
            'region': region
        }

        if not Config().get('calibration'):
            Log().add('fatal', "calibration config missing from config file")

        for key in [
                "hashrate_stabilisation_timeout_mins",
                "hashrate_stabilisation_tolerance",
                "hashrate_stabilisation_consecutive_readings_required",
                "algorithm_start_timeout"
        ]:
            if Config().get('calibration.%s' % (key)) == None:
                Log().add('fatal',
                          "missing config option: calibration.%s" % (key))

        if Config().get('calibration.power_tuning.enable'):
            for key in ["decrement_watts", "acceptable_loss_percent"]:
                if not Config().get('calibration.power_tuning.%s' % (key)):
                    Log().add(
                        'fatal',
                        "missing config option: calibration.power_tuning.%s" %
                        (key))

        Config().set('pools.%s.append_device_id_to_worker_name' % (pool_name),
                     False)

        if pool_name == 'miningpoolhub':
            if Config().get('pools.miningpoolhub.hub_workers.%s' %
                            (algorithm))[-5:] != 'CALIB':
                Config().set(
                    'pools.miningpoolhub.hub_workers.%s' % (algorithm),
                    Config().get('pools.miningpoolhub.hub_workers.%s' %
                                 (algorithm)) + 'CALIB')
        else:
            if Config().get('pools.%s.worker_name' %
                            (pool_name))[-5:] != 'CALIB':
                Config().set(
                    'pools.%s.worker_name' % (pool_name),
                    Config().get('pools.%s.worker_name' % (pool_name)) +
                    "CALIB")

        if quick:
            Config().set('calibration.power_tuning.enable', False)

        profile = Profiles().get_for_device_algo(device, algorithm)

        Log().add('info', '     device id: %d' % (device.id))
        Log().add('info', '          pool: %s' % (pool_name))
        Log().add('info', '  device class: %s' % (device.dclass))
        Log().add('info', 'device profile: %s' % (profile.name))
        Log().add('info', '         miner: %s' % (miner.name))
        Log().add('info', '     algorithm: %s' % (algorithm))
        Log().add('info', '        region: %s' % (region))

        Miners().poll()
        Miners().get_device_state(device)

        if device.state != 'inactive':
            if device.state == 'calibrating':
                device.log(
                    'fatal',
                    'this device is already being used for calibration')

            if force:
                device.log('info', 'terminating existing worker')
                if not device.stop(True):
                    device.log('fatal', 'failed to stop existing worker')
            else:
                device.log(
                    'fatal',
                    'unable to start calibration - device is in use (use --force to override)'
                )

        self.set_pin(device.id)

        default_power_limit = device.default_power_limit_f
        min_power_limit = device.min_power_limit_f
        max_power_limit = device.max_power_limit_f

        if max_power_limit == 0:
            device.log('info', 'device does not support power monitoring')
        else:
            device.log('info', 'max power limit: %d W' % (max_power_limit))

        device.log(
            'info', 'stabilisation tolerance: %.2f%%' %
            (Config().get('calibration.hashrate_stabilisation_tolerance')))

        if Config().get('debug'):
            device.log('debug', 'loading default profile')

        Nvidia().set_default_profile(device)

        if Config().get('debug'):
            device.log('debug', 'initialising pools')

        Pools()

        sample_timeout = Config().get(
            'calibration.hashrate_stabilisation_timeout_mins')

        if default_power_limit != None and Config().get(
                'calibration.power_tuning.enable'):
            device.log(
                'info',
                'starting initial run at max power limit [timeout=%dmins]' %
                (sample_timeout))
        else:
            device.log(
                'info',
                'starting single run [timeout=%dmins]' % (sample_timeout))

        Miners().poll()
        Miners().get_device_state(device)

        if device.state != 'calibrating':
            if not device.start(True):
                device.log('fatal', 'worker failed to start')

        if Config().get('calibration.power_tuning.enable'):
            if not device.power_supported():
                device.log('info', 'device does not support power monitoring')
            else:
                device.set_power_limit(max_power_limit)

        initial_hashrate, initial_max_power_draw = self.get_max_hashrate_and_power_draw(
            miner, device, sample_timeout * 60)

        if initial_hashrate == None:
            device.log(
                'info',
                'skipping algorithm as we failed to get a stable reading')
            print ""
            return

        if initial_max_power_draw != None and initial_max_power_draw > max_power_limit:
            initial_max_power_draw = max_power_limit

        device.log(
            'info', 'benchmark hashrate: %s' %
            (Units().hashrate_str(initial_hashrate)))

        if initial_max_power_draw != None:
            device.log('info',
                       'max power draw: %.2f' % (initial_max_power_draw))
            initial_power_limit = int(math.ceil(initial_max_power_draw))

        hashrate = initial_hashrate

        if initial_max_power_draw == None:
            power_limit = None
        elif Config().get('calibration.power_tuning.enable'):
            if max_power_limit == 0 or min_power_limit == 0 or default_power_limit == 0:
                device.log(
                    'error',
                    'device did not give us sane values for its min/max/default power limits'
                )
                device.log(
                    'error',
                    'unable to proceed with power calibration - device may not support changing the power limit'
                )

                power_limit = default_power_limit
            else:
                power_limit = initial_power_limit

                device.log('info', 'tuning power limit for optimum efficiency')
                hashrate, power_limit = self.do_power_calibration(
                    device, power_limit, miner, hashrate, min_power_limit)
        else:
            power_limit = default_power_limit

        Nvidia().set_default_profile(device)

        self.unset_pin(device.id)

        device.log('info', 'storing calibration data')

        Calibration().update_calibration_data(device.dclass, miner.name,
                                              algorithm, hashrate, power_limit)

        if not device.stop(True):
            device.log('fatal', "failed to stop the miner process")

        print ""

        device.log(
            'info',
            '   calibrated hashrate: %s' % (Units().hashrate_str(hashrate)))

        if power_limit != None:
            device.log('info',
                       'calibrated power limit: %.2f W' % (power_limit))

        print ""
Beispiel #24
0
    def __init__(self, sim, config):
        self.sim = sim
        self.config = config

        self.logger = logging.getLogger("Brake")

        # Limit Switches
        # Switch activation: We only want to call the callback when the switch is tripped, not repeatedly
        self.retract_sw_activated = False
        self.extend_sw_activated = False

        # Volatile
        #self.gap = Units.SI(self.config.initial_gap)  # @todo: make this work

        # Rail Gap
        # Screw pos is the main value from which we calculate the gap and MLP values. [0, 75000]um fully retracted to fully extended (maps to brake gap)
        # Note: screw position is updated by the callback from the FCU
        self.gap = Units.SI(self.config.gap.initial_gap)
        #print "Gap after conversion is {}".format(self.gap)
        #exit()
        self.retracted_gap = Units.SI(self.config.gap.retracted_gap)
        self.extended_gap = Units.SI(self.config.gap.extended_gap)
        self.gap_range = [self.retracted_gap, self.extended_gap]

        # Screw
        self.screw_limit_sw_retract = Units.SI(
            self.config.lead_screw.limit_sw_retract)
        self.screw_limit_sw_extend = Units.SI(
            self.config.lead_screw.limit_sw_extend)
        self.screw_range = [
            self.screw_limit_sw_retract, self.screw_limit_sw_extend
        ]
        # Calculate initial screw position from the initial gap (note: during processing it's the other way around)
        self.screw_pos = np.interp(self.gap, self.gap_range, self.screw_range)

        # Linear Position Sensor
        # @todo: check this to make sure the min/max are in the correct order -- should be retracted->extended
        self.mlp_range = [self.config.mlp.raw_min, self.config.mlp.raw_max]
        # Calculate raw MLP value from the screw position

        print("{}, {}, {}".format(self.screw_pos, self.screw_range,
                                  self.mlp_range))

        self.mlp_raw = np.interp(self.screw_pos, self.screw_range,
                                 self.mlp_range)

        # Negator
        self.negator_torque = Units.SI(self.config.negator.torque)

        # TESTING ONLY
        self._gap_target = self.gap  # Initialize to current value so we don't move yet
        self._gap_close_time = Units.SI(self.config.gap_close_min_time)
        self._gap_close_dist = self.retracted_gap - self.extended_gap
        self._gap_close_speed = self._gap_close_dist / self._gap_close_time  # meters/second -- this is just a guess -- .007 m/s = closing 21mm in 3s
        #self.logger.debug("Brake gap close speed: {} m/s".format(self._gap_close_speed))
        # /TESTING

        self.normal_force = 0.0  # N -- normal against the rail; +normal is away from the rail
        self.drag_force = 0.0  # N -- drag on the pod; -drag is toward the back of the pod

        self.last_normal_force = 0.0
        self.last_drag_force = 0.0

        # Lead Screw
        # revs per cm=2.5  There are 4 mm per single lead so 2.5 turns move the carriage 1 cm
        # Formulas: http://www.nookindustries.com/LinearLibraryItem/Ballscrew_Torque_Calculations
        self.screw_pitch = Units.SI(self.config.lead_screw.pitch)
        self.drive_efficiency = self.config.lead_screw.drive_efficiency
        self.backdrive_efficiency = self.config.lead_screw.backdrive_efficiency

        # Lead Screw Precalculated Values
        self._drive_torque_multiplier = self.screw_pitch / (
            self.drive_efficiency * 2 * 3.14)
        self._backdrive_torque_multiplier = (
            self.screw_pitch * self.backdrive_efficiency) / (2 * 3.14)
Beispiel #25
0
    def hashrate_str(self):
        if self.algos[0]['algo'] in Config().get('algorithms.single'):
            return Units().hashrate_str(self.algos[0]['hashrate'][0])

        return Units().hashrate_str(self.algos[0]['hashrate'])
Beispiel #26
0
    def do_power_calibration(self, device, power_limit, miner,
                             initial_hashrate, min_power_limit):
        sample_timeout = Config().get(
            'calibration.hashrate_stabilisation_timeout_mins')
        acceptable_loss_pc = Config().get(
            'calibration.power_tuning.acceptable_loss_percent')

        dial_back = False
        dialed_back = False
        hashrate = initial_hashrate

        if "_" in device.algos[0]['algo']:
            initial_value = initial_hashrate[0]
        else:
            initial_value = initial_hashrate

        while True:
            if dial_back:
                power_limit += Config().get(
                    'calibration.power_tuning.decrement_watts') / 2
                dialed_back = True
            else:
                power_limit -= Config().get(
                    'calibration.power_tuning.decrement_watts')

            if power_limit < min_power_limit:
                power_limit = min_power_limit

            device.log('info', 'setting power limit: %d W' % (power_limit))

            device.set_power_limit(power_limit)

            new_hashrate, max_power_draw = self.get_max_hashrate_and_power_draw(
                miner, device, sample_timeout * 60)

            if new_hashrate == None:
                device.log(
                    'info',
                    'skipping algorithm as we failed to get a stable reading')
                print ""
                return

            if "_" in device.algos[0]['algo']:
                new_value = new_hashrate[0]
            else:
                new_value = new_hashrate

            device.log(
                'info',
                'nominal hashrate: %s' % (Units().hashrate_str(new_hashrate)))

            if new_value > initial_value:
                device.log('info', 'hashrate is higher than before, w00t!')
                hashrate = new_hashrate
                initial_value = new_value
            elif new_value >= (initial_value -
                               (initial_value / 100) * acceptable_loss_pc):
                hashrate = new_hashrate
                if power_limit == min_power_limit or dial_back:
                    device.log(
                        'info', 'hashrate loss is within acceptable %.2f%%' %
                        (acceptable_loss_pc))
                else:
                    device.log(
                        'info',
                        'hashrate loss is within acceptable %.2f%%, continuing'
                        % (acceptable_loss_pc))
            else:
                if dial_back or Config().get(
                        'calibration.power_tuning.decrement_watts') == 1:
                    device.log(
                        'info',
                        'hashrate still below our acceptable loss level of %.2f%%, stopping'
                        % (acceptable_loss_pc))

                    if Config().get(
                            'calibration.power_tuning.decrement_watts') == 1:
                        power_limit += 1
                    else:
                        power_limit += Config().get(
                            'calibration.power_tuning.decrement_watts') / 2
                    break
                else:
                    device.log(
                        'info',
                        'hashrate fell below our acceptable loss level of %.2f%%, dialling back %d W'
                        % (acceptable_loss_pc, Config().get(
                            'calibration.power_tuning.decrement_watts') / 2))
                    dial_back = True

            if dialed_back:
                break

            if power_limit == min_power_limit and not dial_back:
                device.log('info', 'minimum power limit reached, stopping')
                break

        return [hashrate, power_limit]
Beispiel #27
0
    def __init__(self, sim, config):
        ForceExerter.__init__(self, sim, config)
        self.name = 'F_aero'

        # @see http://www.softschools.com/formulas/physics/air_resistance_formula/85/
        self.air_resistance_k = Units.SI(self.config.air_density) * self.config.drag_coefficient * Units.SI(self.config.drag_area) / 2
Beispiel #28
0
	def testElEncToDeg(self):
		p = Units()
		self.failUnless(p.encoder_to_El(10)==1110)
Beispiel #29
0
	def __init__(self):
		self.converter = Units()
Beispiel #30
0
    def resistance(self):
        """Return a succinct string representing the resistance of this Resistor.

        e.g. '23.6KΩ'
        """
        return str(Units.ohms(self.ohms))
Beispiel #31
0
	def testAzEncToDeg(self):
		p = Units()
		self.failUnless(p.encoder_to_Az(10)==28440)
Beispiel #32
0
    def __init__(self, sim, config):

        self.logger = logging.getLogger("Pod")
        self.logger.info("Initializing pod")

        self.sim = sim
        self.config = config

        self.name = 'pod_actual'

        self.step_listeners = []
        self.step_forces = OrderedDict(
        )  # This will be filled in during each step

        # Pod physical properties
        # *** NOTE: all distances are in the track/tube reference frame, origin is pod location reference (centerpoint of fwd crossbar).  +x is forward, +y is left, +z is up.
        # @see http://confluence.rloop.org/display/SD/2.+Determine+Pod+Kinematics

        self.mass = Units.SI(self.config.mass)
        self.pusher_plate_offset = Units.SI(
            self.config.physical.pusher_plate_offset)
        self.pusher_pin_travel = Units.SI(
            self.config.physical.pusher_pin_travel)

        # Forces that can act on the pod (note: these are cleared at the end of each step)
        self.net_force = np.array(
            (0.0, 0.0, 0.0)
        )  # Newtons; (x, y, z). +x pushes the pod forward, +z force lifts the pod, y is not currently used.

        # Initialize actual physical values (volatile variables). All refer to action in the x dimension only.
        self.acceleration = Units.SI(
            self.config.acceleration) or 0.0  # meters per second ^2
        self.velocity = Units.SI(
            self.config.velocity) or 0.0  # meters per second
        self.position = Units.SI(
            self.config.position
        ) or 0.0  # meters. Position relative to the track; start position is 0m

        # @todo: this is just a sketch, for use with the hover engine calculations. Maybe switch accel, velocity, and position to coordinates? hmmmm...
        self.z_acceleration = 0.0
        self.z_velocity = 0.0
        self.he_height = Units.SI(
            self.config.landing_gear.initial_height
        )  # This should be gotten from the starting height of the lift mechanism
        self._initial_he_height = self.he_height  # @todo: Remove this -- it's only used as a temporary block from going through the floor until the landing gear is implemented

        self.elapsed_time_usec = 0

        # Values from the previous step (for lerping and whatnot)
        self.last_acceleration = 0.0
        self.last_velocity = 0.0
        self.last_position = 0.0
        self.last_he_height = 0.0

        # Handle forces that act on the pod
        """
        self.forces = []
        self.forces.append( AeroForce(self.sim, self.config.forces.aero) )
        self.forces.append( BrakeForce(self.sim, self.config.forces.brakes) )
        self.forces.append( GimbalForce(self.sim, self.config.forces.gimbals) )
        self.forces.append( HoverEngineForce(self.sim, self.config.forces.hover_engines) )
        self.forces.append( LateralStabilityForce(self.sim, self.config.forces.lateral_stability) )
        self.forces.append( LandingGearForce(self.sim, self.config.forces.landing_gear) )
        """
        self.force_exerters = OrderedDict()
        self.force_exerters['aero'] = AeroForce(self.sim,
                                                self.config.forces.aero)
        self.force_exerters['brakes'] = BrakeForce(self.sim,
                                                   self.config.forces.brakes)
        self.force_exerters['gimbals'] = GimbalForce(
            self.sim, self.config.forces.gimbals)
        self.force_exerters['hover_engines'] = HoverEngineForce(
            self.sim, self.config.forces.hover_engines)
        self.force_exerters['lateral_stability'] = LateralStabilityForce(
            self.sim, self.config.forces.lateral_stability)
        self.force_exerters['landing_gear'] = LandingGearForce(
            self.sim, self.config.forces.landing_gear)

        # Forces applied during the step (for recording purposes)
        # @todo: Maybe initialize these to ForceExerter.data(0,0,0)?
        self.step_forces = OrderedDict()
        self.step_forces['aero'] = ForceExerter.data(0, 0, 0)
        self.step_forces['brakes'] = ForceExerter.data(0, 0, 0)
        self.step_forces['gimbals'] = ForceExerter.data(0, 0, 0)
        self.step_forces['hover_engines'] = ForceExerter.data(0, 0, 0)
        self.step_forces['lateral_stability'] = ForceExerter.data(0, 0, 0)
        self.step_forces['landing_gear'] = ForceExerter.data(0, 0, 0)

        # Pre-calculated values

        # HE Drag
        """
        Drag for a single hover engine (keep in mind that we have 8):
        
        Constants:
        w: Comes from solving 3d maxwell's equations (@whiplash) and using other fancy math -- provided by @whiplash -- not dependent on velocity, just depends on magnetic characteristics
        mu_0: Absolute permeability of the vacuum (constant) -- permeability constant, magnetic constant, etc. -- permeability of free space
        m: Magnetic dipole strength (constant, but depends on how magnets are arranged)
        h: thickness of conducting material (rail in this case)
        rho: density of conducting material (aluminum in this case)

        Variables: 
        z_0: Distance between magnet and conducting surface
        v: Velocity
        
        Calculated:        
        w = 2 * rho / (mu_0 * h)
        F_lift / F_drag = v / w
        F_lift = ((3 * mu_0 * m**2) / (32 * 3.14159 * z_0**4)) * (1 - w * (v**2 + w**2)**(-1/2))

        Values (from @whiplash): 
        mu_0: 4 pi x10e-7
        rho: 2.7 g/cubic centimeter
        h: 0.5 in
        m: (@whiplash will need to calculate this -- it's a vector quantity, need to draw a magnetic circuit) 
        """

        # Brakes

        #self.brakes = []
        #for brake_config in self.config.brakes:
        #    self.brakes.append(Brake(self.sim, brake_config))
        self.brakes = Brakes(self.sim, self.config.brakes)
        """ Sketch:
Beispiel #33
0
    args_cli = pytools.parse_args()
    var = args_cli.var

    #confs = [ "gam3.ini", ]
    confs = [
        args_cli.conf_filename,
    ]

    for conf_filename in confs:
        conf = Configuration(conf_filename, do_print=True)

        # restructure path to point to this dir
        fdir = conf.outdir
        print(fdir)

        units = Units(conf)

        #--------------------------------------------------
        # read data

        flds_Epar = []
        flds_Eperp = []

        flds_Bpar = []
        flds_Bperp = []

        flds_Jpar = []
        flds_Jperp = []
        flds_time = []

        flds_tot = []
Beispiel #34
0
    def get_local_data(self, minimal=False):
        data = []

        devices = nvidia.Nvidia().get_nvidia_devices(1, True)

        Miners().poll()

        if not minimal and os.path.exists(
                self.power_file) and os.path.getsize(self.power_file) > 0:
            power_draw_readings = pickle.loads(open(self.power_file).read())
        else:
            power_draw_readings = []

        if not minimal and os.path.exists(
                self.profitability_file) and os.path.getsize(
                    self.profitability_file) > 0:
            profitability_readings = pickle.loads(
                open(self.profitability_file).read())
        else:
            profitability_readings = []

        Calibration().load()

        total_mbtc = 0
        total_power = 0
        total_power_limit = 0

        power_values = {}
        power_limit_values = {}

        for device in devices:
            device.algos = []
            Miners().get_device_state(device)

            mbtc_per_day_values = [0]

            algos = device.algos

            if len(algos) == 0:
                algos = ['IDLE']

            for algo_i in range(0, len(algos)):
                algo = algos[algo_i]

                if algo_i == 0:
                    omit_fields = False
                else:
                    omit_fields = True

                if algo == 'IDLE':
                    algo = "IDLE"
                    algo1 = "IDLE"
                    rate_s = "-"
                    mbtc_per_day = 0
                    miner = '-'
                    region = '-'
                    pool = '-'
                    _time = '-'
                else:
                    algo1 = algo['algo']
                    miner = algo['miner']
                    region = algo['region']
                    pool = algo['pool']
                    _pool = Pools().pools[pool]

                    if os.path.exists("/tmp/.minotaur.%d" % (device.id)):
                        _time = Units().to_timestr(
                            int(time.time() - os.stat("/tmp/.minotaur.%d" %
                                                      (device.id)).st_mtime))
                    else:
                        _time = '-'

                    rate_a, rate_b = algo['hashrate']

                    if algo['algo'] in Config().get('algorithms')['double']:
                        rate_s = Units().hashrate_str(rate_a)
                        rate_s2 = Units().hashrate_str(rate_b)

                        benchmarks = {algo['algo']: [rate_a, rate_b]}

                        algo1, algo2 = algo['algo'].split("_")

                        mbtc_per_day_values = [
                            _pool.mbtc_per_day(
                                benchmarks,
                                'cached')[algo['region']][algo['algo']]
                        ]
                    else:
                        rate_s = Units().hashrate_str(rate_a)

                        benchmarks = {algo['algo']: rate_a}

                        if algo['algo'] in _pool.mbtc_per_day(
                                benchmarks, 'cached')[algo['region']].keys():
                            mbtc_per_day_values = [
                                _pool.mbtc_per_day(
                                    benchmarks,
                                    'cached')[algo['region']][algo['algo']]
                            ]
                        else:
                            mbtc_per_day_values = [0]

                if pool != '-':
                    pool = _pool.shortened(region)

                metrics = device.to_hash()
                metrics.pop('changed', None)
                metrics['miner'] = miner
                metrics['region'] = region
                metrics['pool'] = pool
                metrics['time'] = _time
                metrics['omit_fields'] = omit_fields

                if metrics['fan']:
                    metrics['fan'] = str(metrics['fan']).rjust(3) + " %"

                if metrics['miner']:
                    metrics['miner'] = metrics['miner'][0:5]
                else:
                    metrics['miner'] = '-'

                if algo == "IDLE":
                    if metrics['gpu_u_i'] and metrics['gpu_u_i'] >= 90:
                        algo = ".pending."
                        algo1 = ".pending."
                        rate_s = ".."

                mbtc_per_day = mbtc_per_day_values[0]

                metrics['host'] = 'local'
                metrics['id'] = device.id
                metrics[" algo"] = algo1
                metrics["rate"] = rate_s

                metrics[" mBTC/day"] = ("%.2f" % (mbtc_per_day)).rjust(5)

                if not metrics['region']:
                    metrics['region'] = '-'

                total_mbtc += sum(mbtc_per_day_values)

                if metrics['power_f']:
                    power_values[metrics['id']] = metrics['power_f']
                    margin = self.calculate_profit_margin_for_card(
                        sum(mbtc_per_day_values), metrics['power_f'])

                    net_mbtc = (mbtc_per_day / 100) * margin

                    if margin < 0:
                        margin = 0

                    margin_s = "%d%%" % (int(margin))

                    metrics[" mBTC/day"] += "/"
                    metrics[" mBTC/day"] += ("%.2f" % (net_mbtc)).rjust(5)
                    metrics[" mBTC/day"] += " %s" % (margin_s.rjust(4))
                else:
                    margin = 0

                if margin > 0:
                    metrics["margin"] = "%.1f%%" % (margin)
                else:
                    metrics["margin"] = "-"

                if metrics['limit_f']:
                    power_limit_values[metrics['id']] = metrics['limit_f']

                if device.state == 'calibrating':
                    metrics[' algo'] = '*' + metrics[' algo']
                elif device.get_pin() and 'algorithm' in device.get_pin().keys(
                ) and device.get_pin()['algorithm'] == metrics[' algo']:
                    metrics[' algo'] = '+' + metrics[' algo']
                elif device.get_pin() and 'algorithm' in device.get_pin().keys(
                ) and '_' in device.get_pin()['algorithm'] and metrics[
                        ' algo'] in device.get_pin()['algorithm'].split('_'):
                    metrics[' algo'] = '+' + metrics[' algo']
                else:
                    metrics[' algo'] = ' ' + metrics[' algo']

                if metrics['gpu_f']:
                    match = re.match("^([\d]+)", metrics['gpu_f'])
                    if match:
                        metrics['gpu_f'] = match.group(1)
                    else:
                        metrics['gpu_f'] = '-'
                else:
                    metrics['gpu_f'] = '-'

                if metrics['mem_f']:
                    match = re.match("^([\d]+)", metrics['mem_f'])
                    if match:
                        metrics['mem_f'] = match.group(1)
                    else:
                        metrics['mem_f'] = '-'
                else:
                    metrics['mem_f'] = '-'

                metrics['ps clocks'] = "%s %s/%s MHz" % (
                    metrics['ps'], metrics['gpu_f'], metrics['mem_f'])

                power = re.match("^([\d]+)", metrics['power'])
                limit = re.match("^([\d]+)", metrics['limit'])

                if power and limit:
                    metrics['power'] = "%s/%s W" % (power.group(1),
                                                    limit.group(1))
                else:
                    metrics['power'] = '-'

                data.append(metrics)

                if algo not in [
                        'IDLE', '.pending.'
                ] and algo['algo'] in Config().get('algorithms.double'):
                    mbtc_per_day = mbtc_per_day_values[1]

                    metrics2 = metrics.copy()
                    metrics2[" algo"] = algo2

                    metrics2["rate"] = rate_s2

                    metrics2[" mBTC/day"] = ("%.2f" % (mbtc_per_day)).rjust(5)

                    net_mbtc = (mbtc_per_day / 100) * margin

                    metrics2[" mBTC/day"] += "/"
                    metrics2[" mBTC/day"] += ("%.2f" % (net_mbtc)).rjust(5)
                    metrics2[" mBTC/day"] += " %s" % (margin_s.rjust(4))

                    if device.state == 'calibrating':
                        metrics2[" algo"] = '*' + metrics2[' algo']
                    elif device.get_pin() and '_' in device.get_pin(
                    )['algorithm'] and metrics2[' algo'] in device.get_pin(
                    )['algorithm'].split('_'):
                        metrics2[" algo"] = '+' + metrics2[' algo']
                    else:
                        metrics2[" algo"] = ' ' + metrics2[' algo']

                    data.append(metrics2)

        total_power = sum(power_values.values())
        total_power_limit = sum(power_limit_values.values())

        electric_cost_mbtc = self.get_electricity_cost(
            total_power + Config().get('system_draw_watts'), True,
            Config().get('electricity_per_kwh'))
        net_mbtc = total_mbtc - electric_cost_mbtc

        return [
            data, total_mbtc, net_mbtc, total_power, total_power_limit,
            power_draw_readings, profitability_readings
        ]