Tangent Fox 5 years ago
commit
de08e7d87d
4 changed files with 296 additions and 0 deletions
  1. 112
    0
      Fluid.lua
  2. 77
    0
      Fluid.moon
  3. 65
    0
      test.lua
  4. 42
    0
      test.moon

+ 112
- 0
Fluid.lua View File

@@ -0,0 +1,112 @@
1
+local Fluid
2
+do
3
+  local _class_0
4
+  local _base_0 = {
5
+    update = function(self, dt)
6
+      local leak = 0
7
+      local _list_0 = self.breaches
8
+      for _index_0 = 1, #_list_0 do
9
+        local breach = _list_0[_index_0]
10
+        local rate = (self.pressure - breach.pressure) * (breach.size / self.volume) * dt
11
+        leak = leak + rate
12
+        breach.pressure = breach.pressure + (rate * (self.volume / breach.volume))
13
+        if breach.pressure < 0 then
14
+          breach.pressure = 0
15
+        end
16
+        local amount = breach.pressure * breach.volume
17
+        local modifier = 1 - self.volume * rate / amount
18
+        for item, percentage in pairs(breach.contents) do
19
+          breach.contents[item] = percentage * modifier
20
+        end
21
+        for item, percentage in pairs(self.contents) do
22
+          percentage = (self.volume * rate * percentage) / amount
23
+          if breach.contents[item] then
24
+            breach.contents[item] = breach.contents[item] + percentage
25
+          else
26
+            breach.contents[item] = percentage
27
+          end
28
+        end
29
+      end
30
+      self.pressure = self.pressure - leak
31
+      for i = 1, #self.breaches do
32
+        if self.breaches[i].pressure > self.pressure then
33
+          local other = table.remove(self.breaches, i)
34
+          other:breach(self, other.size)
35
+          i = i - 1
36
+        end
37
+      end
38
+    end,
39
+    amount = function(self, key)
40
+      if key then
41
+        if self.contents[key] then
42
+          return self.volume * self.pressure * self.contents[key]
43
+        else
44
+          return 0
45
+        end
46
+      else
47
+        return self.volume * self.pressure
48
+      end
49
+    end,
50
+    remove = function(self, key, amount)
51
+      if amount == nil then
52
+        amount = 1
53
+      end
54
+      local total = self:amount(key)
55
+      if total >= amount then
56
+        local percentage = amount / total
57
+        self.contents[key] = self.contents[key] - (self.contents[key] * percentage)
58
+        percentage = amount / self:amount()
59
+        self.pressure = self.pressure - (self.pressure * percentage)
60
+        for item, p in pairs(self.contents) do
61
+          self.contents[item] = self.contents[item] + (p * percentage)
62
+        end
63
+        return true
64
+      else
65
+        return false
66
+      end
67
+    end,
68
+    breach = function(self, other, size)
69
+      if other.pressure > self.pressure then
70
+        return other:breach(self, size)
71
+      else
72
+        other.size = size or 1
73
+        return table.insert(self.breaches, other)
74
+      end
75
+    end,
76
+    print = function(self)
77
+      print("Volume", self.volume, "Pressure", self.pressure, "#", self:amount())
78
+      local percentage, amount = 0, 0
79
+      for k, v in pairs(self.contents) do
80
+        local x = self:amount(k)
81
+        print(k, v, x)
82
+        percentage = percentage + v
83
+        amount = amount + x
84
+      end
85
+      return print("", "Total:", percentage, amount)
86
+    end
87
+  }
88
+  _base_0.__index = _base_0
89
+  _class_0 = setmetatable({
90
+    __init = function(self, opts)
91
+      if opts == nil then
92
+        opts = { }
93
+      end
94
+      self.volume = opts.volume or 1
95
+      self.pressure = opts.pressure or 1
96
+      self.contents = opts.contents or { }
97
+      self.breaches = { }
98
+    end,
99
+    __base = _base_0,
100
+    __name = "Fluid"
101
+  }, {
102
+    __index = _base_0,
103
+    __call = function(cls, ...)
104
+      local _self_0 = setmetatable({}, _base_0)
105
+      cls.__init(_self_0, ...)
106
+      return _self_0
107
+    end
108
+  })
109
+  _base_0.__class = _class_0
110
+  Fluid = _class_0
111
+  return _class_0
112
+end

+ 77
- 0
Fluid.moon View File

@@ -0,0 +1,77 @@
1
+-- it is up to user to ensure that total breached volume is lower
2
+--  than the total volume
3
+class Fluid
4
+  new: (opts={}) =>
5
+    @volume = opts.volume or 1
6
+    @pressure = opts.pressure or 1
7
+    @contents = opts.contents or {}
8
+    -- breaches stored on high pressure side of Fluids
9
+    @breaches = {}
10
+
11
+  update: (dt) =>
12
+    leak = 0 -- total leak rate (pressure)
13
+    for breach in *@breaches
14
+      -- difference in pressure * relative size of hole
15
+      rate = (@pressure - breach.pressure) * (breach.size / @volume) * dt
16
+      leak += rate
17
+      breach.pressure += rate * (@volume / breach.volume)
18
+      breach.pressure = 0 if breach.pressure < 0
19
+      amount = breach.pressure * breach.volume
20
+
21
+      modifier = 1 - @volume * rate / amount
22
+      for item, percentage in pairs breach.contents
23
+        breach.contents[item] = percentage * modifier
24
+
25
+      for item, percentage in pairs @contents
26
+        percentage = (@volume * rate * percentage) / amount
27
+        if breach.contents[item]
28
+          breach.contents[item] += percentage
29
+        else
30
+          breach.contents[item] = percentage
31
+
32
+    @pressure -= leak
33
+
34
+    for i = 1, #@breaches
35
+      if @breaches[i].pressure > @pressure
36
+        other = table.remove @breaches, i
37
+        other\breach(@, other.size)
38
+        i -= 1
39
+
40
+  amount: (key) =>
41
+    if key
42
+      if @contents[key]
43
+        return @volume * @pressure * @contents[key]
44
+      else
45
+        return 0
46
+    else
47
+      return @volume * @pressure
48
+
49
+  remove: (key, amount=1) =>
50
+    total = @amount key
51
+    if total >= amount
52
+      percentage = amount / total
53
+      @contents[key] -= @contents[key] * percentage
54
+      percentage = amount / @amount!
55
+      @pressure -= @pressure * percentage
56
+      for item, p in pairs @contents
57
+        @contents[item] += p * percentage
58
+      return true
59
+    else
60
+      return false
61
+
62
+  breach: (other, size) =>
63
+    if other.pressure > @pressure
64
+      other\breach(@, size)
65
+    else
66
+      other.size = size or 1
67
+      table.insert @breaches, other
68
+
69
+  print: =>
70
+    print "Volume", @volume, "Pressure", @pressure, "#", @amount!
71
+    percentage, amount = 0, 0
72
+    for k,v in pairs @contents
73
+      x = @amount k
74
+      print k, v, x
75
+      percentage += v
76
+      amount += x
77
+    print "", "Total:", percentage, amount

+ 65
- 0
test.lua View File

@@ -0,0 +1,65 @@
1
+local Fluid = require("Fluid")
2
+local copy
3
+copy = function(tab)
4
+  local new = { }
5
+  for k, v in pairs(tab) do
6
+    new[k] = v
7
+  end
8
+  return new
9
+end
10
+local air = {
11
+  nitrogen = 0.775,
12
+  oxygen = 0.21,
13
+  argon = 0.01,
14
+  co2 = 0.005
15
+}
16
+local A = Fluid({
17
+  volume = 32,
18
+  pressure = 12,
19
+  contents = copy(air)
20
+})
21
+local B = Fluid({
22
+  volume = 1100,
23
+  pressure = 2,
24
+  contents = {
25
+    hydrogen = 0.9,
26
+    helium = 0.1
27
+  }
28
+})
29
+A:print()
30
+B:print()
31
+A:breach(B, 5)
32
+A:update(1)
33
+B:update(1)
34
+A:print()
35
+B:print()
36
+print("...")
37
+local Air = Fluid({
38
+  volume = 1000,
39
+  pressure = 1,
40
+  contents = copy(air)
41
+})
42
+local Vacuum = Fluid({
43
+  volume = math.huge,
44
+  pressure = 0
45
+})
46
+Air:breach(Vacuum)
47
+for i = 1, 10 do
48
+  Air:print()
49
+  Air:update(i)
50
+end
51
+print("...")
52
+Air = Fluid({
53
+  volume = 1000,
54
+  pressure = 1,
55
+  contents = copy(air)
56
+})
57
+Air:print()
58
+local half = Air:amount("oxygen") / 2
59
+print("Removing half the oxygen (" .. tostring(half) .. ").")
60
+Air:remove("oxygen", half)
61
+Air:print()
62
+local full = Air:amount("oxygen")
63
+print("Removing the rest (" .. tostring(full) .. ").")
64
+Air:remove("oxygen", full)
65
+return Air:print()

+ 42
- 0
test.moon View File

@@ -0,0 +1,42 @@
1
+Fluid = require "Fluid"
2
+
3
+copy = (tab) ->
4
+  new = {}
5
+  for k,v in pairs tab
6
+    new[k] = v
7
+  return new
8
+
9
+air = { nitrogen: 0.775, oxygen: 0.21, argon: 0.01, co2: 0.005 }
10
+
11
+A = Fluid volume: 32, pressure: 12, contents: copy air
12
+B = Fluid volume: 1100, pressure: 2, contents: { hydrogen: 0.9, helium: 0.1 }
13
+A\print!
14
+B\print!
15
+A\breach(B, 5)
16
+A\update 1
17
+B\update 1
18
+A\print!
19
+B\print!
20
+
21
+print "..."
22
+
23
+Air = Fluid volume: 1000, pressure: 1, contents: copy air
24
+Vacuum = Fluid volume: math.huge, pressure: 0
25
+
26
+Air\breach Vacuum
27
+for i = 1, 10
28
+  Air\print!
29
+  Air\update i
30
+
31
+print "..."
32
+
33
+Air = Fluid volume: 1000, pressure: 1, contents: copy air
34
+Air\print!
35
+half = Air\amount("oxygen") / 2
36
+print "Removing half the oxygen (#{half})."
37
+Air\remove "oxygen", half
38
+Air\print!
39
+full = Air\amount "oxygen"
40
+print "Removing the rest (#{full})."
41
+Air\remove "oxygen", full
42
+Air\print!