toji 1.1.0 → 1.2.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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/example/koji_making.ipynb +7 -7
  3. data/example/koji_making.rb +5 -5
  4. data/example/koji_recipe.rb +1 -1
  5. data/example/moromi.ipynb +55 -21
  6. data/example/moromi.rb +5 -5
  7. data/example/rice_recipe.rb +2 -2
  8. data/example/shubo.ipynb +6 -6
  9. data/example/shubo.rb +5 -5
  10. data/example/three_step_mashing_recipe.rb +2 -2
  11. data/lib/toji/brew/base.rb +88 -0
  12. data/lib/toji/brew/builder.rb +27 -0
  13. data/lib/toji/brew/graph/ab.rb +85 -0
  14. data/lib/toji/brew/graph/bmd.rb +58 -0
  15. data/lib/toji/brew/graph/progress.rb +142 -0
  16. data/lib/toji/brew/graph.rb +10 -0
  17. data/lib/toji/{product/koji_making.rb → brew/koji.rb} +35 -43
  18. data/lib/toji/{product → brew}/moromi.rb +105 -96
  19. data/lib/toji/brew/shubo.rb +122 -0
  20. data/lib/toji/brew/state.rb +117 -0
  21. data/lib/toji/{product/job_accessor.rb → brew/state_accessor.rb} +4 -4
  22. data/lib/toji/brew/state_record.rb +82 -0
  23. data/lib/toji/brew.rb +21 -0
  24. data/lib/toji/recipe/ingredient/koji/actual.rb +23 -0
  25. data/lib/toji/recipe/ingredient/koji/actual_fermentable.rb +17 -0
  26. data/lib/toji/recipe/ingredient/koji/base.rb +28 -0
  27. data/lib/toji/recipe/ingredient/koji/expected.rb +53 -0
  28. data/lib/toji/recipe/ingredient/koji/expected_fermentable.rb +17 -0
  29. data/lib/toji/recipe/ingredient/koji.rb +21 -0
  30. data/lib/toji/recipe/ingredient/lactic_acid.rb +21 -0
  31. data/lib/toji/recipe/ingredient/rice/actual.rb +20 -0
  32. data/lib/toji/recipe/ingredient/rice/actual_steamable.rb +29 -0
  33. data/lib/toji/recipe/ingredient/rice/base.rb +42 -0
  34. data/lib/toji/recipe/ingredient/rice/expected.rb +48 -0
  35. data/lib/toji/recipe/ingredient/rice/expected_steamable.rb +31 -0
  36. data/lib/toji/recipe/ingredient/rice.rb +21 -0
  37. data/lib/toji/recipe/ingredient/yeast.rb +21 -0
  38. data/lib/toji/recipe/ingredient.rb +11 -0
  39. data/lib/toji/recipe/lactic_acid_rate.rb +17 -0
  40. data/lib/toji/recipe/three_step_mashing.rb +4 -2
  41. data/lib/toji/recipe/yeast_rate.rb +41 -0
  42. data/lib/toji/recipe.rb +3 -0
  43. data/lib/toji/version.rb +1 -1
  44. data/lib/toji.rb +1 -3
  45. metadata +32 -29
  46. data/lib/toji/graph/ab.rb +0 -79
  47. data/lib/toji/graph/bmd.rb +0 -56
  48. data/lib/toji/graph/progress.rb +0 -87
  49. data/lib/toji/graph.rb +0 -8
  50. data/lib/toji/ingredient/koji/actual.rb +0 -21
  51. data/lib/toji/ingredient/koji/actual_fermentable.rb +0 -15
  52. data/lib/toji/ingredient/koji/base.rb +0 -26
  53. data/lib/toji/ingredient/koji/expected.rb +0 -51
  54. data/lib/toji/ingredient/koji/expected_fermentable.rb +0 -15
  55. data/lib/toji/ingredient/koji.rb +0 -19
  56. data/lib/toji/ingredient/rice/actual.rb +0 -18
  57. data/lib/toji/ingredient/rice/actual_steamable.rb +0 -27
  58. data/lib/toji/ingredient/rice/base.rb +0 -40
  59. data/lib/toji/ingredient/rice/expected.rb +0 -46
  60. data/lib/toji/ingredient/rice/expected_steamable.rb +0 -29
  61. data/lib/toji/ingredient/rice.rb +0 -19
  62. data/lib/toji/ingredient/yeast/base.rb +0 -21
  63. data/lib/toji/ingredient/yeast/red_star.rb +0 -30
  64. data/lib/toji/ingredient/yeast.rb +0 -9
  65. data/lib/toji/ingredient.rb +0 -8
  66. data/lib/toji/product/base.rb +0 -74
  67. data/lib/toji/product/job.rb +0 -176
  68. data/lib/toji/product/shubo.rb +0 -130
  69. data/lib/toji/product.rb +0 -11
@@ -0,0 +1,27 @@
1
+ module Toji
2
+ module Brew
3
+ class Builder
4
+
5
+ def initialize(cls)
6
+ @cls = cls
7
+ @records = []
8
+ @date_line = 0
9
+ end
10
+
11
+ def <<(record)
12
+ @records += [record].flatten
13
+ self
14
+ end
15
+ alias_method :add, :<<
16
+
17
+ def date_line(val)
18
+ @date_line = val
19
+ self
20
+ end
21
+
22
+ def build
23
+ @cls.new(@records, @date_line)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,85 @@
1
+ module Toji
2
+ module Brew
3
+ module Graph
4
+ class Ab
5
+ attr_reader :coef
6
+
7
+ def initialize(coef=1.5)
8
+ @coef = coef
9
+ @actuals = []
10
+ @expects = []
11
+ end
12
+
13
+ def actual(moromi, name=:actual)
14
+ @actuals << [moromi, name]
15
+ self
16
+ end
17
+
18
+ def expect(alcohol, nihonshudo)
19
+ @expects << [alcohol.to_f, nihonshudo.to_f]
20
+ self
21
+ end
22
+
23
+ def plot_data
24
+ result = []
25
+
26
+ @actuals.each {|moromi, name|
27
+ states = moromi.select{|s| s.alcohol && s.baume}
28
+
29
+ xs = states.map(&:alcohol)
30
+ ys = states.map(&:baume)
31
+ texts = states.map{|s| "%s<br />alc=%s, be=%s" % [s.display_time, s.alcohol, s.baume]}
32
+
33
+ result << {x: xs, y: ys, text: texts, name: name}
34
+ }
35
+
36
+ @expects.each {|alcohol, nihonshudo|
37
+ ys = [0.0, 8.0]
38
+ xs = ys.map{|b| alcohol - (b - nihonshudo * -0.1) * @coef}
39
+
40
+ name = "%s%s %s" % [nihonshudo<0 ? "" : "+", nihonshudo, alcohol]
41
+
42
+ result << {x: xs, y: ys, name: name}
43
+ }
44
+
45
+ result
46
+ end
47
+
48
+ def min_baume
49
+ @actuals.map {|moromi, name|
50
+ moromi.map(&:baume).compact.min
51
+ }.compact.min || 0
52
+ end
53
+
54
+ def max_baume
55
+ @actuals.map {|moromi, name|
56
+ moromi.map(&:baume).compact.max
57
+ }.compact.max || 0
58
+ end
59
+
60
+ def plot
61
+ #_min_baume = [min_baume-1, 0].min
62
+ _min_baume = 0
63
+
64
+ _max_baume = [max_baume+1, 10].max
65
+
66
+ Plotly::Plot.new(
67
+ data: plot_data,
68
+ layout: {
69
+ xaxis: {
70
+ title: "Alcohol",
71
+ dtick: 2,
72
+ range: [0, 20],
73
+ },
74
+ yaxis: {
75
+ title: "Baume",
76
+ dtick: 1,
77
+ range: [_min_baume, _max_baume],
78
+ }
79
+ }
80
+ )
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,58 @@
1
+ module Toji
2
+ module Brew
3
+ module Graph
4
+ class Bmd
5
+
6
+ def initialize
7
+ @actuals = []
8
+ @expects = []
9
+ end
10
+
11
+ def actual(moromi, name=:actual)
12
+ @actuals << [moromi, name]
13
+ self
14
+ end
15
+
16
+ def plot_data
17
+ result = []
18
+
19
+ @actuals.each {|moromi, name|
20
+ states = moromi.states.select{|s| s.moromi_day && s.bmd}
21
+
22
+ xs = states.map(&:moromi_day).map{|d| d*DAY}
23
+ ys = states.map(&:bmd)
24
+ texts = states.map{|s| "%s<br />moromi day=%d, be=%s, bmd=%s" % [s.display_time, s.moromi_day, s.baume, s.bmd]}
25
+
26
+ result << {x: xs, y: ys, text: texts, name: name}
27
+ }
28
+
29
+ result
30
+ end
31
+
32
+ def max_moromi_day
33
+ @actuals.map(&:first).map(&:moromi_days).max
34
+ end
35
+
36
+ def plot
37
+ _max_moromi_day = [max_moromi_day, 14].max
38
+
39
+ Plotly::Plot.new(
40
+ data: plot_data,
41
+ layout: {
42
+ xaxis: {
43
+ title: "Moromi day",
44
+ dtick: DAY,
45
+ range: [1, _max_moromi_day].map{|d| d*DAY},
46
+ tickvals: _max_moromi_day.times.map{|d| d*DAY},
47
+ ticktext: _max_moromi_day.times.map(&:succ)
48
+ },
49
+ yaxis: {
50
+ title: "BMD",
51
+ }
52
+ }
53
+ )
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,142 @@
1
+ module Toji
2
+ module Brew
3
+ module Graph
4
+ class Progress
5
+
6
+ attr_accessor :enable_annotations
7
+
8
+ def initialize(data, enable_annotations: true)
9
+ @data = data
10
+ @enable_annotations = enable_annotations
11
+ end
12
+
13
+ def has_keys
14
+ @data.map(&:has_keys).flatten.uniq
15
+ end
16
+
17
+ def plot_data(keys=nil)
18
+ if !keys
19
+ keys = has_keys
20
+ end
21
+
22
+ result = []
23
+
24
+ keys &= [:temps, :preset_temp, :room_temp, :room_psychrometry, :baume, :acid, :amino_acid, :alcohol, :bmd]
25
+
26
+ keys.each {|key|
27
+ xs = []
28
+ ys = []
29
+ text = []
30
+ @data.each {|r|
31
+ val = r.send(key)
32
+ if val
33
+ [val].flatten.each_with_index {|v,i|
34
+ xs << r.elapsed_time_with_offset + i
35
+ ys << v
36
+ text << r.display_time
37
+ }
38
+ end
39
+ }
40
+
41
+ line_shape = :linear
42
+ if key==:preset_temp
43
+ line_shape = :hv
44
+ end
45
+
46
+ result << {x: xs, y: ys, text: text, name: key, line: {shape: line_shape}}
47
+ }
48
+
49
+ if 0<@data.states.length && 0<@data.day_offset
50
+ result = result.map{|h|
51
+ h[:x].unshift(0)
52
+ h[:y].unshift(nil)
53
+ h[:text].unshift(nil)
54
+ h
55
+ }
56
+ end
57
+
58
+ result
59
+ end
60
+
61
+ def annotations
62
+ @data.select{|s| s.mark}.map {|s|
63
+ {
64
+ x: s.elapsed_time_with_offset,
65
+ y: s.temps.first || 0,
66
+ xref: 'x',
67
+ yref: 'y',
68
+ text: s.mark,
69
+ showarrow: true,
70
+ arrowhead: 1,
71
+ ax: 0,
72
+ ay: -40
73
+ }
74
+ }
75
+ end
76
+
77
+ def table_data(keys=nil)
78
+ if !keys
79
+ keys = has_keys
80
+ keys.delete(:elapsed_time)
81
+ keys.delete(:time)
82
+ keys.delete(:day)
83
+ keys.delete(:moromi_day)
84
+ keys.delete(:baume)
85
+ keys.delete(:nihonshudo)
86
+ else
87
+ keys &= has_keys
88
+ end
89
+
90
+ cells = @data.map {|s|
91
+ keys.map {|k|
92
+ v = s.send(k)
93
+ if Array===v
94
+ v.map(&:to_s).join(", ")
95
+ elsif Float===v
96
+ v.round(3)
97
+ elsif v
98
+ v
99
+ else
100
+ ""
101
+ end
102
+ }
103
+ }
104
+
105
+ {header: keys, cells: cells.transpose}
106
+ end
107
+
108
+ def plot(keys=nil)
109
+ Plotly::Plot.new(
110
+ data: plot_data(keys),
111
+ layout: {
112
+ xaxis: {
113
+ dtick: DAY,
114
+ tickvals: @data.days.times.map{|d| d*DAY},
115
+ ticktext: @data.day_labels
116
+ },
117
+ annotations: @enable_annotations ? annotations : [],
118
+ }
119
+ )
120
+ end
121
+
122
+ def table(keys=nil)
123
+ data = table_data(keys)
124
+
125
+ Plotly::Plot.new(
126
+ data: [{
127
+ type: :table,
128
+ header: {
129
+ values: data[:header]
130
+ },
131
+ cells: {
132
+ values: data[:cells]
133
+ },
134
+ }],
135
+ layout: {
136
+ }
137
+ )
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,10 @@
1
+ require 'toji/brew/graph/progress'
2
+ require 'toji/brew/graph/bmd'
3
+ require 'toji/brew/graph/ab'
4
+
5
+ module Toji
6
+ module Brew
7
+ module Graph
8
+ end
9
+ end
10
+ end
@@ -1,93 +1,85 @@
1
1
  module Toji
2
- module Product
3
- class KojiMaking < Base
2
+ module Brew
3
+ class Koji < Base
4
4
 
5
5
  TEMPLATES = {
6
6
  default: [
7
- Job.new(
8
- elapsed_time: 0 * Job::HOUR,
7
+ {
8
+ elapsed_time: 0 * Brew::HOUR,
9
9
  id: :hikikomi,
10
10
  temps: 35.0,
11
11
  room_temp: 28.0,
12
12
  room_psychrometry: nil,
13
- ),
14
- Job.new(
15
- elapsed_time: 1 * Job::HOUR,
13
+ },
14
+ {
15
+ elapsed_time: 1 * Brew::HOUR,
16
16
  id: :tokomomi,
17
17
  temps: 32.0,
18
18
  room_temp: 28.0,
19
19
  room_psychrometry: nil,
20
- ),
21
- Job.new(
22
- elapsed_time: 9 * Job::HOUR,
20
+ },
21
+ {
22
+ elapsed_time: 9 * Brew::HOUR,
23
23
  id: :kirikaeshi,
24
24
  temps: [32.0, 31.0],
25
25
  room_temp: 28.0,
26
26
  room_psychrometry: nil,
27
- ),
28
- Job.new(
29
- elapsed_time: 21 * Job::HOUR,
27
+ },
28
+ {
29
+ elapsed_time: 21 * Brew::HOUR,
30
30
  id: :mori,
31
31
  temps: [35.0, 33.0],
32
32
  room_temp: 28.0,
33
33
  room_psychrometry: 4,
34
- ),
35
- Job.new(
36
- elapsed_time: 29 * Job::HOUR,
34
+ },
35
+ {
36
+ elapsed_time: 29 * Brew::HOUR,
37
37
  id: :naka_shigoto,
38
38
  temps: [37.0, 35.0],
39
39
  room_temp: 28.0,
40
40
  room_psychrometry: 4,
41
- ),
42
- Job.new(
43
- elapsed_time: 35 * Job::HOUR,
41
+ },
42
+ {
43
+ elapsed_time: 35 * Brew::HOUR,
44
44
  id: :shimai_shigoto,
45
45
  temps: [38.0, 37.0],
46
46
  room_temp: 28.0,
47
47
  room_psychrometry: 5,
48
- ),
49
- Job.new(
50
- elapsed_time: 39 * Job::HOUR,
48
+ },
49
+ {
50
+ elapsed_time: 39 * Brew::HOUR,
51
51
  id: :tsumikae,
52
52
  temps: 40.0,
53
53
  room_temp: 28.0,
54
54
  room_psychrometry: 5,
55
- ),
56
- Job.new(
57
- elapsed_time: 44 * Job::HOUR,
55
+ },
56
+ {
57
+ elapsed_time: 44 * Brew::HOUR,
58
58
  id: :dekoji,
59
59
  temps: 40.0,
60
60
  room_temp: 28.0,
61
61
  room_psychrometry: 5,
62
- ),
62
+ },
63
63
  ],
64
64
  }
65
65
 
66
66
 
67
- job_reader :hikikomi
68
- job_reader :tokomomi
69
- job_reader :kirikaeshi
70
- job_reader :mori
71
- job_reader :naka_shigoto
72
- job_reader :shimai_shigoto
73
- job_reader :tsumikae
74
- job_reader :dekoji
67
+ state_reader :hikikomi
68
+ state_reader :tokomomi
69
+ state_reader :kirikaeshi
70
+ state_reader :mori
71
+ state_reader :naka_shigoto
72
+ state_reader :shimai_shigoto
73
+ state_reader :tsumikae
74
+ state_reader :dekoji
75
75
 
76
76
 
77
- def initialize(jobs=[], date_line: 0)
78
- super(jobs, date_line: date_line)
79
- end
80
-
81
- def day_labels
82
- days.times.map(&:succ)
83
- end
84
-
85
77
  def progress(enable_annotations: true)
86
78
  Graph::Progress.new(self, enable_annotations: enable_annotations)
87
79
  end
88
80
 
89
81
  def self.template(key=:default)
90
- new(TEMPLATES[key])
82
+ create(TEMPLATES[key])
91
83
  end
92
84
  end
93
85
  end