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