#include #include "fiko/dokum/gerilme.hpp" #include "fiko_test.hpp" using namespace fiko; using namespace fiko::dokum; namespace { // n³ kafes, [-1,1] AABB, tüm hücreler metal (Ic). VoxelKafes kafesYap(u32 n) { VoxelKafes k; Aabbd s; s.genislet({-1, -1, -1}); s.genislet({1, 1, 1}); k.kur(s, n, 0.0, 1.0); for (auto& t : k.tip) t = HucreTip::Ic; return k; } // Ṙ [°C/s] → SDAS [µm] (λ₂ = K·10⁶·Ṙ^(−⅓)) — çözücü örneklemesinin tersi. f64 sdasR(const Alasim& a, f64 R) { return a.sdasK * 1e6 * std::pow(R, -1.0 / 3.0); } KatilasmaSonuc katYap(u32 N, f64 ts, f64 sdas, f64 ny) { KatilasmaSonuc kat; kat.katilasmaSuresi.assign(N, ts); kat.sonSicaklik.assign(N, 300.0); kat.niyama.assign(N, ny); kat.sdas.assign(N, sdas); kat.hotSpotSure = ts; kat.hazir = true; return kat; } } // namespace FIKO_TEST(gerilme_yardimcilar) { const Alasim al = alasimAlSi7Mg(); // Lineer fs: T(fs)=615−fs·60 FIKO_KONTROL(std::abs(sicaklikFs(al, 0.5) - 585.0) < 0.01); FIKO_KONTROL(sicaklikFs(al, 0.0) == al.tLikidus); FIKO_KONTROL(sicaklikFs(al, 1.0) == al.tSolidus); // Ters-fonksiyon gidiş-dönüş (Scheil eğrisinde de monoton → bisection tutar). Alasim sc = al; sc.fsModel = FsModel::Scheil; FIKO_KONTROL(std::abs(sc.katiOran(sicaklikFs(sc, 0.7)) - 0.7) < 1e-6); // κ (Lineer): ΔT_v=(0.99−0.9)·60=5.4, ΔT_r=(0.9−0.4)·60=30 → 0.18. FIKO_KONTROL(std::abs(cscAlasimOrani(al) - 0.18) < 1e-6); // F = [1/u+2ln u−u] u:0.1→0.01 ≈ 85.4848 (kapalı form doğrulaması). FIKO_KONTROL(std::abs(rdgDrenajFaktoru() - 85.4848) < 0.01); // α likidus ailesi: Al 23e-6, GG 10e-6, çelik 12e-6. FIKO_KONTROL(termalGenlesme(alasimAlSi7Mg()) == 23e-6); FIKO_KONTROL(termalGenlesme(alasimGG25()) == 10e-6); FIKO_KONTROL(termalGenlesme(alasimCelik()) == 12e-6); } FIKO_TEST(gerilme_csc_monotonluk) { // Üç bant: hızlı soğuyan ince kesit (Ṙ=100) düşük, yavaş kalın (Ṙ=1) yüksek. const Alasim al = alasimAlSi7Mg(); const u32 n = 6; VoxelKafes k = kafesYap(n); const u32 N = k.hucreSayi(); KatilasmaSonuc kat = katYap(N, 0.0, 0.0, 1.0); const f64 R[3] = {100.0, 10.0, 1.0}, ts[3] = {1.0, 10.0, 100.0}; for (u32 kk = 0; kk < n; ++kk) for (u32 j = 0; j < n; ++j) for (u32 i = 0; i < n; ++i) { const u32 b = i / 2; // i∈{0,1}→hızlı, {2,3}→orta, {4,5}→yavaş const u32 idx = k.indeks(i, j, kk); kat.katilasmaSuresi[idx] = ts[b]; kat.sdas[idx] = sdasR(al, R[b]); } kat.hotSpotSure = 100.0; const GerilmeSonuc g = gerilmeHesapla(k, kat, al); FIKO_KONTROL(g.hazir); const f32 hizli = g.csc[k.indeks(0, 2, 2)]; const f32 orta = g.csc[k.indeks(2, 2, 2)]; const f32 yavas = g.csc[k.indeks(5, 2, 2)]; FIKO_KONTROL(hizli > 0.0f); FIKO_KONTROL(yavas > orta && orta > hizli); // monotonluk: Ṙ ↓ → CSC ↑ FIKO_KONTROL(std::abs(yavas / hizli - 100.0f) < 0.5f); // t_v oranı = Ṙ oranı // Üniform blok: t_v/medyan=1 → alan her yerde alaşım κ'sı. KatilasmaSonuc uni = katYap(N, 10.0, sdasR(al, 5.0), 1.0); const GerilmeSonuc gu = gerilmeHesapla(k, uni, al); const f32 kappa = (f32)cscAlasimOrani(al); for (u32 i = 0; i < N; ++i) FIKO_KONTROL(std::abs(gu.csc[i] - kappa) < 1e-3f); } FIKO_TEST(gerilme_rdg_pozitif_sinirli) { // Chill rampası (ts=10·i) → gerinim vekili >0; düşük Niyama → yüksek HCS. const Alasim al = alasimAlSi7Mg(); const u32 n = 6; VoxelKafes k = kafesYap(n); const u32 N = k.hucreSayi(); KatilasmaSonuc kat = katYap(N, 0.0, sdasR(al, 10.0), 2.0); for (u32 kk = 0; kk < n; ++kk) for (u32 j = 0; j < n; ++j) for (u32 i = 0; i < n; ++i) kat.katilasmaSuresi[k.indeks(i, j, kk)] = 10.0 * i; kat.hotSpotSure = 10.0 * (n - 1); const u32 dusukNy = k.indeks(2, 2, 2), yuksekNy = k.indeks(3, 2, 2); kat.niyama[dusukNy] = 0.2; // kötü besleme — komşusuyla aynı gecikmede const GerilmeSonuc g = gerilmeHesapla(k, kat, al); FIKO_KONTROL(g.hazir); const GerilmeAyar ay; const f64 ust = termalGenlesme(al) * (al.tLikidus - al.tSolidus) * rdgDrenajFaktoru() / ay.nyMinOran; // gecikme≤1 üst sınırı u32 pozitif = 0; for (u32 i = 0; i < N; ++i) { if (g.rdg[i] == kKatmanGecersiz) continue; FIKO_KONTROL(std::isfinite(g.rdg[i])); FIKO_KONTROL(g.rdg[i] >= 0.0f && g.rdg[i] <= (f32)ust); if (g.rdg[i] > 0.0f) ++pozitif; } FIKO_KONTROL(pozitif > 0); FIKO_KONTROL(g.rdg[dusukNy] > 5.0f * g.rdg[yuksekNy]); // Ny 10× düşük → ~10× } FIKO_TEST(gerilme_carpilma_uniform_vs_chill) { // Üniform soğuyan blok ~0; chill'li asimetrik soğuma yüksek + sapma > 0. const Alasim al = alasimAlSi7Mg(); const u32 n = 6; VoxelKafes k = kafesYap(n); const u32 N = k.hucreSayi(); const KatilasmaSonuc uni = katYap(N, 50.0, sdasR(al, 5.0), 1.0); const GerilmeSonuc gu = gerilmeHesapla(k, uni, al); FIKO_KONTROL(gu.hazir); for (u32 i = 0; i < N; ++i) FIKO_KONTROL(gu.carpilma[i] == 0.0f); FIKO_KONTROL(gu.maksSapmaMm == 0.0); KatilasmaSonuc chill = katYap(N, 0.0, sdasR(al, 5.0), 1.0); for (u32 kk = 0; kk < n; ++kk) for (u32 j = 0; j < n; ++j) for (u32 i = 0; i < n; ++i) chill.katilasmaSuresi[k.indeks(i, j, kk)] = 10.0 * i; // x=0 chill chill.hotSpotSure = 10.0 * (n - 1); const GerilmeSonuc gc = gerilmeHesapla(k, chill, al); FIKO_KONTROL(gc.hazir); const u32 ic = k.indeks(2, 2, 2); FIKO_KONTROL(gc.carpilma[ic] > 0.0f); FIKO_KONTROL(gc.carpilma[ic] > gu.carpilma[ic]); FIKO_KONTROL(gc.maksSapmaMm > 0.0); // Beklenen ölçek: α·(T_sol−25)·(10/50) — komşu farkı 10 s / t_maks 50 s. const f64 beklenen = termalGenlesme(al) * (al.tSolidus - 25.0) * 0.2; FIKO_KONTROL(std::abs(gc.carpilma[ic] - (f32)beklenen) < 1e-6f); } FIKO_TEST(gerilme_bos_giris_cokmez) { const Alasim al = alasimAlSi7Mg(); VoxelKafes bos; FIKO_KONTROL(!gerilmeHesapla(bos, {}, al).hazir); VoxelKafes k = kafesYap(4); const u32 N = k.hucreSayi(); FIKO_KONTROL(!gerilmeHesapla(k, {}, al).hazir); // kat.hazir=false KatilasmaSonuc bozuk = katYap(N, 1.0, 30.0, 1.0); bozuk.niyama.resize(3); // boyut uyumsuz FIKO_KONTROL(!gerilmeHesapla(k, bozuk, al).hazir); Alasim otektik = al; // donma aralığı yok → pencere kurulamaz otektik.tSolidus = otektik.tLikidus; FIKO_KONTROL(!gerilmeHesapla(k, katYap(N, 1.0, 30.0, 1.0), otektik).hazir); } FIKO_TEST(gerilme_katman_entegrasyonu) { // sonuc_katmanlari jenerik dropdown kontratı: 3 yeni katman + rozetler. const Alasim al = alasimAlSi7Mg(); const u32 n = 4; VoxelKafes k = kafesYap(n); const u32 N = k.hucreSayi(); k.fs.assign(N, 1.0); KatilasmaSonuc kat = katYap(N, 0.0, sdasR(al, 5.0), 1.0); for (u32 i = 0; i < N; ++i) kat.katilasmaSuresi[i] = (f64)i; kat.hotSpotSure = (f64)(N - 1); const SonucKatmanlari s = katmanlariHesapla(k, kat, nullptr, al); FIKO_KONTROL(s.hazir); const KatmanBilgi* csc = s.bul("Sıcak Yırtılma (CSC)"); const KatmanBilgi* rdg = s.bul("Sıcak Yırtılma (RDG)≈"); const KatmanBilgi* carp = s.bul("Çarpılma Riski≈"); FIKO_KONTROL(csc && rdg && carp); FIKO_KONTROL(!csc->yaklasik && rdg->yaklasik && carp->yaklasik); FIKO_KONTROL(csc->alan.size() == N && rdg->alan.size() == N && carp->alan.size() == N); FIKO_KONTROL(csc->kaynak == KatmanKaynak::Katilasma); FIKO_KONTROL(carp->aciklama.find("mm") != std::string::npos); // sapma notu FIKO_KONTROL(csc->min <= csc->maks); }