toji 1.6.8 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/example/calendar.ipynb +383 -0
  3. data/example/{schedule.yaml → calendar.yaml} +6 -30
  4. data/example/calendar_file.ipynb +338 -0
  5. data/example/example_core.rb +354 -0
  6. data/example/kake_ingredient.rb +26 -0
  7. data/example/{koji_recipe.rb → koji_ingredient.rb} +1 -2
  8. data/example/koji_making.ipynb +16 -15
  9. data/example/koji_making.rb +2 -1
  10. data/example/koji_making.yaml +10 -9
  11. data/example/koji_making_multi.ipynb +27 -61
  12. data/example/moromi.ipynb +25 -24
  13. data/example/moromi.rb +1 -0
  14. data/example/moromi.yaml +10 -4
  15. data/example/recipe.rb +75 -0
  16. data/example/shubo.ipynb +15 -14
  17. data/example/shubo.rb +2 -1
  18. data/example/shubo.yaml +12 -11
  19. data/lib/toji.rb +3 -1
  20. data/lib/toji/brew.rb +4 -3
  21. data/lib/toji/brew/base.rb +8 -92
  22. data/lib/toji/brew/builder.rb +77 -6
  23. data/lib/toji/brew/graph/bmd.rb +1 -2
  24. data/lib/toji/brew/graph/multi_progress.rb +0 -121
  25. data/lib/toji/brew/graph/progress.rb +17 -52
  26. data/lib/toji/brew/koji.rb +2 -11
  27. data/lib/toji/brew/moromi.rb +4 -37
  28. data/lib/toji/brew/shubo.rb +2 -6
  29. data/lib/toji/brew/state.rb +90 -103
  30. data/lib/toji/brew/wrapped_state.rb +136 -0
  31. data/lib/toji/calendar.rb +123 -0
  32. data/lib/toji/{schedule → calendar}/date_column.rb +3 -6
  33. data/lib/toji/{schedule → calendar}/date_row.rb +6 -6
  34. data/lib/toji/ingredient.rb +10 -0
  35. data/lib/toji/ingredient/kake.rb +17 -0
  36. data/lib/toji/ingredient/kake/actual.rb +26 -0
  37. data/lib/toji/ingredient/kake/base.rb +18 -0
  38. data/lib/toji/ingredient/kake/expected.rb +40 -0
  39. data/lib/toji/ingredient/koji.rb +19 -0
  40. data/lib/toji/ingredient/koji/actual.rb +29 -0
  41. data/lib/toji/ingredient/koji/actual_fermentable.rb +15 -0
  42. data/lib/toji/ingredient/koji/base.rb +35 -0
  43. data/lib/toji/ingredient/koji/expected.rb +45 -0
  44. data/lib/toji/ingredient/koji/expected_fermentable.rb +15 -0
  45. data/lib/toji/{recipe → ingredient}/koji_rate.rb +1 -1
  46. data/lib/toji/ingredient/rice.rb +10 -0
  47. data/lib/toji/ingredient/rice/actual_steamable.rb +27 -0
  48. data/lib/toji/ingredient/rice/base.rb +40 -0
  49. data/lib/toji/ingredient/rice/expected_steamable.rb +27 -0
  50. data/lib/toji/ingredient/rice_rate.rb +23 -0
  51. data/lib/toji/product.rb +65 -0
  52. data/lib/toji/{schedule/product_event.rb → product/event.rb} +4 -4
  53. data/lib/toji/recipe.rb +111 -5
  54. data/lib/toji/recipe/step.rb +49 -64
  55. data/lib/toji/version.rb +1 -1
  56. metadata +33 -39
  57. data/example/rice_recipe.rb +0 -28
  58. data/example/schedule.ipynb +0 -393
  59. data/example/schedule_file.ipynb +0 -337
  60. data/example/three_step_mashing_recipe.rb +0 -67
  61. data/lib/toji/brew/state_accessor.rb +0 -13
  62. data/lib/toji/brew/state_record.rb +0 -72
  63. data/lib/toji/recipe/ingredient.rb +0 -10
  64. data/lib/toji/recipe/ingredient/koji.rb +0 -21
  65. data/lib/toji/recipe/ingredient/koji/actual.rb +0 -32
  66. data/lib/toji/recipe/ingredient/koji/actual_fermentable.rb +0 -17
  67. data/lib/toji/recipe/ingredient/koji/base.rb +0 -37
  68. data/lib/toji/recipe/ingredient/koji/expected.rb +0 -48
  69. data/lib/toji/recipe/ingredient/koji/expected_fermentable.rb +0 -17
  70. data/lib/toji/recipe/ingredient/rice.rb +0 -21
  71. data/lib/toji/recipe/ingredient/rice/actual.rb +0 -29
  72. data/lib/toji/recipe/ingredient/rice/actual_steamable.rb +0 -29
  73. data/lib/toji/recipe/ingredient/rice/base.rb +0 -51
  74. data/lib/toji/recipe/ingredient/rice/expected.rb +0 -43
  75. data/lib/toji/recipe/ingredient/rice/expected_steamable.rb +0 -31
  76. data/lib/toji/recipe/ingredient/yeast.rb +0 -21
  77. data/lib/toji/recipe/rice_rate.rb +0 -10
  78. data/lib/toji/recipe/rice_rate/base.rb +0 -21
  79. data/lib/toji/recipe/rice_rate/cooked.rb +0 -67
  80. data/lib/toji/recipe/rice_rate/steamed.rb +0 -30
  81. data/lib/toji/recipe/three_step_mashing.rb +0 -274
  82. data/lib/toji/recipe/yeast_rate.rb +0 -41
  83. data/lib/toji/schedule.rb +0 -11
  84. data/lib/toji/schedule/calendar.rb +0 -139
  85. data/lib/toji/schedule/date_interval_enumerator.rb +0 -45
  86. 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,15 @@
1
+ module Toji
2
+ module Ingredient
3
+ module Koji
4
+ module ActualFermentable
5
+ def tanekoji_rate
6
+ tanekoji / raw
7
+ end
8
+
9
+ def dekoji_rate
10
+ (dekoji - raw) / raw
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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,15 @@
1
+ module Toji
2
+ module Ingredient
3
+ module Koji
4
+ module ExpectedFermentable
5
+ def tanekoji
6
+ raw * tanekoji_rate
7
+ end
8
+
9
+ def dekoji
10
+ raw + raw * dekoji_rate
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  module Toji
2
- module Recipe
2
+ module Ingredient
3
3
  class KojiRate
4
4
  attr_reader :tanekoji_rate
5
5
  attr_reader :dekoji_rate
@@ -0,0 +1,10 @@
1
+ require 'toji/ingredient/rice/base'
2
+ require 'toji/ingredient/rice/expected_steamable'
3
+ require 'toji/ingredient/rice/actual_steamable'
4
+
5
+ module Toji
6
+ module Ingredient
7
+ module Rice
8
+ end
9
+ end
10
+ 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
@@ -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 Schedule
3
- class ProductEvent
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 << (product.id || product.name)
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).raw
40
+ @product.recipe.steps[@index].send(@type)
41
41
  end
42
42
 
43
43
  def to_h
@@ -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