Advertisement
Guest User

Untitled

a guest
Jun 6th, 2024
396
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.61 KB | None | 0 0
  1. #!/usr/bin/python3
  2. # ----06-06-2024  5:37:06----
  3.  
  4. # Space nuke effects calculator
  5.  
  6. # kg m s J K
  7.  
  8. import math
  9. from collections import namedtuple
  10.  
  11. def MTtoJ(MT):
  12.     return 4.184e15 * MT
  13.  
  14. # radiant exposure, J/m^2 https://en.wikipedia.org/wiki/Radiant_exposure
  15. # energyMT is in units of MT TNT equivalent
  16. def radiantExposure(energyMT, radius):
  17.     return MTtoJ(energyMT) / (radius**2 *4*math.pi)
  18.  
  19. # kg/m^3, J/kg, K, J/kg, m, kg
  20. Armor = namedtuple("Armor", "name density energyToVaporize boilingPoint energyToMelt halvingDepth atomMass")
  21. iron = Armor("iron", 7874, 7.687e6, 3143, 937562, 0.0254, 9.27e-26)
  22. k_B = 1.380649e-23 # Boltzmann's constant, J/K
  23. armorList = [iron]
  24.  
  25. # J/kg at depth x is A 2^(-x/halvingDepth)
  26. # this function returns A (units of J/kg)
  27. def energyDistributionConstant(exposure, armor):
  28.     # integral_0^inf A 2^(-x/halvingDepth) density dx = exposure
  29.     # A*density*halvingDepth/ln(2) = exposure
  30.     return exposure * math.log(2) / (armor.density*armor.halvingDepth)
  31.  
  32. def vaporizationDepth(exposure, armor, A):
  33.     # A 2^(-x/halvingDepth) = energyToVaporize
  34.     # x = -halvingDepth * ln_2(energyToVaporize/A)
  35.     return armor.halvingDepth * math.log(A/armor.energyToVaporize, 2)
  36.  
  37. def meltingDepth(exposure, armor, A):
  38.     return armor.halvingDepth * math.log(A/armor.energyToMelt, 2)
  39.  
  40. # velocity of gas at depth x
  41. def gasVelocity(exposure, armor, x, A):
  42.     # excess energy per atom
  43.     E = (A * 2**(-x/armor.halvingDepth) - armor.energyToVaporize) * armor.atomMass
  44.     return math.sqrt((3*k_B*armor.boilingPoint + 2*E) / armor.atomMass)
  45.  
  46. def momentumImparted(energyMT, radius, armor, increment=0.0001):
  47.     exposure = radiantExposure(energyMT, radius)
  48.     A = energyDistributionConstant(exposure, armor)
  49.     d = vaporizationDepth(exposure, armor, A)
  50.     tot = 0
  51.     for i in range(int(d/increment) + 1):
  52.         x = increment*i
  53.         plateMass = 1 * 1 * increment * armor.density # 1x1xincrement cuboid (in meters)
  54.         momentum = gasVelocity(exposure, armor, x, A) * plateMass
  55.         tot += momentum
  56.     return tot
  57.  
  58. # https://www.icrp.org/docs/Hans%20Menzel%20Doses%20From%20Radiation%20Exposure.pdf
  59. # 450 pSv cm2 "per fluence" for 14 MeV neutrons
  60. # "per fluence" means per neutron, which has 2.243e-12 J
  61. # Converting to Sv / (J/m^2)
  62. SievertPerJm2 = 0.02
  63.  
  64. # humans are basically water, halving thickness of water is 18 cm
  65. # so we might estimate that 50% of the incident radiation is captured by the body
  66. # a 1m x 1m x 18cm plug weighs .18 * (density of water)
  67. # and takes .5*exposure energy
  68. GrayPerJm2 = .5 / (.18 * 997)
  69.  
  70. # There's a factor of 10 difference between SvPerJm2 and GrayPerJm2
  71. # Which is a problem since Gray and Sievert should be about equally lethal
  72. # SvPerJm2 was calculated from a medical datasheet for 14 MeV neutrons
  73. # GrayPerJm2 was back of the envelope
  74. # on the other hand the radiation is not entirely 14 MeV neutrons
  75.  
  76. ld50Gray = 5
  77. ld1Gray = 1
  78. ld50Sievert = 5
  79. ld1Sievert = 1
  80.  
  81. useGray = True
  82.  
  83. def lethalUnshieldedRadius(energyMT):
  84.     energy = MTtoJ(energyMT)
  85.     # GrayPerJm2 * energy / (radius**2 *4*math.pi) = ld50Gray
  86.     if useGray:
  87.         factor = GrayPerJm2 / ld50Gray
  88.     else:
  89.         factor = SievertPerJm2 / ld50Sievert
  90.     return math.sqrt(energy * factor / (4 * math.pi))
  91.  
  92. def shieldingNeededForRadiation(energyMT, radius, armor):
  93.     energy = MTtoJ(energyMT)
  94.     exposure = radiantExposure(energyMT, radius)
  95.     if useGray:
  96.         factor = GrayPerJm2 / ld1Gray
  97.     else:
  98.         factor = SievertPerJm2 / ld1Sievert
  99.     # exposure * 2^(-x / halvingDepth) * GrayPerJm2 = ld1Gray
  100.     # x = halvingDepth * log(GrayPerJm2 * exposure / ld1Gray, 2)
  101.     return armor.halvingDepth * math.log(factor * exposure, 2)
  102.  
  103. # J/kg
  104. TNTequivalent = 4.184e6
  105. TNTdensity = 1654 # kg/m^3
  106.  
  107. def summary(energyMT, radius, armor, armorThickness, shipDepth, shipDensity):
  108.     exposure = radiantExposure(energyMT, radius)
  109.     energy = MTtoJ(energyMT)
  110.     A = energyDistributionConstant(exposure, armor)
  111.     print("Exposure: {:e} J/m^2".format(exposure))
  112.     print("TNT equivalent: {:.0f} kg TNT per m^2".format(exposure/TNTequivalent))
  113.     print(" (like covering the hull with {:.2f} m of TNT)".format(exposure/(TNTequivalent * TNTdensity)))
  114.     vapDepthCm = vaporizationDepth(exposure, armor, A)*100
  115.     meltDepthCm = meltingDepth(exposure, armor, A)*100
  116.     print("Hull is vaporized to a depth of {:.2f} cm".format(vapDepthCm))
  117.     print(" and melted at depths between {:.2f} and {:.2f} cm".format(vapDepthCm, meltDepthCm))
  118.     momentum = momentumImparted(energyMT, radius, armor)
  119.     print("Each square meter of hull recoils with {:e} kg m/s of momentum".format(momentum))
  120.     print("The {:.2f} m of outer armor recoils at {:.2f} m/s".format(armorThickness, momentum/(armorThickness * armor.density)))
  121.     print("The ship as a whole recoils at {:.2f} m/s".format(momentum/(shipDepth * shipDensity)))
  122.     print("To protect humans from acute irradiation, the {} hull should be at least {:.2f} m thick".format(armor.name, shieldingNeededForRadiation(energyMT, radius, armor)))
  123.     print("An unshielded human would have 50% risk of dying at a radius of {:e} km".format(lethalUnshieldedRadius(energyMT) / 1000))
  124.  
  125. if __name__ == "__main__":
  126.     try:
  127.         energyMT = float(input("Nuke energy in MT (default 100 MT): "))
  128.     except:
  129.         energyMT = 100
  130.         print("Using default of 100 MT")
  131.     try:
  132.         radius = float(input("Distance from nuke to spaceship in meters (default 1000 m): "))
  133.     except:
  134.         radius = 1000
  135.         print("Using default of 1000 m")
  136.     if len(armorList) > 1:
  137.         armor = "iron"
  138.         try:
  139.             armorChoices = " ".join([a.name for a in armorList])
  140.             armor = input("Armor material (choices = " + armorChoices + "): ")
  141.         except:
  142.             pass
  143.         if not (armor in [a.name for a in armorList]):
  144.             print("Unrecognized armor; using iron")
  145.             armor = "iron"
  146.         armor = [a for a in armorList if a.name == armor][0]
  147.     else:
  148.         armor = iron
  149.     try:
  150.         armorThickness = float(input("Armor thickness in meters (default 1m): "))
  151.     except:
  152.         armorThickness = 1
  153.         print("Using default of 1 m")
  154.     try:
  155.         shipDepth = float(input("Depth of ship from blast side to opposite side in meters (default 100 m):"))
  156.     except:
  157.         shipDepth = 100
  158.         print("Using default of 100 m")
  159.     try:
  160.         shipDensity = float(input("Density of ship in kg/m^3 (default 500 kg/m^3):"))
  161.     except:
  162.         shipDensity = 500
  163.         print("Using default of 500 kg/m^3")
  164.        
  165.     summary(energyMT, radius, armor, armorThickness, shipDepth, shipDensity)
  166.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement