From de08e7d87d5d0d4e9edd4943c7b07adcc479c311 Mon Sep 17 00:00:00 2001 From: Tangent Fox Date: Mon, 1 Oct 2018 09:12:32 -0700 Subject: [PATCH] v1 --- Fluid.lua | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Fluid.moon | 77 ++++++++++++++++++++++++++++++++++++ test.lua | 65 +++++++++++++++++++++++++++++++ test.moon | 42 ++++++++++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 Fluid.lua create mode 100644 Fluid.moon create mode 100644 test.lua create mode 100644 test.moon diff --git a/Fluid.lua b/Fluid.lua new file mode 100644 index 0000000..ea1963a --- /dev/null +++ b/Fluid.lua @@ -0,0 +1,112 @@ +local Fluid +do + local _class_0 + local _base_0 = { + update = function(self, dt) + local leak = 0 + local _list_0 = self.breaches + for _index_0 = 1, #_list_0 do + local breach = _list_0[_index_0] + local rate = (self.pressure - breach.pressure) * (breach.size / self.volume) * dt + leak = leak + rate + breach.pressure = breach.pressure + (rate * (self.volume / breach.volume)) + if breach.pressure < 0 then + breach.pressure = 0 + end + local amount = breach.pressure * breach.volume + local modifier = 1 - self.volume * rate / amount + for item, percentage in pairs(breach.contents) do + breach.contents[item] = percentage * modifier + end + for item, percentage in pairs(self.contents) do + percentage = (self.volume * rate * percentage) / amount + if breach.contents[item] then + breach.contents[item] = breach.contents[item] + percentage + else + breach.contents[item] = percentage + end + end + end + self.pressure = self.pressure - leak + for i = 1, #self.breaches do + if self.breaches[i].pressure > self.pressure then + local other = table.remove(self.breaches, i) + other:breach(self, other.size) + i = i - 1 + end + end + end, + amount = function(self, key) + if key then + if self.contents[key] then + return self.volume * self.pressure * self.contents[key] + else + return 0 + end + else + return self.volume * self.pressure + end + end, + remove = function(self, key, amount) + if amount == nil then + amount = 1 + end + local total = self:amount(key) + if total >= amount then + local percentage = amount / total + self.contents[key] = self.contents[key] - (self.contents[key] * percentage) + percentage = amount / self:amount() + self.pressure = self.pressure - (self.pressure * percentage) + for item, p in pairs(self.contents) do + self.contents[item] = self.contents[item] + (p * percentage) + end + return true + else + return false + end + end, + breach = function(self, other, size) + if other.pressure > self.pressure then + return other:breach(self, size) + else + other.size = size or 1 + return table.insert(self.breaches, other) + end + end, + print = function(self) + print("Volume", self.volume, "Pressure", self.pressure, "#", self:amount()) + local percentage, amount = 0, 0 + for k, v in pairs(self.contents) do + local x = self:amount(k) + print(k, v, x) + percentage = percentage + v + amount = amount + x + end + return print("", "Total:", percentage, amount) + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, opts) + if opts == nil then + opts = { } + end + self.volume = opts.volume or 1 + self.pressure = opts.pressure or 1 + self.contents = opts.contents or { } + self.breaches = { } + end, + __base = _base_0, + __name = "Fluid" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Fluid = _class_0 + return _class_0 +end diff --git a/Fluid.moon b/Fluid.moon new file mode 100644 index 0000000..9ed2c84 --- /dev/null +++ b/Fluid.moon @@ -0,0 +1,77 @@ +-- it is up to user to ensure that total breached volume is lower +-- than the total volume +class Fluid + new: (opts={}) => + @volume = opts.volume or 1 + @pressure = opts.pressure or 1 + @contents = opts.contents or {} + -- breaches stored on high pressure side of Fluids + @breaches = {} + + update: (dt) => + leak = 0 -- total leak rate (pressure) + for breach in *@breaches + -- difference in pressure * relative size of hole + rate = (@pressure - breach.pressure) * (breach.size / @volume) * dt + leak += rate + breach.pressure += rate * (@volume / breach.volume) + breach.pressure = 0 if breach.pressure < 0 + amount = breach.pressure * breach.volume + + modifier = 1 - @volume * rate / amount + for item, percentage in pairs breach.contents + breach.contents[item] = percentage * modifier + + for item, percentage in pairs @contents + percentage = (@volume * rate * percentage) / amount + if breach.contents[item] + breach.contents[item] += percentage + else + breach.contents[item] = percentage + + @pressure -= leak + + for i = 1, #@breaches + if @breaches[i].pressure > @pressure + other = table.remove @breaches, i + other\breach(@, other.size) + i -= 1 + + amount: (key) => + if key + if @contents[key] + return @volume * @pressure * @contents[key] + else + return 0 + else + return @volume * @pressure + + remove: (key, amount=1) => + total = @amount key + if total >= amount + percentage = amount / total + @contents[key] -= @contents[key] * percentage + percentage = amount / @amount! + @pressure -= @pressure * percentage + for item, p in pairs @contents + @contents[item] += p * percentage + return true + else + return false + + breach: (other, size) => + if other.pressure > @pressure + other\breach(@, size) + else + other.size = size or 1 + table.insert @breaches, other + + print: => + print "Volume", @volume, "Pressure", @pressure, "#", @amount! + percentage, amount = 0, 0 + for k,v in pairs @contents + x = @amount k + print k, v, x + percentage += v + amount += x + print "", "Total:", percentage, amount diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..cf4aeac --- /dev/null +++ b/test.lua @@ -0,0 +1,65 @@ +local Fluid = require("Fluid") +local copy +copy = function(tab) + local new = { } + for k, v in pairs(tab) do + new[k] = v + end + return new +end +local air = { + nitrogen = 0.775, + oxygen = 0.21, + argon = 0.01, + co2 = 0.005 +} +local A = Fluid({ + volume = 32, + pressure = 12, + contents = copy(air) +}) +local B = Fluid({ + volume = 1100, + pressure = 2, + contents = { + hydrogen = 0.9, + helium = 0.1 + } +}) +A:print() +B:print() +A:breach(B, 5) +A:update(1) +B:update(1) +A:print() +B:print() +print("...") +local Air = Fluid({ + volume = 1000, + pressure = 1, + contents = copy(air) +}) +local Vacuum = Fluid({ + volume = math.huge, + pressure = 0 +}) +Air:breach(Vacuum) +for i = 1, 10 do + Air:print() + Air:update(i) +end +print("...") +Air = Fluid({ + volume = 1000, + pressure = 1, + contents = copy(air) +}) +Air:print() +local half = Air:amount("oxygen") / 2 +print("Removing half the oxygen (" .. tostring(half) .. ").") +Air:remove("oxygen", half) +Air:print() +local full = Air:amount("oxygen") +print("Removing the rest (" .. tostring(full) .. ").") +Air:remove("oxygen", full) +return Air:print() diff --git a/test.moon b/test.moon new file mode 100644 index 0000000..43fbbfc --- /dev/null +++ b/test.moon @@ -0,0 +1,42 @@ +Fluid = require "Fluid" + +copy = (tab) -> + new = {} + for k,v in pairs tab + new[k] = v + return new + +air = { nitrogen: 0.775, oxygen: 0.21, argon: 0.01, co2: 0.005 } + +A = Fluid volume: 32, pressure: 12, contents: copy air +B = Fluid volume: 1100, pressure: 2, contents: { hydrogen: 0.9, helium: 0.1 } +A\print! +B\print! +A\breach(B, 5) +A\update 1 +B\update 1 +A\print! +B\print! + +print "..." + +Air = Fluid volume: 1000, pressure: 1, contents: copy air +Vacuum = Fluid volume: math.huge, pressure: 0 + +Air\breach Vacuum +for i = 1, 10 + Air\print! + Air\update i + +print "..." + +Air = Fluid volume: 1000, pressure: 1, contents: copy air +Air\print! +half = Air\amount("oxygen") / 2 +print "Removing half the oxygen (#{half})." +Air\remove "oxygen", half +Air\print! +full = Air\amount "oxygen" +print "Removing the rest (#{full})." +Air\remove "oxygen", full +Air\print!