예제 #1
0
    def __init__(self, name, primary, secondary, avgsep, ep=0, es=0, id=None):
        if secondary.mass <= primary.mass:
            self.primary = primary
            self.secondary = secondary
        else:
            self.primary = secondary
            self.secondary = primary

        if name is None:
            self.has_name = False
            self.name = 'NoName'
        else:
            self.name = name

        self.ecc_p = q(ep)
        self.ecc_s = q(es)
        self.average_separation = q(avgsep, 'au')
        self.barycenter = q(avgsep * (self.secondary.mass.m / (self.primary.mass.m + self.secondary.mass.m)), 'au')
        self.primary_distance = round(self.barycenter, 2)
        self.secondary_distance = round(self.average_separation - self.primary_distance, 2)

        self.primary.orbit = BinaryStarOrbit(self.primary, self.secondary, self.primary_distance, self.ecc_p)
        self.secondary.orbit = BinaryStarOrbit(self.secondary, self.primary, self.secondary_distance, self.ecc_s)

        self.system_name = self.__repr__()

        # ID values make each system unique, even if they have the same stars and separation.
        now = ''.join([char for char in str(datetime.now()) if char not in [' ', '.', ':', '-']])
        self.id = id if id is not None else now
예제 #2
0
    def __init__(self, primary, secondary, avgsep, ep=0, es=0, id=None, name=None):
        super().__init__(name, primary, secondary, avgsep, ep, es, id=id)

        assert 0.4 <= ep <= 0.7, 'Primary eccentricity must be between 0.4 and 0.7'
        max_sep_p, min_sep_p = self.calculate_distances(ep, self.primary_distance.m)

        assert 0.4 <= es <= 0.7, 'Secondary eccentricity must be between 0.4 and 0.7'
        max_sep_s, min_sep_s = self.calculate_distances(es, self.secondary_distance.m)

        self.max_sep = max_sep_p + max_sep_s
        self.min_sep = min_sep_p + min_sep_s
        assert self.min_sep.m > 0.1, "Stars will merge at {:~} minimum distance".format(self.min_sep)

        self._mass = primary.mass + secondary.mass
        self._luminosity = primary.luminosity + secondary.luminosity

        self._habitable_inner = round(sqrt(self._luminosity.m / 1.1), 3)
        self._habitable_outer = round(sqrt(self._luminosity.m / 0.53), 3)
        self._inner_boundry = round(self._mass.m * 0.01, 3)
        self._outer_boundry = round(self._mass.m * 40, 3)
        self._frost_line = round(4.85 * sqrt(self._luminosity.m), 3)
        self.set_qs()
        self.spin = self.primary.spin

        self.inner_forbbiden_zone = q(round(self.min_sep.m / 3, 3), 'au')
        self.outer_forbbiden_zone = q(round(self.max_sep.m * 3, 3), 'au')

        self.habitable_orbit = round(self.max_sep * 4, 3)
예제 #3
0
 def reset_period_and_speed(self, main_body_mass):
     satellite_mass = round(self.astrobody.mass.m, 3)
     self.velocity = q(sqrt(main_body_mass.m / self._a),
                       'earth_orbital_velocity').to('kilometer per second')
     self.period = q(
         sqrt(
             pow(self.a.to('au').m, 3) /
             (main_body_mass.m + satellite_mass)), 'year').to('day')
예제 #4
0
 def tilt(self, value):
     if 0 <= value < 90:
         self.spin = 'prograde'
     elif 90 <= value <= 180:
         self.spin = 'retrograde'
     self._tilt = q(value, 'degree')
     self.habitable = self.set_habitability()
     self.albedo = self.albedo if not self.habitable else q(29)
예제 #5
0
    def __init__(self, data):
        mass = data.get('mass', False)
        radius = data.get('radius', False)
        gravity = data.get('gravity', False)
        if not mass and not radius and not gravity:
            raise AssertionError('must specify at least two values')

        name = data.get('name', None)
        if name is not None:
            self.name = name
            self.has_name = True

        unit = data.get('unit', "earth")
        self.unit = unit
        self.idx = data.get('idx', 0)

        self._mass = None if not mass else mass
        self._radius = None if not radius else radius
        self._gravity = None if not gravity else gravity
        self._temperature = 0

        if not self._gravity:
            self._gravity = mass / pow(radius, 2)
        if not self._radius:
            self._radius = sqrt(mass / gravity)
        if not self._mass:
            self._mass = gravity * pow(radius, 2)

        self.set_qs(unit)
        if 'composition' in data and data['composition'] is not None:
            self.composition = {
                'water ice': data['composition'].get('water ice', 0),
                'silicates': data['composition'].get('silicates', 0),
                'iron': data['composition'].get('iron', 0),
                'helium': data['composition'].get('helium', 0),
                'hydrogen': data['composition'].get('hydrogen', 0),
            }

        self.atmosphere = {}
        self.albedo = q(data['albedo'])
        self.greenhouse = q(
            data['greenhouse']) if 'greenhouse' in data else q(1)
        self.clase = data['clase'] if 'clase' in data else self.set_class(
            self.mass, self.radius)
        self.tilt = data['tilt'] if 'tilt' in data else 0

        self.satellites = []

        # ID values make each planet unique, even if they have the same characteristics.
        now = ''.join([
            char for char in str(datetime.now())
            if char not in [' ', '.', ':', '-']
        ])
        self.id = data['id'] if 'id' in data else now

        self.system_id = data.get('system', None)
예제 #6
0
    def __truediv__(self, other):
        new_a = None
        if type(other) not in (float, Orbit):
            return NotImplemented()
        elif type(other) is float:
            new_a = q(self.semi_major_axis.m / other, self._unit)
        elif type(other) is Orbit:
            new_a = q(self.semi_major_axis.m / other.semi_major_axis.m,
                      self._unit)

        return new_a.m
예제 #7
0
    def elevate_changes(key, new_value):
        if key == 'Eccentricity':
            if new_value.m < 0.001:
                return q(0.001)
            elif new_value.m > 0.9999:
                return q(0.999)

        elif key == 'Inclination':
            if new_value.m < 0:
                return q(0, new_value.u)
            elif new_value.m > 180:
                return q(180, new_value.u)
예제 #8
0
    def __init__(self, primary, secondary, avgsep, ep=0, es=0, id=None, name=None):
        super().__init__(name, primary, secondary, avgsep, ep, es, id=id)

        assert 0.4 <= ep <= 0.7, 'Primary eccentricity must be between 0.4 and 0.7'
        max_sep_p, min_sep_p = self.calculate_distances(ep, self.average_separation.m)

        assert 0.4 <= es <= 0.7, 'Secondary eccentricity must be between 0.4 and 0.7'
        max_sep_s, min_sep_s = self.calculate_distances(es, self.average_separation.m)

        self.max_sep = max_sep_p + max_sep_s
        self.min_sep = min_sep_p + min_sep_s

        self.inner_forbbiden_zone = q(self.min_sep.m / 3, 'au')
        self.outer_forbbiden_zone = q(self.max_sep.m * 3, 'au')
예제 #9
0
 def update(self):
     self.reset_power()
     if hasattr(self.value, '__round__') and self.unit is not None:
         if self.parent.do_round:
             value = q(add_decimal(str(round(self.value, 3))), self.unit)
         else:
             value = q(add_decimal(str(self.value)), self.unit)
         if self.unit != 'year':
             value = '{:~}'.format(value)
         value = str(value)
     else:
         value = str(self.value)
     self.image = self.f.render(value, True, self.fg, self.bg)
     self.rect = self.image.get_rect(topleft=self.rect.topleft)
예제 #10
0
    def set_qs(self, unit):
        m = unit + '_mass'
        r = unit + '_radius'

        self.mass = q(self._mass, m)
        self.radius = q(self._radius, r)
        self.gravity = q(self._gravity, unit + '_gravity')
        self.density = self.calculate_density(self.mass.to('grams'),
                                              self.radius.to('centimeters'))
        self.volume = self.calculate_volume(self.radius.to('kilometers'))
        self.surface = self.calculate_surface_area(
            self.radius.to('kilometers'))
        self.circumference = self.calculate_circumference(
            self.radius.to('kilometers'))
        self.escape_velocity = q(sqrt(self.mass.m / self.radius.m),
                                 unit + '_escape_velocity')
예제 #11
0
def temp_by_lat(lat) -> q:
    """Devuelve la temperatura media relativa a la latitud seleccionada
    
    :rtype: q
    """
    if type(lat) is q:
        lat = lat.m

    if lat > 90:
        lat -= 90
    elif lat < 0:
        lat = abs(lat)

    temp = None
    if 0 <= lat <= 10:
        temp = -(5 * lat / 9) + 33

    elif 11 <= lat <= 37:
        temp = -(9 * lat / 26) + 31

    elif 38 <= lat <= 60:
        temp = -(17 * lat / 24) + 44

    elif 61 <= lat <= 75:
        a = ((lat / 60) - 3)
        b = (lat - 60)
        temp = a * b if b != 0 else 0.0

    elif 76 <= lat <= 90:
        temp = -lat + 45

    if temp is not None:
        return q(round(temp, 2), 'celsius')
    else:
        raise ValueError('La latitud "{}" no es válida'.format(lat))
예제 #12
0
 def set_hill_sphere(self):
     a = self.orbit.semi_major_axis.to('au').magnitude
     mp = self.mass.to('earth_mass').magnitude
     ms = self.orbit.star.mass.to('sol_mass').magnitude
     # "star" is actually the planet in this case
     return q(round((a * pow(mp / ms, 1 / 3)), 3),
              'earth_hill_sphere').to('earth_radius')
예제 #13
0
def set_orbital_properties(inclination):
    if inclination in (0, 180):
        return q(0, 'degree'), 'undefined'
    else:
        values = rotation_loop()
        Renderer.reset()
        return values
예제 #14
0
 def show_mass(self):
     try:
         mass = Systems.get_current().get_available_mass()
     except AttributeError:
         mass = q(0, 'jupiter_mass')
     if not self.show_jovian_mass:
         mass = mass.to('earth_mass')
     attr = '{:,g~}'.format((round(mass, 4)))
     return attr
예제 #15
0
    def set_roche(self, obj_density):
        density = self.density.to('earth_density').m
        radius = self.get_radius().to('earth_radius').m

        roches = q(round(2.44 * radius * pow(density / obj_density, 1 / 3), 3),
                   'earth_radius')
        if self.roches_limit == 0 or roches < self.roches_limit:
            self.roches_limit = roches
        return self.roches_limit
예제 #16
0
    def create_ring(self, asteroid):
        mass = asteroid.mass.to('ring_mass').m
        density = asteroid.density.to('earth_density').m
        vol = mass / density

        outer_limit = self.roches_limit.to('km')
        inner_limit = q(self._radius + 10000, 'km')
        # "10K" debería ser seteado por el Atmosphere Panel, porque es el fin de la atmósfera.
        wideness = outer_limit - inner_limit

        ro = outer_limit.to('earth_radius').m
        ri = inner_limit.to('earth_radius').m
        ra = pow((vol / (4 / 3 * pi)), 3)

        thickness = q(4 / 3 * (pow(ra, 3) / (pow(ro, 2) - pow(ri, 2))),
                      'km').to('m')

        return Ring(self, inner_limit, outer_limit, wideness, thickness)
예제 #17
0
 def set_qs(self):
     self.mass = q(self._mass.m, 'sol_mass')
     self.luminosity = q(self._luminosity.m, 'sol_luminosity')
     self.habitable_inner = q(self._habitable_inner, 'au')
     self.habitable_outer = q(self._habitable_outer, 'au')
     self.inner_boundry = q(self._inner_boundry, 'au')
     self.outer_boundry = q(self._outer_boundry, 'au')
     self.frost_line = q(self._frost_line, 'au')
예제 #18
0
    def set_loaded_orbits(self):
        for orbit_data in self._loaded_orbits:
            a = q(orbit_data['a'], 'au')
            if 'e' not in orbit_data:
                self.add_orbit_marker(a)
            else:
                e = q(orbit_data['e'])
                i = q(orbit_data['i'], 'degree')
                system = Systems.get_system_by_id(orbit_data['star_id'])
                planet = system.get_astrobody_by(orbit_data['astrobody'],
                                                 tag_type='id')
                star = system.star_system
                planet.set_orbit(star, [a, e, i])
                self.add_orbit_marker(planet.orbit)
                self.planet_area.delete_objects(planet)

        # borrar las órbitas cargadas para evitar que se dupliquen.
        self.sort_markers()
        self._loaded_orbits.clear()
예제 #19
0
    def tune_value(self, delta):
        if not self.locked:
            self.increment = self.update_increment()
            self.increment *= delta

            if Systems.get_current_star().validate_orbit(self.value.m +
                                                         self.increment):
                self.value += q(self.increment, self.value.u)
                self.increment = 0
                self.parent.sort_markers()
예제 #20
0
    def fill(self, tos):
        for i, elemento in enumerate(self.relatives.widgets()):
            arg = self.relative_args[i]
            if self.parent.relative_mode:
                got_attr = getattr(self.current, arg)
            else:
                got_attr = getattr(self.current, arg).to(tos[arg])
            attr = q(str(round(got_attr.m, 5)),
                     got_attr.u) if type(got_attr) is not str else got_attr
            elemento.value = attr
            elemento.text_area.show()

        for i, elemento in enumerate(self.absolutes.widgets()):
            arg = self.absolute_args[i]
            got_attr = getattr(self.current, arg)
            attr = q(str(round(got_attr.m, 3)),
                     got_attr.u) if type(got_attr) is not str else got_attr
            elemento.value = attr
            elemento.text_area.show()
        self.has_values = True
예제 #21
0
def from_stellar_resonance(star, planet, resonance: str):
    """Return the semi-major axis in AU of the resonant orbit.

    The resonance argument is a string in the form of 'x:y'
    where both x and y are integers and x >= y.
    """
    x, y = [int(i) for i in resonance.split(':')]
    period = (x / y) * planet.orbit.period.to('year').m
    semi_major_axis = q(
        pow(pow(period, 2) * star.mass.to('sol_mass').m, (1 / 3)), 'au')
    return semi_major_axis
예제 #22
0
 def calculate_density(ice, silicate, iron):
     comp = {
         'water ice': ice / 100,
         'silicates': silicate / 100,
         'iron': iron / 100
     }
     density = q(
         sum([
             comp[material] * material_densities[material]
             for material in comp
         ]), 'g/cm^3')
     return density
예제 #23
0
 def fill(self):
     parametros = []
     for elemento in self.properties.widgets():
         if elemento.text == 'Inclination':
             value = q(
                 0 if elemento.text_area.value == '' else
                 elemento.text_area.value, 'degree')
         elif elemento.text not in ['Orbital motion', 'Temperature']:
             value = q(elemento.text_area.value)
         else:
             value = 'au'
         parametros.append(value)
     main = self.parent.current
     orbit = self.linked_astrobody.set_orbit(main, parametros)
     self.linked_marker.orbit = orbit
     self.show()
     self.parent.planet_area.delete_objects(self.linked_astrobody)
     if hasattr(self.parent, 'recomendation'):
         self.parent.recomendation.hide()
     self.locked = True
     self.has_values = True
예제 #24
0
    def set_loaded_orbits(self):
        for orbit_data in self._loaded_orbits:
            a = q(orbit_data['a'], 'earth_radius')
            e = q(orbit_data['e'])
            i = q(orbit_data['i'], 'degree')
            system = Systems.get_system_by_id(orbit_data['star_id'])
            planet = system.get_astrobody_by(orbit_data['planet_id'],
                                             tag_type='id')
            if planet.id not in self.satellites:
                self.satellites[planet.id] = []

            if planet.id not in self._markers:
                self._markers[planet.id] = []
            satellite = system.get_astrobody_by(orbit_data['astrobody'],
                                                tag_type='id')
            self.satellites[planet.id].append(satellite)
            satellite.set_orbit(planet, [a, e, i])
            self.add_existing(satellite, planet.id)

        # borrar las órbitas cargadas para evitar que se dupliquen.
        self._loaded_orbits.clear()
예제 #25
0
def from_planetary_resonance(planet, satellite, resonance: str):
    """Return the semi-major axis in Re of the resonant orbit.

    The resonance argument is a string in the form of 'x:y'
    where both x and y are integers and x >= y.
    """

    x, y = [int(i) for i in resonance.split(':')]
    period = (x / y) * satellite.orbit.period.to('year').m
    mass = planet.mass.m + satellite.mass.m  # earth masses
    semi_major_axis = q(pow(pow(period, 2) * mass, (1 / 3)), 'au')
    return semi_major_axis.to('earth_radius')
예제 #26
0
def lagrange_three(sma, m_primary, m_secondary, ref='primary'):
    delta_a_limit, m_primary, m_secondary, sma, period_secondary = _lagrange(sma, m_primary, m_secondary)

    a = 1
    delta_a = 1000000000000
    while delta_a > delta_a_limit:
        condition = True
        while condition:
            b = _acc(3, a, m_primary, m_secondary, sma, period_secondary)
            c = _acc(3, a + delta_a, m_primary, m_secondary, sma, period_secondary)
            a = a + delta_a
            condition = abs(b) > abs(c)
        a = a - 2 * delta_a
        delta_a /= 10

    secondary_distance = -(a + sma)  # in meters
    primary_distance = a  # in meters
    assert ref == 'primary' or ref == 'secondary', 'Requested options are invalid'
    if ref == 'primary':
        return q(primary_distance, 'm')
    elif ref == 'secondary':
        return q(secondary_distance, 'm')
    def __init__(self, star_system):
        self.planets = []
        self.satellites = []
        self.asteroids = []
        self.astro_bodies = []
        self.star_system = star_system
        self.id = star_system.id
        self.body_mass = q(
            16 * exp(-0.6931 * star_system.mass.m) * 0.183391347289428,
            'jupiter_mass')

        self.aparent_brightness = {}
        self.average_visibility = {}
예제 #28
0
 def load_atmosphere(self, event):
     if 'Planets' in event.data and len(event.data['Planets']):
         atmosphere = event.data['Planets'][0]['atmosphere']
         elements = [e.symbol for e in self.elements.widgets()]
         for elem in atmosphere:
             if elem != 'pressure_at_sea_level':
                 idx = elements.index(elem)
                 element = self.elements.widgets()[idx]
                 element.percent.value = str(atmosphere[elem])
             else:
                 value = atmosphere[elem]['value']
                 unit = atmosphere[elem]['unit']
                 self.pressure = q(value, unit)
         self.pre_loaded = True
예제 #29
0
 def set_class(mass, radius):
     em = 'earth_mass'
     jm = 'jupiter_mass'
     jr = 'jupiter_radius'
     if q(0.0001, em) < mass < q(0.1, em) and radius > q(
             0.03, 'earth_radius'):
         return 'Dwarf Planet'
     elif q(10, em) < mass < q(13, jm):
         return 'Gas Giant'
     elif mass < q(2, jm) and radius > q(1, jr):
         return 'Puffy Giant'
     else:
         raise AssertionError("couldn't class the planet")
예제 #30
0
    def fill(self):
        tos = {'Mass': 'Me', 'Density': 'De', 'Volume': 'Ve'}

        for elemento in self.properties.get_widgets_from_layer(2):
            idx = self.properties.widgets().index(elemento)
            attr = self.relative_args[idx]

            if not self.parent.relative_mode:
                got_attr = getattr(self.current, attr)
            else:
                got_attr = getattr(self.current,
                                   attr).to(tos[elemento.text.capitalize()])
            attr = q(str(got_attr.m),
                     got_attr.u) if type(got_attr) is not str else got_attr
            elemento.value = attr
            if elemento.text_area.unit == 'earth_mass':
                elemento.do_round = False
            elemento.text_area.show()

        for elemento in self.properties.get_widgets_from_layer(3):
            name = elemento.text
            if ' ' in elemento.text:
                name = name.replace(' ', '_')
            got_attr = getattr(self.current, name.lower())
            attr = q(str(round(got_attr.m, 3)),
                     got_attr.u) if type(got_attr) is not str else got_attr
            elemento.value = attr
            elemento.text_area.show()

        for elemento in self.properties.get_widgets_from_layer(4):
            got_attr = self.current.composition.get(elemento.text.lower(), 0)
            attr = str(round(got_attr, 3)) + ' %'
            elemento.value = attr
            elemento.text_area.show()

        self.has_values = True