go-hep.org/x/hep@v0.38.1/hbook/ops_test.go (about)

     1  // Copyright ©2017 The go-hep 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  package hbook
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/google/go-cmp/cmp"
    14  )
    15  
    16  func ExampleDivideH1D() {
    17  
    18  	h1 := NewH1D(5, 0, 5)
    19  	h1.Fill(0, 1)
    20  	h1.Fill(1, 2)
    21  	h1.Fill(2, 3)
    22  	h1.Fill(3, 3)
    23  	h1.Fill(4, 4)
    24  
    25  	h2 := NewH1D(5, 0, 5)
    26  	h2.Fill(0, 11)
    27  	h2.Fill(1, 22)
    28  	h2.Fill(2, 0)
    29  	h2.Fill(3, 33)
    30  	h2.Fill(4, 44)
    31  
    32  	s0, err := DivideH1D(h1, h2)
    33  	if err != nil {
    34  		panic(err)
    35  	}
    36  	s1, err := DivideH1D(h1, h2, DivIgnoreNaNs())
    37  	if err != nil {
    38  		panic(err)
    39  	}
    40  	s2, err := DivideH1D(h1, h2, DivReplaceNaNs(1.0))
    41  	if err != nil {
    42  		panic(err)
    43  	}
    44  
    45  	fmt.Println("Default:")
    46  	for i, pt := range s0.Points() {
    47  		fmt.Printf("Point %v: %.2f  + %.2f  - %.2f\n", i, pt.Y, pt.ErrY.Min, pt.ErrY.Min)
    48  	}
    49  
    50  	fmt.Println("\nDivIgnoreNaNs:")
    51  	for i, pt := range s1.Points() {
    52  		fmt.Printf("Point %v: %.2f  + %.2f  - %.2f\n", i, pt.Y, pt.ErrY.Min, pt.ErrY.Min)
    53  	}
    54  
    55  	fmt.Println("\nDivReplaceNaNs with v=1.0:")
    56  	for i, pt := range s2.Points() {
    57  		fmt.Printf("Point %v: %.2f  + %.2f  - %.2f\n", i, pt.Y, pt.ErrY.Min, pt.ErrY.Min)
    58  	}
    59  
    60  	// Output:
    61  	// Default:
    62  	// Point 0: 0.09  + 0.13  - 0.13
    63  	// Point 1: 0.09  + 0.13  - 0.13
    64  	// Point 2: NaN  + 0.00  - 0.00
    65  	// Point 3: 0.09  + 0.13  - 0.13
    66  	// Point 4: 0.09  + 0.13  - 0.13
    67  	//
    68  	// DivIgnoreNaNs:
    69  	// Point 0: 0.09  + 0.13  - 0.13
    70  	// Point 1: 0.09  + 0.13  - 0.13
    71  	// Point 2: 0.09  + 0.13  - 0.13
    72  	// Point 3: 0.09  + 0.13  - 0.13
    73  	//
    74  	// DivReplaceNaNs with v=1.0:
    75  	// Point 0: 0.09  + 0.13  - 0.13
    76  	// Point 1: 0.09  + 0.13  - 0.13
    77  	// Point 2: 1.00  + 0.00  - 0.00
    78  	// Point 3: 0.09  + 0.13  - 0.13
    79  	// Point 4: 0.09  + 0.13  - 0.13
    80  }
    81  
    82  func TestDivideH1D(t *testing.T) {
    83  	h1 := NewH1D(5, 0, 5)
    84  	h2 := NewH1D(5, 0, 5)
    85  	for i := range 5 {
    86  		h1.Fill(float64(i), float64(i+1))
    87  		h2.Fill(float64(i), float64(i+3))
    88  	}
    89  	s, err := DivideH1D(h1, h2)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  
    94  	chk, err := s.MarshalYODA()
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  
    99  	want := []byte(`BEGIN YODA_SCATTER2D_V2 /
   100  Path: /
   101  Title: ""
   102  Type: Scatter2D
   103  ---
   104  # xval	 xerr-	 xerr+	 yval	 yerr-	 yerr+	
   105  5.000000e-01	5.000000e-01	5.000000e-01	3.333333e-01	4.714045e-01	4.714045e-01
   106  1.500000e+00	5.000000e-01	5.000000e-01	5.000000e-01	7.071068e-01	7.071068e-01
   107  2.500000e+00	5.000000e-01	5.000000e-01	6.000000e-01	8.485281e-01	8.485281e-01
   108  3.500000e+00	5.000000e-01	5.000000e-01	6.666667e-01	9.428090e-01	9.428090e-01
   109  4.500000e+00	5.000000e-01	5.000000e-01	7.142857e-01	1.010153e+00	1.010153e+00
   110  END YODA_SCATTER2D_V2
   111  
   112  `)
   113  
   114  	if !reflect.DeepEqual(chk, want) {
   115  		t.Fatalf("divide(num,den) differ:\n%s\n",
   116  			cmp.Diff(
   117  				string(chk),
   118  				string(want),
   119  			),
   120  		)
   121  	}
   122  }
   123  
   124  func TestAddH1DPanics(t *testing.T) {
   125  	for _, tc := range []struct {
   126  		h1, h2 *H1D
   127  		panics error
   128  	}{
   129  		{
   130  			h1:     NewH1D(10, 0, 10),
   131  			h2:     NewH1D(5, 0, 10),
   132  			panics: fmt.Errorf("hbook: h1 and h2 have different number of bins"),
   133  		},
   134  		{
   135  			h1:     NewH1D(10, 0, 10),
   136  			h2:     NewH1D(10, 1, 10),
   137  			panics: fmt.Errorf("hbook: h1 and h2 have different range"),
   138  		},
   139  		{
   140  			h1:     NewH1D(10, 0, 10),
   141  			h2:     NewH1D(10, 0, 11),
   142  			panics: fmt.Errorf("hbook: h1 and h2 have different range"),
   143  		},
   144  		{
   145  			h1:     NewH1D(10, 0, 10),
   146  			h2:     NewH1D(10, 1, 11),
   147  			panics: fmt.Errorf("hbook: h1 and h2 have different range"),
   148  		},
   149  	} {
   150  		t.Run("", func(t *testing.T) {
   151  			if tc.panics != nil {
   152  				defer func() {
   153  					err := recover()
   154  					if err == nil {
   155  						t.Fatalf("expected a panic")
   156  					}
   157  					if got, want := err.(error).Error(), tc.panics.Error(); got != want {
   158  						t.Fatalf("invalid panic message.\ngot= %v\nwant=%v", got, want)
   159  					}
   160  				}()
   161  			}
   162  			_ = AddH1D(tc.h1, tc.h2)
   163  		})
   164  	}
   165  }
   166  
   167  func TestAddH1D(t *testing.T) {
   168  
   169  	h1 := NewH1D(6, 0, 6)
   170  	h1.Fill(-0.5, 1)
   171  	h1.Fill(0, 1.5)
   172  	h1.Fill(0.5, 1)
   173  	h1.Fill(1.2, 1)
   174  	h1.Fill(2.1, 2)
   175  	h1.Fill(4.2, 1)
   176  	h1.Fill(5.9, 1)
   177  	h1.Fill(6, 0.5)
   178  
   179  	h2 := NewH1D(6, 0, 6)
   180  	h2.Fill(-0.5, 0.7)
   181  	h2.Fill(0.2, 1)
   182  	h2.Fill(0.7, 1.2)
   183  	h2.Fill(1.5, 0.8)
   184  	h2.Fill(2.2, 0.7)
   185  	h2.Fill(4.3, 1.3)
   186  	h2.Fill(5.2, 2)
   187  	h2.Fill(6.8, 1)
   188  
   189  	h3 := AddH1D(h1, h2)
   190  
   191  	got, err := h3.MarshalYODA()
   192  	if err != nil {
   193  		t.Fatalf("could not marshal to yoda: %+v", err)
   194  	}
   195  
   196  	want := []byte(`BEGIN YODA_HISTO1D_V2 /
   197  Path: /
   198  Title: ""
   199  Type: Histo1D
   200  ---
   201  # Mean: 2.526554e+00
   202  # Area: 1.770000e+01
   203  # ID	 ID	 sumw	 sumw2	 sumwx	 sumwx2	 numEntries
   204  Total   	Total   	1.770000e+01	2.225000e+01	4.472000e+01	2.115580e+02	1.600000e+01
   205  Underflow	Underflow	1.700000e+00	1.490000e+00	-8.500000e-01	4.250000e-01	2.000000e+00
   206  Overflow	Overflow	1.500000e+00	1.250000e+00	9.800000e+00	6.424000e+01	2.000000e+00
   207  # xlow	 xhigh	 sumw	 sumw2	 sumwx	 sumwx2	 numEntries
   208  0.000000e+00	1.000000e+00	4.700000e+00	5.690000e+00	1.540000e+00	8.780000e-01	4.000000e+00
   209  1.000000e+00	2.000000e+00	1.800000e+00	1.640000e+00	2.400000e+00	3.240000e+00	2.000000e+00
   210  2.000000e+00	3.000000e+00	2.700000e+00	4.490000e+00	5.740000e+00	1.220800e+01	2.000000e+00
   211  3.000000e+00	4.000000e+00	0.000000e+00	0.000000e+00	0.000000e+00	0.000000e+00	0.000000e+00
   212  4.000000e+00	5.000000e+00	2.300000e+00	2.690000e+00	9.790000e+00	4.167700e+01	2.000000e+00
   213  5.000000e+00	6.000000e+00	3.000000e+00	5.000000e+00	1.630000e+01	8.889000e+01	2.000000e+00
   214  END YODA_HISTO1D_V2
   215  
   216  `)
   217  
   218  	if !bytes.Equal(got, want) {
   219  		t.Fatalf("add differ:\n%s\n",
   220  			cmp.Diff(
   221  				string(got),
   222  				string(want),
   223  			),
   224  		)
   225  	}
   226  }
   227  
   228  func TestSubH1DPanics(t *testing.T) {
   229  	for _, tc := range []struct {
   230  		h1, h2 *H1D
   231  		panics error
   232  	}{
   233  		{
   234  			h1:     NewH1D(10, 0, 10),
   235  			h2:     NewH1D(5, 0, 10),
   236  			panics: fmt.Errorf("hbook: h1 and h2 have different number of bins"),
   237  		},
   238  		{
   239  			h1:     NewH1D(10, 0, 10),
   240  			h2:     NewH1D(10, 1, 10),
   241  			panics: fmt.Errorf("hbook: h1 and h2 have different range"),
   242  		},
   243  		{
   244  			h1:     NewH1D(10, 0, 10),
   245  			h2:     NewH1D(10, 0, 11),
   246  			panics: fmt.Errorf("hbook: h1 and h2 have different range"),
   247  		},
   248  		{
   249  			h1:     NewH1D(10, 0, 10),
   250  			h2:     NewH1D(10, 1, 11),
   251  			panics: fmt.Errorf("hbook: h1 and h2 have different range"),
   252  		},
   253  	} {
   254  		t.Run("", func(t *testing.T) {
   255  			if tc.panics != nil {
   256  				defer func() {
   257  					err := recover()
   258  					if err == nil {
   259  						t.Fatalf("expected a panic")
   260  					}
   261  					if got, want := err.(error).Error(), tc.panics.Error(); got != want {
   262  						t.Fatalf("invalid panic message.\ngot= %v\nwant=%v", got, want)
   263  					}
   264  				}()
   265  			}
   266  			_ = SubH1D(tc.h1, tc.h2)
   267  		})
   268  	}
   269  }
   270  
   271  func TestSubH1D(t *testing.T) {
   272  	h1 := NewH1D(6, 0, 6)
   273  	h1.Fill(-0.5, 1)
   274  	h1.Fill(0, 1.5)
   275  	h1.Fill(0.5, 1)
   276  	h1.Fill(1.2, 1)
   277  	h1.Fill(2.1, 2)
   278  	h1.Fill(4.2, 1)
   279  	h1.Fill(5.9, 1)
   280  	h1.Fill(6, 0.5)
   281  
   282  	h2 := NewH1D(6, 0, 6)
   283  	h2.Fill(-0.5, 0.7)
   284  	h2.Fill(0.2, 1)
   285  	h2.Fill(0.7, 1.2)
   286  	h2.Fill(1.5, 0.8)
   287  	h2.Fill(2.2, 0.7)
   288  	h2.Fill(4.3, 1.3)
   289  	h2.Fill(5.2, 2)
   290  	h2.Fill(6.8, 1)
   291  
   292  	h3 := SubH1D(h1, h2)
   293  
   294  	got, err := h3.MarshalYODA()
   295  	if err != nil {
   296  		t.Fatalf("could not marshal to yoda: %+v", err)
   297  	}
   298  
   299  	want := []byte(`BEGIN YODA_HISTO1D_V2 /
   300  Path: /
   301  Title: ""
   302  Type: Histo1D
   303  ---
   304  # Mean: -2.573333e+01
   305  # Area: 3.000000e-01
   306  # ID	 ID	 sumw	 sumw2	 sumwx	 sumwx2	 numEntries
   307  Total   	Total   	3.000000e-01	2.225000e+01	-7.720000e+00	-4.913800e+01	1.600000e+01
   308  Underflow	Underflow	3.000000e-01	1.490000e+00	-1.500000e-01	7.500000e-02	2.000000e+00
   309  Overflow	Overflow	-5.000000e-01	1.250000e+00	-3.800000e+00	-2.824000e+01	2.000000e+00
   310  # xlow	 xhigh	 sumw	 sumw2	 sumwx	 sumwx2	 numEntries
   311  0.000000e+00	1.000000e+00	3.000000e-01	5.690000e+00	-5.400000e-01	-3.780000e-01	4.000000e+00
   312  1.000000e+00	2.000000e+00	2.000000e-01	1.640000e+00	-2.220446e-16	-3.600000e-01	2.000000e+00
   313  2.000000e+00	3.000000e+00	1.300000e+00	4.490000e+00	2.660000e+00	5.432000e+00	2.000000e+00
   314  3.000000e+00	4.000000e+00	0.000000e+00	0.000000e+00	0.000000e+00	0.000000e+00	0.000000e+00
   315  4.000000e+00	5.000000e+00	-3.000000e-01	2.690000e+00	-1.390000e+00	-6.397000e+00	2.000000e+00
   316  5.000000e+00	6.000000e+00	-1.000000e+00	5.000000e+00	-4.500000e+00	-1.927000e+01	2.000000e+00
   317  END YODA_HISTO1D_V2
   318  
   319  `)
   320  
   321  	if !bytes.Equal(got, want) {
   322  		t.Fatalf("sub differ:\n%s\n",
   323  			cmp.Diff(
   324  				string(got),
   325  				string(want),
   326  			),
   327  		)
   328  	}
   329  }