forked from spatialmodel/inmap
/
speciate.go
127 lines (113 loc) · 3.45 KB
/
speciate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
Copyright © 2017 the InMAP authors.
This file is part of InMAP.
InMAP is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
InMAP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with InMAP. If not, see <http://www.gnu.org/licenses/>.*/
package slca
import (
"fmt"
"io"
"os"
"strings"
"github.com/ctessum/unit"
"github.com/Amen-Tes/inmap/emissions/aep"
)
// Speciate returns a chemically speciated copy of r.
func (db *DB) Speciate(r *Results) (*Results, error) {
if err := db.CSTConfig.lazyLoadSpeciator(); err != nil {
return nil, err
}
o := NewResults(db.LCADB)
o.Nodes = r.Nodes
o.Edges = make([]*ResultEdge, len(r.Edges))
for i, oldE := range r.Edges {
newE := ResultEdge{
FromID: oldE.ToID,
ToID: oldE.ToID,
ID: oldE.ID,
}
var err error
newE.FromResults, err = db.speciate(oldE.FromResults)
if err != nil {
return nil, err
}
o.Edges[i] = &newE
}
return o, nil
}
func (db *DB) speciate(r *OnsiteResults) (*OnsiteResults, error) {
year := int(db.LCADB.GetYear() + 0.5)
begin, end, err := aep.Annual.TimeInterval(fmt.Sprintf("%d", year))
interval := unit.New(end.Sub(begin).Seconds(), unit.Second)
if err != nil {
return nil, err
}
o := NewOnsiteResults(db)
o.Resources = r.Resources
o.Requirements = r.Requirements
for sp, spData := range r.Emissions {
rec := new(aep.PolygonRecord)
rec.SourceData.SCC = string(sp.GetSCC())
rec.SourceData.FIPS = "01001"
rec.SourceData.Country = aep.USA
for g, v := range spData {
p := splitPol(g.GetName())
rec.Emissions.Add(begin, end, p.Name, p.Prefix, unit.Div(v, interval))
}
emis, _, err := db.CSTConfig.speciator.Speciate(
rec,
db.CSTConfig.NEIData.ChemicalMechanism,
db.CSTConfig.NEIData.MassSpeciation,
!db.CSTConfig.NEIData.SCCExactMatch,
)
if err != nil {
return nil, err
}
totals := emis.Totals()
for p, v := range totals {
o.AddEmission(sp, gas(p.Name), v)
}
}
return o, nil
}
type gas string
func (g gas) GetName() string { return string(g) }
func (g gas) GetID() string { return string(g) }
func splitPol(p string) aep.Pollutant {
if strings.Contains(p, "_TBW") {
return aep.Pollutant{Name: strings.TrimRight(p, "_TBW"), Prefix: "TIR"}
}
if strings.Contains(p, "_evap") {
return aep.Pollutant{Name: strings.TrimRight(p, "_evap"), Prefix: "EVP"}
}
return aep.Pollutant{Name: p}
}
func (c *CSTConfig) lazyLoadSpeciator() error {
var err error
c.speciateOnce.Do(func() {
files := []string{c.NEIData.SpecRef, c.NEIData.SpecRefCombo, c.NEIData.SpeciesProperties,
c.NEIData.GasProfile, c.NEIData.GasSpecies, c.NEIData.OtherGasSpecies, c.NEIData.PMSpecies,
c.NEIData.MechAssignment, c.NEIData.MolarWeight, c.NEIData.SpeciesInfo}
f := make([]io.Reader, len(files))
for i, file := range files {
var fid io.Reader
fid, err = os.Open(os.ExpandEnv(file))
if err != nil {
err = fmt.Errorf("aep: loading speciator: %v", err)
return
}
f[i] = fid
}
c.speciator, err = aep.NewSpeciator(f[0], f[1], f[2], f[3], f[4], f[5], f[6],
f[7], f[8], f[9], c.InventoryConfig.PolsToKeep)
})
return err
}