github.com/gopherd/gonum@v0.0.4/unit/constant/generate_constants.go (about) 1 // Copyright ©2014 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build ignore 6 // +build ignore 7 8 package main 9 10 import ( 11 "bytes" 12 "go/format" 13 "log" 14 "math" 15 "os" 16 "strings" 17 "text/template" 18 19 "github.com/gopherd/gonum/unit" 20 ) 21 22 const ( 23 elementaryCharge = 1.602176634e-19 24 fineStructure = 7.2973525693e-3 25 lightSpeed = 2.99792458e8 26 planck = 6.62607015e-34 27 ) 28 29 var constants = []Constant{ 30 { 31 Name: "AtomicMass", Value: 1.66053906660e-27, 32 Dimensions: []Dimension{{massName, 1}}, 33 Comment: "AtomicMass is the atomic mass constant (mᵤ), one twelfth of the mass of an unbound atom of carbon-12 at rest and in its ground state.", 34 Uncertainty: 0.00000000050e-27, 35 }, 36 { 37 Name: "Avogadro", Value: 6.02214076e23, 38 Dimensions: []Dimension{{moleName, -1}}, 39 Comment: "Avogadro is the Avogadro constant (A), the number of constituent particles contained in one mole of a substance.", 40 }, 41 { 42 Name: "Boltzmann", Value: 1.380649e-23, 43 Dimensions: []Dimension{{massName, 1}, {lengthName, 2}, {timeName, -2}, {temperatureName, -1}}, 44 Comment: "Boltzmann is the Boltzmann constant (k), it relates the average relative kinetic energy of particles in a gas with the temperature of the gas.", 45 }, 46 { 47 Name: "ElectricConstant", Value: 1 / (4 * math.Pi * 1e-7 * lightSpeed * lightSpeed), 48 Dimensions: []Dimension{{currentName, 2}, {timeName, 4}, {massName, -1}, {lengthName, -3}}, 49 Comment: "ElectricConstant is the electric constant (ε₀), the value of the absolute dielectric permittivity of classical vacuum.", 50 Uncertainty: 0.0000000013e-12, 51 }, 52 { 53 Name: "ElementaryCharge", Value: elementaryCharge, 54 Dimensions: []Dimension{{currentName, 1}, {timeName, 1}}, 55 Comment: "ElementaryCharge, is the elementary charge constant (e), the magnitude of electric charge carried by a single proton or electron.", 56 }, 57 { 58 Name: "Faraday", Value: 96485.33212, 59 Dimensions: []Dimension{{currentName, 1}, {timeName, 1}, {moleName, -1}}, 60 Comment: "Faraday is the Faraday constant, the magnitude of electric charge per mole of electrons.", 61 }, 62 { 63 Name: "FineStructure", Value: fineStructure, 64 Comment: "FineStructure is the fine structure constant (α), it describes the strength of the electromagnetic interaction between elementary charged particles.", 65 Uncertainty: 0.0000000011e-3, 66 }, 67 { 68 Name: "Gravitational", Value: 6.67430e-11, 69 Dimensions: []Dimension{{massName, -1}, {lengthName, 3}, {timeName, -2}}, 70 Comment: "Gravitational is the universal gravitational constant (G), the proportionality constant connecting the gravitational force between two bodies.", 71 Uncertainty: 0.00015e-11, 72 }, 73 { 74 Name: "LightSpeedInVacuum", Value: lightSpeed, 75 Dimensions: []Dimension{{lengthName, 1}, {timeName, -1}}, 76 Comment: "LightSpeedInVacuum is the c constant, the speed of light in a vacuum.", 77 }, 78 { 79 Name: "MagneticConstant", Value: 2 * fineStructure * planck / (elementaryCharge * elementaryCharge * lightSpeed), 80 Dimensions: []Dimension{{currentName, 2}, {timeName, 4}, {massName, -1}, {lengthName, -3}}, 81 Comment: "MagneticConstant is the magnetic constant (μ₀), the magnetic permeability in a classical vacuum.", 82 Uncertainty: 0.00000000019e-6, 83 }, 84 { 85 Name: "Planck", Value: planck, 86 Dimensions: []Dimension{{massName, 1}, {lengthName, 2}, {timeName, -1}}, 87 Comment: "Planck is the Planck constant (h), it relates the energy carried by a photon to its frequency.", 88 }, 89 { 90 Name: "StandardGravity", Value: 9.80665, 91 Dimensions: []Dimension{{lengthName, 1}, {timeName, -2}}, 92 Comment: "StandardGravity is the standard gravity constant (g₀), the nominal gravitational acceleration of an object in a vacuum near the surface of the Earth", 93 }, 94 } 95 96 const ( 97 angleName = "AngleDim" 98 currentName = "CurrentDim" 99 lengthName = "LengthDim" 100 luminousIntensityName = "LuminousIntensityDim" 101 massName = "MassDim" 102 moleName = "MoleDim" 103 temperatureName = "TemperatureDim" 104 timeName = "TimeDim" 105 ) 106 107 var dimOf = map[string]unit.Dimension{ 108 "AngleDim": unit.AngleDim, 109 "CurrentDim": unit.CurrentDim, 110 "LengthDim": unit.LengthDim, 111 "LuminousIntensityDim": unit.LuminousIntensityDim, 112 "MassDim": unit.MassDim, 113 "MoleDim": unit.MoleDim, 114 "TemperatureDim": unit.TemperatureDim, 115 "TimeDim": unit.TimeDim, 116 } 117 118 type Constant struct { 119 Name string 120 Value float64 121 Dimensions []Dimension 122 Comment string 123 Uncertainty float64 124 } 125 126 type Dimension struct { 127 Name string 128 Power int 129 } 130 131 func (c Constant) IsDefined() bool { 132 return definedEquivalentOf(unit.New(1, c.dimensions())) != "" 133 } 134 135 func (c Constant) Type() string { 136 typ := definedEquivalentOf(unit.New(1, c.dimensions())) 137 if typ == "" { 138 return strings.ToLower(c.Name[:1]) + c.Name[1:] + "Units" 139 } 140 return typ 141 } 142 143 func (c Constant) Units() string { 144 return c.dimensions().String() 145 } 146 147 func (c Constant) dimensions() unit.Dimensions { 148 dims := make(unit.Dimensions) 149 for _, d := range c.Dimensions { 150 dims[dimOf[d.Name]] = d.Power 151 } 152 return dims 153 } 154 155 // Generate a file for each of the constants. 156 func main() { 157 for _, c := range constants { 158 generate(c) 159 generateTest(c) 160 } 161 } 162 163 const baseUnitTemplate = `// Code generated by "go generate github.com/gopherd/gonum/unit/constant”; DO NOT EDIT. 164 165 // Copyright ©2019 The Gonum Authors. All rights reserved. 166 // Use of this source code is governed by a BSD-style 167 // license that can be found in the LICENSE file. 168 169 package constant 170 171 import "github.com/gopherd/gonum/unit" 172 173 // {{.Comment}}{{if .Dimensions}} 174 // {{$n := len .Dimensions}}The dimension{{if gt $n 1}}s{{end}} of {{.Name}} {{if eq $n 1}}is{{else}}are{{end}} {{.Units}}.{{end}} {{if not .Uncertainty}}The constant is exact.{{else}}The standard uncertainty of the constant is {{.Uncertainty}} {{.Units}}.{{end}} 175 const {{.Name}} = {{.Type}}({{.Value}}) 176 ` 177 178 var baseUnit = template.Must(template.New("base").Parse(baseUnitTemplate)) 179 180 const methodTemplate = `// Code generated by "go generate github.com/gopherd/gonum/unit/constant”; DO NOT EDIT. 181 182 // Copyright ©2019 The Gonum Authors. All rights reserved. 183 // Use of this source code is governed by a BSD-style 184 // license that can be found in the LICENSE file. 185 186 package constant 187 188 import ( 189 "fmt" 190 191 "github.com/gopherd/gonum/unit" 192 ) 193 194 // {{.Comment}} 195 // {{$n := len .Dimensions}}The dimension{{if gt $n 1}}s{{end}} of {{.Name}} {{if eq $n 1}}is{{else}}are{{end}} {{.Units}}. {{if not .Uncertainty}}The constant is exact.{{else}}The standard uncertainty of the constant is {{.Uncertainty}} {{.Units}}.{{end}} 196 const {{.Name}} = {{.Type}}({{.Value}}) 197 198 type {{.Type}} float64 199 200 // Unit converts the {{.Type}} to a *unit.Unit 201 func (cnst {{.Type}}) Unit() *unit.Unit { 202 return unit.New(float64(cnst), unit.Dimensions{ 203 {{range .Dimensions}} unit.{{.Name}}: {{.Power}}, 204 {{end}} 205 }) 206 } 207 208 func (cnst {{.Type}}) Format(fs fmt.State, c rune) { 209 switch c { 210 case 'v': 211 if fs.Flag('#') { 212 fmt.Fprintf(fs, "%T(%v)", cnst, float64(cnst)) 213 return 214 } 215 fallthrough 216 case 'e', 'E', 'f', 'F', 'g', 'G': 217 p, pOk := fs.Precision() 218 w, wOk := fs.Width() 219 switch { 220 case pOk && wOk: 221 fmt.Fprintf(fs, "%*.*"+string(c), w, p, cnst.Unit()) 222 case pOk: 223 fmt.Fprintf(fs, "%.*"+string(c), p, cnst.Unit()) 224 case wOk: 225 fmt.Fprintf(fs, "%*"+string(c), w, cnst.Unit()) 226 default: 227 fmt.Fprintf(fs, "%"+string(c), cnst.Unit()) 228 } 229 default: 230 fmt.Fprintf(fs, "%%!"+string(c)+"(constant.{{.Type}}=%v {{.Units}})", float64(cnst)) 231 } 232 } 233 ` 234 235 var methods = template.Must(template.New("methods").Parse(methodTemplate)) 236 237 func generate(c Constant) { 238 lowerName := strings.ToLower(c.Name) 239 filename := lowerName + ".go" 240 f, err := os.Create(filename) 241 if err != nil { 242 log.Fatal(err) 243 } 244 defer f.Close() 245 246 var buf bytes.Buffer 247 248 if c.IsDefined() { 249 err = baseUnit.Execute(&buf, c) 250 if err != nil { 251 log.Fatal(err) 252 } 253 } else { 254 err = methods.Execute(&buf, c) 255 if err != nil { 256 log.Fatal(err) 257 } 258 } 259 260 b, err := format.Source(buf.Bytes()) 261 if err != nil { 262 f.Write(buf.Bytes()) // This is here to debug bad format. 263 log.Fatalf("error formatting %q: %s", c.Name, err) 264 } 265 266 f.Write(b) 267 } 268 269 const testTemplate = `// Code generated by "go generate github.com/gopherd/gonum/unit/constant”; DO NOT EDIT. 270 271 // Copyright ©2019 The Gonum Authors. All rights reserved. 272 // Use of this source code is governed by a BSD-style 273 // license that can be found in the LICENSE file. 274 275 package constant 276 277 import ( 278 "fmt" 279 "testing" 280 ) 281 282 func Test{{.Name}}Format(t *testing.T) { 283 t.Parallel() 284 for _, test := range []struct{ 285 format string 286 want string 287 }{ 288 {"%v", "{{.Value}} {{.Units}}"}, 289 {"%.1v", "{{printf "%.1v" .Value}} {{.Units}}"}, 290 {"%50.1v", "{{$s := printf "%.1v %s" .Value .Units}}{{printf "%50s" $s}}"}, 291 {"%50v", "{{$s := printf "%v %s" .Value .Units}}{{printf "%50s" $s}}"}, 292 {"%1v", "{{.Value}} {{.Units}}"}, 293 {"%#v", "constant.{{.Type}}({{.Value}})"}, 294 {"%s", "%!s(constant.{{.Type}}={{.Value}} {{.Units}})"}, 295 } { 296 got := fmt.Sprintf(test.format, {{.Name}}) 297 if got != test.want { 298 t.Errorf("Format %q: got: %q want: %q", test.format, got, test.want) 299 } 300 } 301 } 302 ` 303 304 var tests = template.Must(template.New("test").Parse(testTemplate)) 305 306 func generateTest(c Constant) { 307 if c.IsDefined() { 308 return 309 } 310 311 lowerName := strings.ToLower(c.Name) 312 filename := lowerName + "_test.go" 313 f, err := os.Create(filename) 314 if err != nil { 315 log.Fatal(err) 316 } 317 defer f.Close() 318 319 var buf bytes.Buffer 320 321 err = tests.Execute(&buf, c) 322 if err != nil { 323 log.Fatal(err) 324 } 325 326 b, err := format.Source(buf.Bytes()) 327 if err != nil { 328 f.Write(buf.Bytes()) // This is here to debug bad format. 329 log.Fatalf("error formatting test for %q: %s", c.Name, err) 330 } 331 332 f.Write(b) 333 }