File size: 14,351 Bytes
095dd0b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
import gradio as gr
import math

# ─────────────────────────────────────────────
#  CORE SCIENCE ENGINE
# ─────────────────────────────────────────────

STAR_TYPES = {
    "O": {"hz_min": 100, "hz_max": 200,  "uv_risk": 10,  "lifespan_gyr": 0.01},
    "B": {"hz_min": 50,  "hz_max": 100,  "uv_risk": 9,   "lifespan_gyr": 0.1},
    "A": {"hz_min": 15,  "hz_max": 40,   "uv_risk": 7,   "lifespan_gyr": 2},
    "F": {"hz_min": 1.5, "hz_max": 3.0,  "uv_risk": 5,   "lifespan_gyr": 4},
    "G": {"hz_min": 0.9, "hz_max": 1.5,  "uv_risk": 3,   "lifespan_gyr": 10},
    "K": {"hz_min": 0.3, "hz_max": 0.9,  "uv_risk": 2,   "lifespan_gyr": 30},
    "M": {"hz_min": 0.1, "hz_max": 0.3,  "uv_risk": 4,   "lifespan_gyr": 100},
}

def clamp(value, lo=0, hi=100):
    return max(lo, min(hi, value))

def analyze_planet(planet_name, radius_earth, mass_earth,
                   temperature_k, stellar_flux, star_type, orbital_period_days):

    star  = STAR_TYPES.get(star_type.upper(), STAR_TYPES["G"])
    risks = []

    # ── 1. GRAVITY SUITABILITY ──────────────────────────────
    # Simple approximation: g ∝ mass / radius²
    surface_gravity = mass_earth / (radius_earth ** 2)
    if 0.5 <= surface_gravity <= 2.0:
        gravity_score = 100
        gravity_label = "✅ Uygun (%.2fg)" % surface_gravity
    elif surface_gravity < 0.5:
        gravity_score = clamp(surface_gravity / 0.5 * 80)
        gravity_label = "⚠️ Düşük yerçekimi (%.2fg)" % surface_gravity
        risks.append("Düşük yerçekimi atmosfer kaybına yol açabilir.")
    elif surface_gravity <= 3.0:
        gravity_score = clamp(100 - (surface_gravity - 2.0) * 30)
        gravity_label = "⚠️ Yüksek yerçekimi (%.2fg)" % surface_gravity
        risks.append("Yüksek yerçekimi biyolojik yapıları zorlayabilir.")
    else:
        gravity_score = clamp(100 - (surface_gravity - 2.0) * 25)
        gravity_label = "❌ Aşırı yerçekimi (%.2fg)" % surface_gravity
        risks.append("Aşırı yerçekimi çok hücreli yaşamla uyumsuz olabilir.")

    # ── 2. TEMPERATURE & LIQUID WATER ───────────────────────
    LIQUID_MIN, LIQUID_MAX = 273, 373   # Kelvin (1 atm baseline)
    if LIQUID_MIN <= temperature_k <= LIQUID_MAX:
        temp_score  = 100
        water_label = "✅ Sıvı su mümkün (%d K)" % temperature_k
    elif temperature_k < 273:
        delta = 273 - temperature_k
        temp_score  = clamp(100 - delta * 1.2)
        water_label = "🧊 Donma riski (%d K)" % temperature_k
        risks.append("Sıcaklık donma noktasının altında – sıvı su kısıtlı.")
    else:
        delta = temperature_k - 373
        temp_score  = clamp(100 - delta * 1.5)
        water_label = "🔥 Kaynama riski (%d K)" % temperature_k
        risks.append("Yüksek sıcaklık yüzey suyunu buharlaştırabilir.")

    # ── 3. STELLAR FLUX & ATMOSPHERE STABILITY ──────────────
    # Earth baseline ≈ 1.0 S⊕
    if 0.5 <= stellar_flux <= 1.5:
        flux_score   = 100
        atm_label    = "✅ Kararlı enerji akısı (%.2f S⊕)" % stellar_flux
    elif stellar_flux < 0.5:
        flux_score   = clamp(stellar_flux / 0.5 * 80)
        atm_label    = "❄️ Düşük akı – buzul riski (%.2f S⊕)" % stellar_flux
        risks.append("Düşük yıldız akısı global donmaya neden olabilir.")
    elif stellar_flux <= 2.5:
        flux_score   = clamp(100 - (stellar_flux - 1.5) * 40)
        atm_label    = "☀️ Yüksek akı – ısınma riski (%.2f S⊕)" % stellar_flux
        risks.append("Venüs benzeri sera etkisi riski mevcut.")
    else:
        flux_score   = clamp(100 - (stellar_flux - 2.5) * 30)
        atm_label    = "🌋 Aşırı akı – sera etkisi (%.2f S⊕)" % stellar_flux
        risks.append("Yoğun atmosfer erozyonu ve radyasyon tehdidi.")

    # ── 4. RADIATION RISK ───────────────────────────────────
    uv_base = star["uv_risk"]
    # M dwarfları flare riski taşır
    if star_type.upper() == "M":
        risks.append("M cüce yıldızları sık güneş patlaması (flare) üretir – radyasyon dalgalanmaları.")
    if orbital_period_days < 10 and star_type.upper() in ("M", "K"):
        risks.append("Kısa orbital periyot: tidal kilitlenme (tidal locking) ihtimali yüksek.")

    radiation_score = clamp(100 - uv_base * 8)
    rad_label = {
        1: "✅ Minimum radyasyon", 2: "✅ Düşük radyasyon",
        3: "✅ Orta-düşük radyasyon", 4: "⚠️ Orta radyasyon",
        5: "⚠️ Yüksek radyasyon", 6: "❌ Tehlikeli radyasyon",
        7: "❌ Çok tehlikeli", 8: "❌ Ölümcül", 9: "☢️ Şiddetli",
        10: "☢️ Felaket seviyesi"
    }.get(uv_base, "⚠️ Bilinmeyen")

    # ── 5. SIZE SUITABILITY ──────────────────────────────────
    if 0.5 <= radius_earth <= 1.8:
        size_bonus = 10
    elif radius_earth < 0.5:
        size_bonus = -10
        risks.append("Çok küçük gezegen – atmosfer tutma kapasitesi sınırlı.")
    elif radius_earth <= 2.5:
        size_bonus = 0
    else:
        size_bonus = -15
        risks.append("Süper-Jüpiter veya mini-Neptün sınırında – kayalık yüzey olmayabilir.")

    # ── 6. ORBITAL PERIOD BONUS ─────────────────────────────
    hz_min = star["hz_min"]
    hz_max = star["hz_max"]
    orbital_au_approx = (orbital_period_days / 365.25) ** (2/3)
    if hz_min <= orbital_au_approx <= hz_max:
        orbital_bonus = 5
    else:
        orbital_bonus = -5
        risks.append("Yörünge yaşanabilir bölge (habitable zone) dışında görünüyor.")

    # ── COMPOSITE SCORES ────────────────────────────────────
    habitability_score = clamp(
        gravity_score * 0.25 +
        temp_score    * 0.35 +
        flux_score    * 0.20 +
        radiation_score * 0.20 +
        size_bonus + orbital_bonus
    )

    # Life probability: daha temkinli, logaritmik
    life_base = habitability_score
    star_life_factor = min(star["lifespan_gyr"] / 4.0, 2.5)   # evrim için zaman
    life_probability = clamp(life_base * 0.6 * min(star_life_factor, 1.5))

    # ── VERDICT ─────────────────────────────────────────────
    if habitability_score >= 70:
        verdict = "🟢 YAŞANABİLİR"
    elif habitability_score >= 40:
        verdict = "🟡 KISMİ (Koşullu)"
    else:
        verdict = "🔴 YAŞANAMAz"

    # ── FORMAT OUTPUT ───────────────────────────────────────
    explanation = build_explanation(
        planet_name, star_type, radius_earth, mass_earth,
        temperature_k, stellar_flux, orbital_period_days,
        surface_gravity, orbital_au_approx, star
    )

    output = f"""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🪐  PLANET: {planet_name.upper()}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

🌍  HABITABİLİTY SCORE   :  {habitability_score:.1f} / 100
👽  ALIEN LIFE PROBABILITY:  {life_probability:.1f} %

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊  ALT ANALİZ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  🌡️  Sıvı Su Potansiyeli  :  {water_label}
  🛡️  Atmosfer Kararlılığı :  {atm_label}
  ☢️  Radyasyon Riski      :  {rad_label}
  ⚖️  Yerçekimi Uygunluğu  :  {gravity_label}

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🧠  BİLİMSEL AÇIKLAMA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

{explanation}

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠️  RİSK FAKTÖRLERİ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

"""
    if risks:
        for r in risks:
            output += f"  • {r}\n"
    else:
        output += "  ✅ Kritik risk faktörü tespit edilmedi.\n"

    output += f"""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🌌  FINAL VERDICT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  {verdict}

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
"""
    return output


def build_explanation(name, star_type, radius, mass, temp, flux,
                      period, gravity, au, star):
    hz_mid = (star["hz_min"] + star["hz_max"]) / 2
    in_hz  = "yaşanabilir bölge içinde" if star["hz_min"] <= au <= star["hz_max"] \
              else "yaşanabilir bölge dışında"

    return (
        f"{name}, bir {star_type} tipi yıldızın yörüngesinde, "
        f"yaklaşık {au:.2f} AU uzaklıkta ({in_hz}) yer almaktadır. "
        f"Dünya'nın {radius:.2f} katı yarıçapı ve {mass:.2f} katı kütlesiyle "
        f"yüzey yerçekimi ~{gravity:.2f}g olarak hesaplanmıştır. "
        f"\n\n"
        f"Yüzey sıcaklığı {temp} K ({temp - 273:.0f}°C), "
        f"sıvı su koridoru (273–373 K) ile karşılaştırıldığında "
        f"{'bu aralık içindedir' if 273 <= temp <= 373 else 'bu aralığın dışındadır'}. "
        f"Yıldız akısı {flux:.2f} S⊕ olup Dünya referansına "
        f"({'yakın' if 0.7 <= flux <= 1.3 else 'görece uzak'}) düşmektedir. "
        f"\n\n"
        f"{star_type} tipi yıldızın tahmini ömrü ~{star['lifespan_gyr']:.0f} milyar yıldır; "
        f"{'bu, karmaşık yaşam evrimine yeterli zamanı temsil eder' if star['lifespan_gyr'] >= 4 else 'bu süre karmaşık yaşamın evrimleşmesi için yetersiz olabilir'}. "
        f"Orbital periyot {period:.1f} gün; "
        f"{'tidal kilitlenme olasılığı düşük' if period > 20 else 'kısa periyot tidal kilitlenmeye işaret edebilir'}."
    )


# ─────────────────────────────────────────────
#  GRADIO INTERFACE
# ─────────────────────────────────────────────

EXAMPLES = [
    ["Kepler-452b",  1.63, 3.0,  265, 1.10, "G", 385.0],
    ["TRAPPIST-1e",  0.92, 0.77, 251, 0.38, "M",  6.1],
    ["HD 40307g",    2.50, 8.0,  226, 0.40, "K", 197.8],
    ["Proxima Cen b",1.08, 1.27, 234, 0.65, "M", 11.2],
    ["55 Cancri f",  0.96, 0.14, 300, 0.47, "G", 260.7],
]

CSS = """
body { font-family: 'Courier New', monospace; }
.gradio-container { max-width: 960px; margin: auto; }
#title { text-align: center; }
"""

with gr.Blocks(title="🪐 Exoplanet Intelligence Engine") as demo:

    gr.Markdown(
        """
# 🪐 Exoplanet Intelligence Engine
### Gezegen verilerini gir — yaşanabilirliği keşfet.
> *Bilimsel tahmin motoru · Gerçek NASA verisi içermez · Fizik tabanlı sezgisel model*
        """,
        elem_id="title"
    )

    with gr.Row():
        with gr.Column(scale=1):
            planet_name      = gr.Textbox(label="🏷️ Gezegen Adı",      placeholder="ör. Kepler-452b", value="MyPlanet-X")
            radius_earth     = gr.Slider( label="📏 Yarıçap (R⊕)",      minimum=0.1, maximum=15.0, step=0.01, value=1.0)
            mass_earth       = gr.Slider( label="⚖️ Kütle (M⊕)",        minimum=0.01, maximum=30.0, step=0.01, value=1.0)
            temperature_k    = gr.Slider( label="🌡️ Yüzey Sıcaklığı (K)",minimum=50,  maximum=800,  step=1,    value=288)
            stellar_flux     = gr.Slider( label="☀️ Yıldız Akısı (S⊕)", minimum=0.01, maximum=10.0, step=0.01, value=1.0)
            star_type        = gr.Dropdown(label="⭐ Yıldız Tipi",
                                           choices=["O","B","A","F","G","K","M"],
                                           value="G")
            orbital_period   = gr.Slider( label="🔄 Orbital Periyot (gün)", minimum=1, maximum=1000, step=0.1, value=365.0)
            analyze_btn      = gr.Button("🔭 ANALİZ ET", variant="primary")

        with gr.Column(scale=2):
            output_box = gr.Textbox(
                label="📋 Analiz Raporu",
                lines=38,
                max_lines=60,
            )

    gr.Examples(
        examples=EXAMPLES,
        inputs=[planet_name, radius_earth, mass_earth,
                temperature_k, stellar_flux, star_type, orbital_period],
        label="🌌 Hazır Örnek Gezegenler"
    )

    analyze_btn.click(
        fn=analyze_planet,
        inputs=[planet_name, radius_earth, mass_earth,
                temperature_k, stellar_flux, star_type, orbital_period],
        outputs=output_box
    )

    gr.Markdown(
        """
---
**Model Notları:** Yerçekimi `g = M/R²` yaklaşımı kullanır.
Yaşanabilir bölge sınırları yıldız tipine göre değişir.
Radyasyon riski yıldız sınıfından türetilir.
Hayat olasılığı, habitability skoru ve yıldız ömrünün fonksiyonudur.
        """
    )


if __name__ == "__main__":
    demo.launch(css=CSS)