toji 1.6.8 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/example/calendar.ipynb +383 -0
- data/example/{schedule.yaml → calendar.yaml} +6 -30
- data/example/calendar_file.ipynb +338 -0
- data/example/example_core.rb +354 -0
- data/example/kake_ingredient.rb +26 -0
- data/example/{koji_recipe.rb → koji_ingredient.rb} +1 -2
- data/example/koji_making.ipynb +16 -15
- data/example/koji_making.rb +2 -1
- data/example/koji_making.yaml +10 -9
- data/example/koji_making_multi.ipynb +27 -61
- data/example/moromi.ipynb +25 -24
- data/example/moromi.rb +1 -0
- data/example/moromi.yaml +10 -4
- data/example/recipe.rb +75 -0
- data/example/shubo.ipynb +15 -14
- data/example/shubo.rb +2 -1
- data/example/shubo.yaml +12 -11
- data/lib/toji.rb +3 -1
- data/lib/toji/brew.rb +4 -3
- data/lib/toji/brew/base.rb +8 -92
- data/lib/toji/brew/builder.rb +77 -6
- data/lib/toji/brew/graph/bmd.rb +1 -2
- data/lib/toji/brew/graph/multi_progress.rb +0 -121
- data/lib/toji/brew/graph/progress.rb +17 -52
- data/lib/toji/brew/koji.rb +2 -11
- data/lib/toji/brew/moromi.rb +4 -37
- data/lib/toji/brew/shubo.rb +2 -6
- data/lib/toji/brew/state.rb +90 -103
- data/lib/toji/brew/wrapped_state.rb +136 -0
- data/lib/toji/calendar.rb +123 -0
- data/lib/toji/{schedule → calendar}/date_column.rb +3 -6
- data/lib/toji/{schedule → calendar}/date_row.rb +6 -6
- data/lib/toji/ingredient.rb +10 -0
- data/lib/toji/ingredient/kake.rb +17 -0
- data/lib/toji/ingredient/kake/actual.rb +26 -0
- data/lib/toji/ingredient/kake/base.rb +18 -0
- data/lib/toji/ingredient/kake/expected.rb +40 -0
- data/lib/toji/ingredient/koji.rb +19 -0
- data/lib/toji/ingredient/koji/actual.rb +29 -0
- data/lib/toji/ingredient/koji/actual_fermentable.rb +15 -0
- data/lib/toji/ingredient/koji/base.rb +35 -0
- data/lib/toji/ingredient/koji/expected.rb +45 -0
- data/lib/toji/ingredient/koji/expected_fermentable.rb +15 -0
- data/lib/toji/{recipe → ingredient}/koji_rate.rb +1 -1
- data/lib/toji/ingredient/rice.rb +10 -0
- data/lib/toji/ingredient/rice/actual_steamable.rb +27 -0
- data/lib/toji/ingredient/rice/base.rb +40 -0
- data/lib/toji/ingredient/rice/expected_steamable.rb +27 -0
- data/lib/toji/ingredient/rice_rate.rb +23 -0
- data/lib/toji/product.rb +65 -0
- data/lib/toji/{schedule/product_event.rb → product/event.rb} +4 -4
- data/lib/toji/recipe.rb +111 -5
- data/lib/toji/recipe/step.rb +49 -64
- data/lib/toji/version.rb +1 -1
- metadata +33 -39
- data/example/rice_recipe.rb +0 -28
- data/example/schedule.ipynb +0 -393
- data/example/schedule_file.ipynb +0 -337
- data/example/three_step_mashing_recipe.rb +0 -67
- data/lib/toji/brew/state_accessor.rb +0 -13
- data/lib/toji/brew/state_record.rb +0 -72
- data/lib/toji/recipe/ingredient.rb +0 -10
- data/lib/toji/recipe/ingredient/koji.rb +0 -21
- data/lib/toji/recipe/ingredient/koji/actual.rb +0 -32
- data/lib/toji/recipe/ingredient/koji/actual_fermentable.rb +0 -17
- data/lib/toji/recipe/ingredient/koji/base.rb +0 -37
- data/lib/toji/recipe/ingredient/koji/expected.rb +0 -48
- data/lib/toji/recipe/ingredient/koji/expected_fermentable.rb +0 -17
- data/lib/toji/recipe/ingredient/rice.rb +0 -21
- data/lib/toji/recipe/ingredient/rice/actual.rb +0 -29
- data/lib/toji/recipe/ingredient/rice/actual_steamable.rb +0 -29
- data/lib/toji/recipe/ingredient/rice/base.rb +0 -51
- data/lib/toji/recipe/ingredient/rice/expected.rb +0 -43
- data/lib/toji/recipe/ingredient/rice/expected_steamable.rb +0 -31
- data/lib/toji/recipe/ingredient/yeast.rb +0 -21
- data/lib/toji/recipe/rice_rate.rb +0 -10
- data/lib/toji/recipe/rice_rate/base.rb +0 -21
- data/lib/toji/recipe/rice_rate/cooked.rb +0 -67
- data/lib/toji/recipe/rice_rate/steamed.rb +0 -30
- data/lib/toji/recipe/three_step_mashing.rb +0 -274
- data/lib/toji/recipe/yeast_rate.rb +0 -41
- data/lib/toji/schedule.rb +0 -11
- data/lib/toji/schedule/calendar.rb +0 -139
- data/lib/toji/schedule/date_interval_enumerator.rb +0 -45
- data/lib/toji/schedule/product.rb +0 -117
@@ -0,0 +1,29 @@
|
|
1
|
+
module Toji
|
2
|
+
module Ingredient
|
3
|
+
module Koji
|
4
|
+
class Actual
|
5
|
+
include Base
|
6
|
+
include Rice::ActualSteamable
|
7
|
+
include ActualFermentable
|
8
|
+
|
9
|
+
def initialize(raw, soaked, steamed, cooled, tanekoji, dekoji)
|
10
|
+
@raw = raw.to_f
|
11
|
+
@soaked = soaked.to_f
|
12
|
+
@steamed = steamed.to_f
|
13
|
+
@cooled = cooled.to_f
|
14
|
+
@tanekoji = tanekoji.to_f
|
15
|
+
@dekoji = dekoji.to_f
|
16
|
+
end
|
17
|
+
|
18
|
+
def *(other)
|
19
|
+
if Integer===other || Float===other
|
20
|
+
Actual.new(raw * other, soaked * other, steamed * other, cooled * other, tanekoji * other, dekoji * other)
|
21
|
+
else
|
22
|
+
x, y = other.coerce(self)
|
23
|
+
x * y
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Toji
|
2
|
+
module Ingredient
|
3
|
+
module Koji
|
4
|
+
module Base
|
5
|
+
include Rice::Base
|
6
|
+
|
7
|
+
# 種麹
|
8
|
+
#
|
9
|
+
# 総破精麹を造るには、種麹の量を麹米100kgあたり種麹100gとする
|
10
|
+
# 突き破精麹を造るには、種麹の量を麹米100kgあたり種麹80gとする
|
11
|
+
#
|
12
|
+
# 出典: 酒造教本 P66
|
13
|
+
attr_reader :tanekoji_rate
|
14
|
+
attr_reader :tanekoji
|
15
|
+
|
16
|
+
# 出麹歩合
|
17
|
+
#
|
18
|
+
# 出麹歩合17〜19%のものが麹菌の繁殖のほどよい麹である
|
19
|
+
#
|
20
|
+
# 出典: 酒造教本 P67
|
21
|
+
attr_reader :dekoji_rate
|
22
|
+
attr_reader :dekoji
|
23
|
+
|
24
|
+
def +(other)
|
25
|
+
if Base===other
|
26
|
+
Actual.new(raw + other.raw, soaked + other.soaked, steamed + other.steamed, cooled + other.cooled, tanekoji + other.tanekoji, dekoji + other.dekoji)
|
27
|
+
else
|
28
|
+
x, y = other.coerce(self)
|
29
|
+
x + y
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Toji
|
2
|
+
module Ingredient
|
3
|
+
module Koji
|
4
|
+
class Expected
|
5
|
+
include Base
|
6
|
+
include Rice::ExpectedSteamable
|
7
|
+
include ExpectedFermentable
|
8
|
+
|
9
|
+
def initialize(raw, rice_rate: RiceRate::DEFAULT, koji_rate: KojiRate::DEFAULT)
|
10
|
+
@raw = raw.to_f
|
11
|
+
|
12
|
+
@rice_rate = rice_rate
|
13
|
+
@soaked_rate = rice_rate.soaked_rate
|
14
|
+
@steamed_rate = rice_rate.steamed_rate
|
15
|
+
@cooled_rate = rice_rate.cooled_rate
|
16
|
+
|
17
|
+
@koji_rate = koji_rate
|
18
|
+
@tanekoji_rate = koji_rate.tanekoji_rate
|
19
|
+
@dekoji_rate = koji_rate.dekoji_rate
|
20
|
+
end
|
21
|
+
|
22
|
+
def round(ndigit=0, half: :up)
|
23
|
+
self.class.new(@raw.round(ndigit, half: half), rice_rate: @rice_rate, koji_rate: @koji_rate)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create(x)
|
27
|
+
if self===x
|
28
|
+
x
|
29
|
+
else
|
30
|
+
new(x)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def *(other)
|
35
|
+
if Integer===other || Float===other
|
36
|
+
Expected.new(@raw * other, rice_rate: @rice_rate, koji_rate: @koji_rate)
|
37
|
+
else
|
38
|
+
x, y = other.coerce(self)
|
39
|
+
x * y
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Toji
|
2
|
+
module Ingredient
|
3
|
+
module Rice
|
4
|
+
module ActualSteamable
|
5
|
+
def soaked_rate
|
6
|
+
soaking_water / raw
|
7
|
+
end
|
8
|
+
|
9
|
+
def soaking_water
|
10
|
+
soaked - raw
|
11
|
+
end
|
12
|
+
|
13
|
+
def steamed_rate
|
14
|
+
(steamed - raw) / raw
|
15
|
+
end
|
16
|
+
|
17
|
+
def steaming_water
|
18
|
+
steamed - raw
|
19
|
+
end
|
20
|
+
|
21
|
+
def cooled_rate
|
22
|
+
(cooled - raw) / raw
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Toji
|
2
|
+
module Ingredient
|
3
|
+
module Rice
|
4
|
+
module Base
|
5
|
+
# 白米
|
6
|
+
attr_reader :raw
|
7
|
+
|
8
|
+
# 浸漬米吸水率
|
9
|
+
#
|
10
|
+
# 標準的な白米吸水率は掛米で30〜35%、麹米で33%前後で許容範囲はかなり狭い
|
11
|
+
#
|
12
|
+
# 出典: 酒造教本 P38
|
13
|
+
attr_reader :soaked_rate
|
14
|
+
attr_reader :soaking_water
|
15
|
+
attr_reader :soaked
|
16
|
+
|
17
|
+
# 蒸米吸水率
|
18
|
+
#
|
19
|
+
# 蒸しにより通常甑置き前の浸漬白米の重量よりさらに12〜13%吸水する
|
20
|
+
# 蒸しにより吸水の増加が13%を超える場合は、蒸米の表面が柔らかくべとつく蒸米になりやすい
|
21
|
+
# 蒸米吸水率は麹米及び酒母米で41〜43%、掛米は39〜40%で、吟醸造りの場合は数%低い
|
22
|
+
#
|
23
|
+
# 出典: 酒造教本 P48
|
24
|
+
attr_reader :steamed_rate
|
25
|
+
attr_reader :steaming_water
|
26
|
+
attr_reader :steamed
|
27
|
+
|
28
|
+
# 放冷
|
29
|
+
#
|
30
|
+
# 冷却法で若干異なるが蒸米の冷却により掛米で白米重量の10%、麹米で8%程度の水が失われる
|
31
|
+
# 出典: 酒造教本 P49
|
32
|
+
#
|
33
|
+
# 麹を造るのに適した蒸米は、引込時の吸水率が33%を理想とし、許容幅はプラスマイナス1%である
|
34
|
+
# 出典: 酒造教本 P59
|
35
|
+
attr_reader :cooled_rate
|
36
|
+
attr_reader :cooled
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Toji
|
2
|
+
module Ingredient
|
3
|
+
module Rice
|
4
|
+
module ExpectedSteamable
|
5
|
+
def soaking_water
|
6
|
+
raw * soaked_rate
|
7
|
+
end
|
8
|
+
|
9
|
+
def soaked
|
10
|
+
raw + raw * soaked_rate
|
11
|
+
end
|
12
|
+
|
13
|
+
def steaming_water
|
14
|
+
raw * steamed_rate
|
15
|
+
end
|
16
|
+
|
17
|
+
def steamed
|
18
|
+
raw + raw * steamed_rate
|
19
|
+
end
|
20
|
+
|
21
|
+
def cooled
|
22
|
+
raw + raw * cooled_rate
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Toji
|
2
|
+
module Ingredient
|
3
|
+
class RiceRate
|
4
|
+
# 浸漬米吸水率
|
5
|
+
attr_reader :soaked_rate
|
6
|
+
|
7
|
+
# 蒸米吸水率
|
8
|
+
attr_reader :steamed_rate
|
9
|
+
|
10
|
+
# 放冷後蒸米吸水率
|
11
|
+
attr_reader :cooled_rate
|
12
|
+
|
13
|
+
def initialize(soaked_rate, steamed_rate, cooled_rate)
|
14
|
+
@soaked_rate = soaked_rate
|
15
|
+
@steamed_rate = steamed_rate
|
16
|
+
@cooled_rate = cooled_rate
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
DEFAULT = new(0.33, 0.41, 0.33)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/toji/product.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'toji/product/event'
|
2
|
+
|
3
|
+
module Toji
|
4
|
+
module Product
|
5
|
+
attr_reader :reduce_key
|
6
|
+
attr_accessor :name
|
7
|
+
attr_accessor :recipe
|
8
|
+
attr_accessor :start_date
|
9
|
+
|
10
|
+
def koji_dates
|
11
|
+
date = start_date
|
12
|
+
recipe.steps.map {|step|
|
13
|
+
date = date.next_day(step.koji_interval_days)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def kake_dates
|
18
|
+
date = start_date
|
19
|
+
recipe.steps.map {|step|
|
20
|
+
date = date.next_day(step.kake_interval_days)
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def events
|
25
|
+
events = []
|
26
|
+
|
27
|
+
koji_dates.length.times {|i|
|
28
|
+
events << Event.new(self, :koji, i)
|
29
|
+
}
|
30
|
+
|
31
|
+
kake_dates.length
|
32
|
+
.times.map {|i|
|
33
|
+
Event.new(self, :kake, i)
|
34
|
+
}
|
35
|
+
.delete_if {|e|
|
36
|
+
4<=e.index && e.weight==0
|
37
|
+
}
|
38
|
+
.each {|e|
|
39
|
+
events << e
|
40
|
+
}
|
41
|
+
|
42
|
+
events
|
43
|
+
end
|
44
|
+
|
45
|
+
def events_group
|
46
|
+
events.group_by{|event|
|
47
|
+
event.group_key
|
48
|
+
}.map {|group_key,events|
|
49
|
+
breakdown = events.map {|event|
|
50
|
+
{index: event.index, weight: event.weight}
|
51
|
+
}
|
52
|
+
if 1<breakdown.length
|
53
|
+
breakdown = breakdown.select{|event| 0<event[:weight]}
|
54
|
+
end
|
55
|
+
|
56
|
+
{
|
57
|
+
date: events.first.date,
|
58
|
+
type: events.first.type,
|
59
|
+
weight: events.map(&:weight).sum,
|
60
|
+
breakdown: breakdown,
|
61
|
+
}
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Toji
|
2
|
-
module
|
3
|
-
class
|
2
|
+
module Product
|
3
|
+
class Event
|
4
4
|
attr_reader :product
|
5
5
|
attr_reader :type
|
6
6
|
attr_reader :index
|
@@ -30,14 +30,14 @@ module Toji
|
|
30
30
|
|
31
31
|
def group_key
|
32
32
|
a = []
|
33
|
-
a <<
|
33
|
+
a << product.reduce_key
|
34
34
|
a << type
|
35
35
|
a << group_index
|
36
36
|
a.map(&:to_s).join(":")
|
37
37
|
end
|
38
38
|
|
39
39
|
def weight
|
40
|
-
@product.recipe.steps[@index].send(@type)
|
40
|
+
@product.recipe.steps[@index].send(@type)
|
41
41
|
end
|
42
42
|
|
43
43
|
def to_h
|
data/lib/toji/recipe.rb
CHANGED
@@ -1,11 +1,117 @@
|
|
1
|
-
require 'toji/recipe/ingredient'
|
2
|
-
require 'toji/recipe/rice_rate'
|
3
|
-
require 'toji/recipe/koji_rate'
|
4
|
-
require 'toji/recipe/yeast_rate'
|
5
1
|
require 'toji/recipe/step'
|
6
|
-
require 'toji/recipe/three_step_mashing'
|
7
2
|
|
8
3
|
module Toji
|
9
4
|
module Recipe
|
5
|
+
attr_accessor :steps
|
6
|
+
|
7
|
+
def scale(rice_total)
|
8
|
+
rate = rice_total / steps.map(&:rice_total).sum
|
9
|
+
new_steps = steps.map {|step|
|
10
|
+
step * rate
|
11
|
+
}
|
12
|
+
|
13
|
+
self.class.new.tap {|o|
|
14
|
+
o.steps = new_steps
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def round(ndigit=0, mini_ndigit=nil, half: :up)
|
19
|
+
new_steps = steps.map {|step|
|
20
|
+
step.round(ndigit, mini_ndigit, half: half)
|
21
|
+
}
|
22
|
+
|
23
|
+
self.class.new.tap {|o|
|
24
|
+
o.steps = new_steps
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
# 総米の累計
|
29
|
+
def cumulative_rice_totals
|
30
|
+
rice_total = steps.map(&:rice_total)
|
31
|
+
|
32
|
+
rice_total.map.with_index {|x,i|
|
33
|
+
rice_total[0..i].inject(&:+)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
# 酒母歩合の累計
|
38
|
+
def cumulative_shubo_rates
|
39
|
+
rice_total = steps.map(&:rice_total)
|
40
|
+
shubo = rice_total.first
|
41
|
+
|
42
|
+
rice_total.map.with_index {|x,i|
|
43
|
+
shubo / rice_total[0..i].inject(&:+)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# 酒母歩合
|
48
|
+
#
|
49
|
+
# 7%が標準である
|
50
|
+
# 汲水歩合が大きい高温糖化酒母では6%程度である
|
51
|
+
#
|
52
|
+
# 出典: 酒造教本 P96
|
53
|
+
def shubo_rate
|
54
|
+
cumulative_shubo_rates.last || 0.0
|
55
|
+
end
|
56
|
+
|
57
|
+
# 白米比率
|
58
|
+
#
|
59
|
+
# 発酵型と白米比率
|
60
|
+
# 発酵の型 酒母 添 仲 留 特徴
|
61
|
+
# 湧き進め型 1 2 4 6 短期醪、辛口、軽快な酒質
|
62
|
+
# 湧き抑え型 1 2 4 7 長期醪、甘口、おだやかな酒質
|
63
|
+
#
|
64
|
+
# 出典: 酒造教本 P95
|
65
|
+
def rice_rates
|
66
|
+
steps.map {|step|
|
67
|
+
step.rice_total / steps.first.rice_total
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def table_data
|
72
|
+
headers = [""] + @steps.map(&:name) + [:total]
|
73
|
+
keys = [:rice_total, :kake, :koji, :alcohol, :water, :lactic_acid]
|
74
|
+
|
75
|
+
cells = [keys]
|
76
|
+
cells += @steps.map {|step|
|
77
|
+
[step.rice_total, step.kake, step.koji, step.alcohol, step.water, step.lactic_acid]
|
78
|
+
}
|
79
|
+
cells << keys.map {|key|
|
80
|
+
@steps.map(&key).compact.sum
|
81
|
+
}
|
82
|
+
|
83
|
+
cells = cells.map {|cell|
|
84
|
+
cell.map {|c|
|
85
|
+
case c
|
86
|
+
when NilClass
|
87
|
+
""
|
88
|
+
when 0
|
89
|
+
""
|
90
|
+
else
|
91
|
+
c
|
92
|
+
end
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
{header: headers, rows: cells.transpose}
|
97
|
+
end
|
98
|
+
|
99
|
+
def table
|
100
|
+
data = table_data
|
101
|
+
|
102
|
+
Plotly::Plot.new(
|
103
|
+
data: [{
|
104
|
+
type: :table,
|
105
|
+
header: {
|
106
|
+
values: data[:header]
|
107
|
+
},
|
108
|
+
cells: {
|
109
|
+
values: data[:rows].transpose
|
110
|
+
},
|
111
|
+
}],
|
112
|
+
layout: {
|
113
|
+
}
|
114
|
+
)
|
115
|
+
end
|
10
116
|
end
|
11
117
|
end
|