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.
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