File: testfit.py

package info (click to toggle)
openmolcas 25.02-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 170,204 kB
  • sloc: f90: 498,088; fortran: 139,779; python: 13,587; ansic: 5,745; sh: 745; javascript: 660; pascal: 460; perl: 325; makefile: 17
file content (118 lines) | stat: -rwxr-xr-x 4,703 bytes parent folder | download | duplicates (3)
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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#***********************************************************************
# This file is part of OpenMolcas.                                     *
#                                                                      *
# OpenMolcas is free software; you can redistribute it and/or modify   *
# it under the terms of the GNU Lesser General Public License, v. 2.1. *
# OpenMolcas is distributed in the hope that it will be useful, but it *
# is provided "as is" and without any express or implied warranties.   *
# For more details see the full text of the license in the file        *
# LICENSE or in <http://www.gnu.org/licenses/>.                        *
#                                                                      *
# Copyright (C) 2017, Ignacio Fdez. Galván                             *
#***********************************************************************

# Test the accuracy of the fitting polynomials generated by the genfit.py script.
# The roots and weights are computed at the "data" points and in the midpoints.

from mpmath import mp
from rys_aux import *
import sys

# Set floating point precision
# Single precision (32 bits): 24-bit significand, 6 decimal places
# Double precision (64 bits): 53-bit significand, 15 decimal places
# Quadruple precision (128 bits): 113-bit significand, 33 decimal places
mp.dps = 33

# Read the data from stdin, expected to be a file formated
# as a Molcas "rysrw" file
# Maximum number of roots and degree of fitting polynomials
nmax, fit_degree = (int(i) for i in sys.stdin.readline().split())
# Requested accuracy (not needed)
accuracy = []
while (len(accuracy) < nmax):
  accuracy.extend([mp.mpf(i) for i in sys.stdin.readline().split()])
# Value of x from which the asymptotic approximation is accurate enough (not needed)
xmax = []
while (len(xmax) < nmax):
  xmax.extend([mp.mpf(i) for i in sys.stdin.readline().split()])
# Step for the x values
dx = []
while (len(dx) < nmax):
  dx.extend([mp.mpf(i) for i in sys.stdin.readline().split()])
# Number of x values
nx = []
while (len(nx) < nmax):
  nx.extend([int(i) for i in sys.stdin.readline().split()])
# Number of fitting intervals
npol = []
while (len(npol) < nmax):
  npol.extend([int(i) for i in sys.stdin.readline().split()])
# Map for which fitting interval to use for each x value
# (values are 1-based, so subtract 1)
polmap = [[] for i in range(nmax)]
# And center of each interval (offset value for x)
center = [[] for i in range(nmax)]
for n in range(nmax):
  while (len(polmap[n]) < nx[n]):
    polmap[n].extend([int(i)-1 for i in sys.stdin.readline().split()])
  while (len(center[n]) < npol[n]):
    center[n].extend([mp.mpf(i) for i in sys.stdin.readline().split()])
# Coefficients for all roots and weights and intervals
coeff = [[] for i in range(nmax)]
for n in range(nmax):
  # First read a single list
  tmp = []
  while (len(tmp) < npol[n]*(n+1)*(fit_degree+1)*2):
    tmp.extend([mp.mpf(i) for i in sys.stdin.readline().split()])
  # Then arrange it, the nesting order in the file is:
  #   roots, weights
  #     0th...6th order coefficients
  #       root 1...n
  #         interval 1...npol
  m = 0
  for j in range(2):
    coeff[n].append([])
    for k in range(fit_degree+1):
      coeff[n][j].append([])
      for l in range(n+1):
        coeff[n][j][k].append([])
        coeff[n][j][k][l] = tmp[m:m+npol[n]]
        m += npol[n]

# Now it's time to actually test the fittings for each order of Rys polynomials
for n in range(nmax):
  max_error = [zero, zero]
  # Test all the "data points" (x values) and mid-points too
  for ix in range(2*nx[n]-1):
    x = ix*dx[n]/2

    # Compute roots and weights
    roots, weights = rysroots(n+1, x)

    # Select approximating polynomial
    ipol = polmap[n][int(mp.floor(x/dx[n]))]
    xoff = x-center[n][ipol]
    # For each root and weight calculate the value from the fitting polynomial
    roots_fit = []
    weights_fit = []
    for i in range(n+1):
      pol = []
      for j in range(fit_degree+1):
        pol.insert(0, coeff[n][0][j][i][ipol])
      roots_fit.append(mp.polyval(pol, xoff))
      pol = []
      for j in range(fit_degree+1):
        pol.insert(0, coeff[n][1][j][i][ipol])
      weights_fit.append(mp.polyval(pol, xoff))
    # Obtain the maximum relative error
    error_r = max([abs((a-b)/b) for a,b in zip(roots_fit, roots)])
    error_w = max([abs((a-b)/b) for a,b in zip(weights_fit, weights)])
    error = max(error_r, error_w)
    # Keep separate track of maximum error at data points and mid-points
    i = ix%2
    max_error[i] = max(max_error[i], error)
  print(n+1, figs(max_error[0], exp=True), figs(max_error[1], exp=True))