toji 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +39 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/example/koji_recipe.rb +34 -0
  11. data/example/make_koji.rb +18 -0
  12. data/example/rice_recipe.rb +28 -0
  13. data/example/three_step_mashing_recipe.rb +65 -0
  14. data/lib/toji.rb +12 -0
  15. data/lib/toji/graph.rb +6 -0
  16. data/lib/toji/graph/ab.rb +75 -0
  17. data/lib/toji/ingredient.rb +8 -0
  18. data/lib/toji/ingredient/koji.rb +19 -0
  19. data/lib/toji/ingredient/koji/actual.rb +21 -0
  20. data/lib/toji/ingredient/koji/actual_fermentable.rb +15 -0
  21. data/lib/toji/ingredient/koji/base.rb +26 -0
  22. data/lib/toji/ingredient/koji/expected.rb +51 -0
  23. data/lib/toji/ingredient/koji/expected_fermentable.rb +15 -0
  24. data/lib/toji/ingredient/rice.rb +19 -0
  25. data/lib/toji/ingredient/rice/actual.rb +18 -0
  26. data/lib/toji/ingredient/rice/actual_steamable.rb +27 -0
  27. data/lib/toji/ingredient/rice/base.rb +40 -0
  28. data/lib/toji/ingredient/rice/expected.rb +46 -0
  29. data/lib/toji/ingredient/rice/expected_steamable.rb +29 -0
  30. data/lib/toji/ingredient/yeast.rb +9 -0
  31. data/lib/toji/ingredient/yeast/base.rb +21 -0
  32. data/lib/toji/ingredient/yeast/red_star.rb +30 -0
  33. data/lib/toji/progress.rb +11 -0
  34. data/lib/toji/progress/job.rb +165 -0
  35. data/lib/toji/progress/job_accessor.rb +13 -0
  36. data/lib/toji/progress/jobs.rb +142 -0
  37. data/lib/toji/progress/make_koji.rb +100 -0
  38. data/lib/toji/progress/moromi.rb +276 -0
  39. data/lib/toji/progress/shubo.rb +158 -0
  40. data/lib/toji/recipe.rb +9 -0
  41. data/lib/toji/recipe/koji_rate.rb +16 -0
  42. data/lib/toji/recipe/rice_rate.rb +10 -0
  43. data/lib/toji/recipe/rice_rate/base.rb +21 -0
  44. data/lib/toji/recipe/rice_rate/cooked.rb +61 -0
  45. data/lib/toji/recipe/rice_rate/steamed.rb +42 -0
  46. data/lib/toji/recipe/step.rb +65 -0
  47. data/lib/toji/recipe/three_step_mashing.rb +87 -0
  48. data/lib/toji/version.rb +3 -0
  49. data/toji.gemspec +36 -0
  50. metadata +178 -0
@@ -0,0 +1,158 @@
1
+ module Toji
2
+ module Progress
3
+ class Shubo
4
+ extend JobAccessor
5
+
6
+ TEMPLATES = {
7
+ default: [
8
+ Job.new(
9
+ elapsed_time: 0 * Job::DAY,
10
+ id: :mizukoji,
11
+ after_temp: 12.0,
12
+ acid: 13.0,
13
+ ),
14
+ Job.new(
15
+ elapsed_time: 0 * Job::DAY + 1 * Job::HOUR,
16
+ id: :shikomi,
17
+ after_temp: 20.0,
18
+ acid: 13.0,
19
+ ),
20
+ Job.new(
21
+ elapsed_time: 1 * Job::DAY,
22
+ id: :utase,
23
+ after_temp: 14.0,
24
+ baume: 15.0,
25
+ acid: 13.0,
26
+ ),
27
+ Job.new(
28
+ elapsed_time: 2 * Job::DAY,
29
+ before_temp: 8.0,
30
+ after_temp: 11.0,
31
+ baume: 16.0,
32
+ acid: 13.0,
33
+ warming: Job::WARM_DAKI,
34
+ ),
35
+ Job.new(
36
+ elapsed_time: 3 * Job::DAY,
37
+ before_temp: 10.0,
38
+ after_temp: 13.0,
39
+ baume: 16.5,
40
+ acid: 13.5,
41
+ warming: Job::WARM_DAKI,
42
+ ),
43
+ Job.new(
44
+ elapsed_time: 4 * Job::DAY,
45
+ before_temp: 12.0,
46
+ after_temp: 15.0,
47
+ baume: 17.0,
48
+ acid: 13.5,
49
+ warming: Job::WARM_DAKI,
50
+ ),
51
+ Job.new(
52
+ elapsed_time: 5 * Job::DAY,
53
+ after_temp: 14.0,
54
+ baume: 17.0,
55
+ acid: 14.0,
56
+ warming: Job::WARM_ANKA,
57
+ ),
58
+ Job.new(
59
+ elapsed_time: 6 * Job::DAY,
60
+ after_temp: 20.0,
61
+ baume: 17.0,
62
+ acid: 14.5,
63
+ warming: Job::WARM_ANKA,
64
+ ),
65
+ Job.new(
66
+ elapsed_time: 7 * Job::DAY,
67
+ after_temp: 20.0,
68
+ baume: 14.0,
69
+ acid: 15.5,
70
+ ),
71
+ Job.new(
72
+ elapsed_time: 8 * Job::DAY,
73
+ after_temp: 20.0,
74
+ baume: 12.0,
75
+ acid: 16.0,
76
+ ),
77
+ Job.new(
78
+ elapsed_time: 9 * Job::DAY,
79
+ id: :wake,
80
+ after_temp: 20.0,
81
+ baume: 9.0,
82
+ acid: 16.0,
83
+ ),
84
+ Job.new(
85
+ elapsed_time: 10 * Job::DAY,
86
+ after_temp: 15.0,
87
+ baume: 8.0,
88
+ acid: 16.5,
89
+ ),
90
+ Job.new(
91
+ elapsed_time: 11 * Job::DAY,
92
+ after_temp: 12.0,
93
+ baume: 7.0,
94
+ acid: 17.0,
95
+ ),
96
+ Job.new(
97
+ elapsed_time: 12 * Job::DAY,
98
+ after_temp: 10.0,
99
+ baume: 6.0,
100
+ acid: 17.5,
101
+ ),
102
+ Job.new(
103
+ elapsed_time: 13 * Job::DAY,
104
+ after_temp: 9.0,
105
+ baume: 5.0,
106
+ acid: 17.5,
107
+ ),
108
+ ],
109
+ }
110
+
111
+
112
+ job_reader :mizukoji
113
+ job_reader :shikomi
114
+ job_reader :utase
115
+ job_reader :wake
116
+
117
+ def initialize(jobs=[])
118
+ @jobs = Jobs.new(jobs)
119
+ end
120
+
121
+ def add(job)
122
+ @jobs << job
123
+ self
124
+ end
125
+
126
+ def jobs
127
+ @jobs.to_a
128
+ end
129
+
130
+ def days
131
+ (jobs.last.elapsed_time.to_f / Job::DAY).ceil + 1
132
+ end
133
+
134
+ def plot_data
135
+ @jobs.plot_data
136
+ end
137
+
138
+ def plot
139
+ _days = days
140
+
141
+ Plotly::Plot.new(
142
+ data: plot_data,
143
+ layout: {
144
+ xaxis: {
145
+ dtick: 24*60*60,
146
+ tickvals: _days.times.map{|d| d*Job::DAY},
147
+ ticktext: (1.._days).to_a
148
+ }
149
+ }
150
+ )
151
+ end
152
+
153
+ def self.template(key=:default)
154
+ new(TEMPLATES[key])
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,9 @@
1
+ require 'toji/recipe/rice_rate'
2
+ require 'toji/recipe/koji_rate'
3
+ require 'toji/recipe/step'
4
+ require 'toji/recipe/three_step_mashing'
5
+
6
+ module Toji
7
+ module Recipe
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module Toji
2
+ module Recipe
3
+ class KojiRate
4
+ attr_reader :tanekoji_rate
5
+ attr_reader :dekoji_rate
6
+
7
+ def initialize(tanekoji_rate, dekoji_rate)
8
+ @tanekoji_rate = tanekoji_rate
9
+ @dekoji_rate = dekoji_rate
10
+ end
11
+
12
+ DEFAULT = new(0.001, 0.18)
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,10 @@
1
+ require 'toji/recipe/rice_rate/base'
2
+ require 'toji/recipe/rice_rate/cooked'
3
+ require 'toji/recipe/rice_rate/steamed'
4
+
5
+ module Toji
6
+ module Recipe
7
+ module RiceRate
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ module Toji
2
+ module Recipe
3
+ module RiceRate
4
+ module Base
5
+ # 浸漬米吸水率
6
+ attr_reader :soaked_rate
7
+
8
+ # 蒸し前浸漬米吸水率
9
+ # 炊飯の場合は水を追加
10
+ # 蒸しの場合は一晩経って蒸発した分を削減
11
+ attr_reader :before_steaming_rate
12
+
13
+ # 蒸米吸水率
14
+ attr_reader :steamed_rate
15
+
16
+ # 放冷後蒸米吸水率
17
+ attr_reader :cooled_rate
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,61 @@
1
+ module Toji
2
+ module Recipe
3
+ module RiceRate
4
+ class Cooked
5
+ include Base
6
+
7
+ # 炊飯器を使う場合
8
+ # 白米の60%の水で炊くと蒸米吸水率はだいたい38%くらいになる
9
+ # 炊飯、放冷の過程で水分のうち36%程度は蒸発する
10
+
11
+ # 蒸す前
12
+ # ・白米(無洗米コシヒカリ) 85g
13
+ # ・水 50g
14
+ # ・浸漬米吸水率 58.82%
15
+ #
16
+ # 蒸した後
17
+ # ・蒸米 117.5g
18
+ # ・蒸米吸水率 38.24%
19
+
20
+ def initialize(soaked_rate, before_steaming_rate, steamed_rate, cooled_rate)
21
+ @soaked_rate = soaked_rate
22
+ @before_steaming_rate = before_steaming_rate
23
+ @steamed_rate = steamed_rate
24
+ @cooled_rate = cooled_rate
25
+ end
26
+
27
+
28
+ DEFAULT = new(0.35, 0.5, 0.40, 0.36)
29
+
30
+ @@rates = [
31
+ #new(0.60, 0.380+0.1, 0.380),
32
+ #new(0.55, 0.360+0.1, 0.360),
33
+ #new(0.50, 0.335+0.1, 0.335),
34
+ new(0.35, 0.5, 0.40, 0.36),
35
+ new(0.33, 0.45, 0.40, 0.35),
36
+ ]
37
+
38
+ def self.soaked_rate(val)
39
+ @@rates.select{|r| r.soaked_rate==val}.first
40
+ end
41
+
42
+ def self.before_steaming_rate(val)
43
+ @@rates.select{|r| r.before_steaming_rate==val}.first
44
+ end
45
+
46
+ def self.steamed_rate(val)
47
+ @@rates.select{|r| r.steamed_rate==val}.first
48
+ end
49
+
50
+ def self.cooled_rate(val)
51
+ @@rates.select{|r| r.cooled_rate==val}.first
52
+ end
53
+ end
54
+
55
+
56
+ def self.cooked(soaked_rate, before_steaming_rate, steamed_rate, cooled_rate)
57
+ Cooked.new(soaked_rate, before_steaming_rate, steamed_rate, cooled_rate)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,42 @@
1
+ module Toji
2
+ module Recipe
3
+ module RiceRate
4
+ class Steamed
5
+ include Base
6
+
7
+ def initialize(soaked_rate, before_steaming_rate, steamed_rate, cooled_rate)
8
+ @soaked_rate = soaked_rate
9
+ @before_steaming_rate = before_steaming_rate
10
+ @steamed_rate = steamed_rate
11
+ @cooled_rate = cooled_rate
12
+ end
13
+
14
+ def before_steaming_rate
15
+ @before_steaming_rate || begin
16
+ @soaked_rate - 0.04
17
+ end
18
+ end
19
+
20
+
21
+ DEFAULT = new(0.33, nil, 0.41, 0.33)
22
+
23
+ def self.soaked_rate(val)
24
+ @@rates.select{|r| r.soaked_rate==val}.first
25
+ end
26
+
27
+ def self.steamed_rate(val)
28
+ @@rates.select{|r| r.steamed_rate==val}.first
29
+ end
30
+
31
+ def self.cooled_rate(val)
32
+ @@rates.select{|r| r.cooled_rate==val}.first
33
+ end
34
+ end
35
+
36
+
37
+ def self.steamed(soaked_rate, before_steaming_rate, steamed_rate, cooled_rate)
38
+ Steamed.new(soaked_rate, before_steaming_rate, steamed_rate, cooled_rate)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,65 @@
1
+ module Toji
2
+ module Recipe
3
+ class Step
4
+ attr_reader :rice
5
+ attr_reader :koji
6
+ attr_reader :water
7
+
8
+ def initialize(rice, koji, water)
9
+ @rice = Ingredient::Rice::Expected.create(rice)
10
+ @koji = Ingredient::Koji::Expected.create(koji)
11
+ @water = water.to_f
12
+ end
13
+
14
+ # 総米
15
+ def rice_total
16
+ @rice.raw + @koji.raw
17
+ end
18
+
19
+ # 総重量
20
+ def weight_total
21
+ @rice.cooled + @koji.dekoji + @water
22
+ end
23
+
24
+ # 麹歩合
25
+ # 原料白米に占める麹米の割合
26
+ # 留め仕込みまでの総米重量の20〜22%が標準である
27
+ # なお、留め仕込みまでの麹歩合が20%を下回ると蒸米の溶解糖化に影響が出るので注意がいる
28
+ # 出典: 酒造教本 P95
29
+ def koji_rate
30
+ @koji.raw / rice_total
31
+ end
32
+
33
+ # 汲水歩合
34
+ #
35
+ # 酒母: 110%が標準、高温糖化酒母は150〜180%
36
+ # 添: 85〜100%の範囲で90%が標準、湧き進め型は歩合が高い
37
+ # 仲: 120%が標準
38
+ # 留: 130〜150%の範囲
39
+ # 全体: 留までの総米に対し120〜130%、標準は125%、高級酒は130〜145%である
40
+ #
41
+ # 出典: 酒造教本 P96
42
+ def water_rate
43
+ @water / rice_total
44
+ end
45
+
46
+ def +(other)
47
+ if Step===other
48
+ self.class.new(@rice + other.rice, @koji + other.koji, @water + other.water)
49
+ else
50
+ x, y = other.coerce(self)
51
+ x + y
52
+ end
53
+ end
54
+
55
+ def *(other)
56
+ if Integer===other || Float===other
57
+ self.class.new(@rice * other, @koji * other, @water * other)
58
+ else
59
+ x, y = other.coerce(self)
60
+ x * y
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,87 @@
1
+ module Toji
2
+ module Recipe
3
+ class ThreeStepMashing
4
+
5
+ STEP_NAMES = ["酒母", "初添", "仲添", "留添"]
6
+
7
+ @@template = [
8
+ Step.new(93, 47, 170),
9
+ Step.new(217, 99, 270),
10
+ Step.new(423, 143, 670),
11
+ Step.new(813, 165, 1330),
12
+ ]
13
+ #@@template = [
14
+ # Step.new(45, 20, 70),
15
+ # Step.new(100, 40, 130),
16
+ # Step.new(215, 60, 330),
17
+ # Step.new(360, 80, 630),
18
+ #]
19
+
20
+ attr_reader :yeast
21
+ attr_reader :steps
22
+
23
+ def initialize(yeast_cls, total, template=@@template)
24
+ @total = total
25
+ rate = total / template.map(&:weight_total).sum
26
+
27
+ @yeast = yeast_cls.new(total)
28
+
29
+ @steps = template.map {|step|
30
+ step * rate
31
+ }
32
+ end
33
+
34
+ # 内容量の累計
35
+ def cumulative_weight_totals
36
+ total = @steps.map(&:weight_total)
37
+
38
+ total.map.with_index {|x,i|
39
+ total[0..i].inject(:+)
40
+ }
41
+ end
42
+
43
+ # 総米の累計
44
+ def cumulative_rice_totals
45
+ rice_total = @steps.map(&:rice_total)
46
+
47
+ rice_total.map.with_index {|x,i|
48
+ rice_total[0..i].inject(&:+)
49
+ }
50
+ end
51
+
52
+ # 酒母歩合の累計
53
+ def cumulative_shubo_rates
54
+ rice_total = @steps.map(&:rice_total)
55
+ shubo = rice_total[0]
56
+
57
+ rice_total.map.with_index {|x,i|
58
+ shubo / rice_total[0..i].inject(&:+)
59
+ }
60
+ end
61
+
62
+ # 酒母歩合
63
+ #
64
+ # 7%が標準である
65
+ # 汲水歩合が大きい高温糖化酒母では6%程度である
66
+ #
67
+ # 出典: 酒造教本 P96
68
+ def shubo_rate
69
+ cumulative_shubo_rates.last
70
+ end
71
+
72
+ # 白米比率
73
+ #
74
+ # 発酵型と白米比率
75
+ # 発酵の型 酒母 添 仲 留 特徴
76
+ # 湧き進め型 1 2 4 6 短期醪、辛口、軽快な酒質
77
+ # 湧き抑え型 1 2 4 7 長期醪、甘口、おだやかな酒質
78
+ #
79
+ # 出典: 酒造教本 P95
80
+ def rice_rates
81
+ @steps.map {|step|
82
+ step.rice_total / @steps[0].rice_total
83
+ }
84
+ end
85
+ end
86
+ end
87
+ end