first push

This commit is contained in:
jean paul nshuti 2025-10-09 09:58:31 +02:00
commit 3fbacaf43d
60 changed files with 334023 additions and 0 deletions

177
Makefile Normal file
View File

@ -0,0 +1,177 @@
######################################################################
# GNU MAKEFILE #
######################################################################
# There may be some trickery involved in this file; most of which is #
# hopefully explained sufficiently. This makefile is unlikely to #
# work with non-GNU make utilities. #
# #
######################################################################
SHELL = /bin/bash
# clear out suffix list
.SUFFIXES :
# declare suffixes allowed to be subject to implicit rules.
.SUFFIXES : .f .o .f90
current_version=4.0c
tarname=NH3-Plus
src = ./src/
build = ./obj/
bin = ./bin/
ldir = $(src)lib/
pdir = $(src)parser/
# DEFINE THE PATH
VPATH = $(src)
VPATH += $(ldir)
VPATH += $(pdir)
# extra dir
extra_dirs = logs nnfits scans
gincl = -I$(src) -I$(pdir) -I$(ldir)
# GFORTRAN COMPILER
FC := gfortran
GFFLAGS = -O2 -fopenmp -fbackslash -fmax-errors=5 -Wall -Werror
GFFLAGS += -std=legacy -cpp -J$(build)
GFFLAGS += $(gincl)
#GFFLAGS += -Wall -Wextra -Werror -Wno-error=integer-division -Wno-error=conversion \
-Wno-error=intrinsic-shadow
GLLAPCK = -llapack
DBGFFLAGS = -O0 -fcheck=bounds -fcheck=do -fcheck=mem -fcheck=pointer -p -debug all
#cGINCL = -I -I$(pdir) -I$(ldir)
GFFLAGS += $(GINCL)
GFFLAGS += $(GLLAPCK)
DBGFFLAGS += $(GLLAPCK)
#IFORT COMPILER
IFC := ifort
IFFLAGS = -O3 -qopenmp -qmkl -fpp -stand f95 -warn all -warn noerrors \
-fp-model precise -traceback -assume byterecl
IFFLAGS += -g -diag-disable=10448
DBGIFC = -O0 -g -check all -traceback -fpp -warn all -fp-stack-check
LDFLAGS = -llapack
# CHOSE THE COMPILER
###########################
COMPILER = $(FC)
ifeq ($(COMPILER),IFC)
FC = $(IFC)
FFLAGS = $(IFFLAGS)
DBGFLAGS = $(DBGIFC)
else
#FC = $(FC)
FFLAGS = $(GFFLAGS)
DBGFLAGS = $(DBGFFLAGS)
endif
######################################################################
### Functions
######################################################################
# return 'true' if file $(1) exists, else return ''
file_exists = $(shell if [ -f $(1) ]; then echo "true"; fi)
# return 'true' if file $(1) doesn't exist, else return ''
file_lost = $(shell if [ ! -f $(1) ]; then echo "true"; fi)
######################################################################
### Objects
######################################################################
# Objects solely relying on ANN parameters
ann_objects = backprop.o ff_neunet.o neuron_types.o \
axel.o nnmqo.o scans.o nnread.o
# Objects relying on both genetic & ANN params
genann_objects = geNNetic.o iNNterface.o puNNch.o \
mkNN.o error.o long_io.o parse_errors.o parser.o
# Objects depending on model
#mod_objects = nnmodel.o nncoords.o
pln_objects = invariants_no3.o nncoords_no3.o genetic_param_no3.o model_no3.o nnadia_no3.o
#pyr_objects = invariants_nh3.o nncoords_nh3.o fit_genetic_Umb.o model_dipole_nh3.o dip_nh3plus_model.o
#mod_objects = invariants_nh3.o nncoords_nh3.o fit_genetic.o \
new_model_dipole.o dip_nh3plus_model.o
# Objects belonging to internal library
lib_objects = misc.o ran_gv.o choldc.o diag.o \
qsort.o dmatrix.o imatrix.o strings.o ran.o \
fileread.o keyread.o long_keyread.o
# Objects from hell; if it exists, don't compile it
hell_objects = $(ldir)random.o
hell_flags = -O3
hell_flags += -llapack
# All objects (one would want to update)
objects = $(addprefix $(build), $(ann_objects) $(genann_objects) $(pln_objects) \
$(lib_objects))
#umb_objects = $(addprefix $(build), $(ann_objects) $(genann_objects) $(pyr_objects) \
$(lib_objects))
#surface_obj = $(addprefix $(build), invariants_nh3.o nncoords_nh3.o nnread.o \
try_param.o model_dipole_nh3.o)
# Name of the main program
main = genANN
######################################################################
### Include files
######################################################################
ann_include = nncommon.incl nndbg.incl nnparams.incl
gen_include = common.incl params.incl keylist.incl errcat.incl
mod_include = JTmod.incl only_model.incl dip_planar_genetic.incl
# Misc. files generated during compilation
trash = *__genmod* *~ *\# *.g .mod
$(main) : $(objects)
ifeq ($(call file_exists,$(hell_objects)),)
$(MAKE) hell
endif
$(FC) $(FFLAGS) $(hell_objects) $(objects) $(LDFLAGS) -o $(bin)$(main)
#$(FFLAGS)
#pyram_ANN : $(umb_objects)
# $(FC) $(FFLAGS) $(hell_objects) $(umb_objects) $(LDFLAGS) -o $(bin)pyram_ANN
# compile a library for the Diabatic Dipole
#libdipole_surface.a : $(surface_obj) $(build)Diabatic_Dipole.o
# ar rcs $(bin)libdipole_surface.a $(surface_obj) $(build)Diabatic_Dipole.o
# EXPLICIT RULE FOR COMPILING
$(build)%.o : %.f
$(FC) -c $(FFLAGS) $< -o $@
$(build)%.o : %.f90
$(FC) -c $(FFLAGS) $< -o $@
# add dependencies to include files
$(ann_objects) : $(ann_include) $(lib_objects)
$(genann_objects) : $(ann_include) $(gen_include) $(lib_objects)
$(mod_objects) : $(ann_include) $(gen_include) $(mod_include) $(lib_objects)
# overrule standard compilation method for hellfiles.
$(hell_objects) : override FFLAGS=$(hell_flags)
nnmqo.o : axel.o
# making
.PHONY : clean dirs neat hell pyram_ANN all
clean:
$(RM) $(objects) $(hell_objects) $(trash) $(bin)/$(main)
dirs:
@mkdir -p $(build) $(bin) $(extra_dirs)
neat:
$(RM) -f $(TRASH)
hell : $(hell_objects)
all : clean hell $(main) pyram_ANN libdipole_surface.a

91406
src/ANN_NH3Plus_few.in Normal file

File diff suppressed because it is too large Load Diff

88
src/Diabatic_Dipole.f Normal file
View File

@ -0,0 +1,88 @@
module Diab_dipole
implicit none
contains
Subroutine Dipole_Diab_nn(X1,Dx,Dy)
use ctrans_mod, only: ctrans
implicit none
include "nnparams.incl"
!include "nncommon.incl"
!include "nndbg.incl"
double precision,intent(inout):: x1(maxnin)
double precision,intent(out):: Dx(4,4),Dy(4,4)
! compute the symmetric coordianate and all the invariants needed for ANN
call ctrans(x1)
! get the diabatic dipole matrix
call coord2Dip(x1,Dx,Dy)
end subroutine Dipole_Diab_nn
! subroutine for DIab dipole
subroutine coord2Dip(nn_in,Dx,Dy)
use diabmodel, only: diab_x,diab_y
implicit none
include "nnparams.incl"
include "nncommon.incl"
include "nndbg.incl"
include "ann.incl"
real(8),intent(in),dimension(maxnin):: nn_in
real(8),intent(out),dimension(4,4):: Dx,Dy
real(8),dimension(maxnout)::nn_out
! call neunet and propagate ANN
call neunet(nn_in,nn_out,netpars)
! generate dibatic matrix
call diab_x(nn_in,Dx,nn_out)
call diab_y(nn_in,Dy,nn_out)
end subroutine coord2Dip
subroutine networkpinit()
implicit none
include 'nnparams.incl' !this includes ANN-parameters
include 'nncommon.incl' !this includes ANN struture restrictions
include 'ann.incl' !this includes ANN structure variables
!include 'netpars.incl' !this contains all network parameters
include 'nndbg.incl' !this includes debug-mode specifics
!real*8 verte1,verte2,verte3
!common /pot_vertical/verte1,verte2,verte3
!save /ann/,/nnio/
!save /pnetwork/
!.....ANN-specific variables
character*32 netfile
! parameter (netfile='network')
! parameter (netfile='Par_no35s_6D') !FF: Original parameter file for the 6D NN with b
parameter (netfile='fit_pars') !FF: New parameter file for the 6D refitt
! write in the output
write(6,*) "# NH3Plus Dipole for 4 states"
write(6,*) "# use the PES Of Maik"
write(6,*) "# Last update 22.09.2025"
write(6,*) "# Only the stretch cuts"
call nninit_mod()
call read_net_prim(netfile,netpars,nlay,laystr,weistr,typop)
!! get energies at reference point
! nn_in=0.0d0
! len_in=laystr(1,1)
! len_out=laystr(1,nlay)
!
!! propagate ANN
! call neunet(nn_in,nn_out,netpars)
!! generate diabatic matrix from ANN output
! call nndiab(nn_in,diab_matr,nn_out)
End subroutine
subroutine nninit_mod()
implicit none
include 'nnparams.incl'
end subroutine
end module

1
src/JTmod.incl Symbolic link
View File

@ -0,0 +1 @@
JTmod-v1.0.incl

50
src/README Normal file
View File

@ -0,0 +1,50 @@
makepar.sh
here the input is used to generate and save the parameters for the NN
The program should run well with:
valgrind --main-stacksize=100000000 --max-stackframe=150000000
(sizes may vary)
used directories:
.
../bin
../nnfits
../logs
../scans
./: the source directory
../bin/:
Directory in which binaries are stored and executed. Input files
are copied here.
../nnfits/:
Directory in which a copy of the program outout is stored, as well as
fitted parameters of the best (fit_pars.in) and 10th percentile
(fit_10p.in) network.
../logs/:
Directory in which the convergence of the different networks is logged
and summarized in performance.log.
../scans/:
Fitting results of the particular scans are dumped as functions of a
progression parameter t.
input file nomenclature:
diab_* : fit against diabatic energies
*_ci_* : include CI information
*_en_* : exclude CI information (energies only)
gen_* : input generation file
*_minmodel_* : use minimal model of only 2 basis matrices
*_tmcs_* : use tmc coordinates
*_small_* : within a small coordinate range (~0.5-2.5)

20
src/ann.incl Normal file
View File

@ -0,0 +1,20 @@
****Basic data structures and special constants for ANN
***
*** /ann/: block containing basic structural information
*** required for propagation etc
***
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
real*8 netpars(wbcap)
common /ann/ nlay, laystr, weistr, typop
common /pnetwork/ netpars
!!! add

317
src/axel.f Normal file
View File

@ -0,0 +1,317 @@
************************************************************************
*** aXel
*** convergence accelerators for ANN's Marquardt-Levenberg
***
************************************************************************
module axel
implicit none
contains
subroutine mqlimstep(wbsteps,wbnorm,gradnorm,fails,lambda,
> mqfact,weistr,nlay)
implicit none
! Rescales step if stepsize restrictions are violated.
!
! Depending on the size of each parameter, this subroutine
! establishes a maximum allowed size for the parameter's
! corresponding step. This maximum size is absolute for small
! parameter sizes (below the given threshold), but scales relatively
! to the current parameter value for larger ones. The entire step
! vector is normalized in such a way that the largest offending
! stepsize is reduced to it's maximum allowed value. Additionally,
! if the total length of the step vector exceeds a certain trust
! radius, it is renormalized as well.
!
! wei_end: position of last defined weight in W-vector
! lay_end: position of last defined bias in B-vector
! len_in: number of input-neurons. Since they have no biases
! B(1:len_in) is meaningless.
! large_rel: number of relative threshold violations in step
! large_abs: number of absolute threshold violations in step
!
!
! W: weight matrix vector
! B: bias vector
! wbsteps: steps for weights and biases, same order as a single
! jacobian-row.
!
! stepsize-control parameters for WEIghts and BIases
!
! wb_arad: maximal length of a single step through the entire parameter space,
! aka the trust radius
! *_alim: threshold for switching from relative to absolute scaling
! *_ascale: multiplicative factor by which parameter size is multiplied
! to determine relative maximum step size
! *_amax: hard step limit for small parameter values
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision wbsteps(wbcap)
double precision lambda,wbnorm,gradnorm
double precision mqfact
integer weistr(2,maxlay,2),nlay
integer fails
double precision scale
integer jac_end
jac_end=weistr(2,nlay,2)
write(6,*) 'CHECKNORM'
write(6,*) wbnorm,gradnorm
if (wbnorm.gt.gradnorm*unit_con) then !? does that make sense???
write(6,*) 'FIXING..'
scale=gradnorm*unit_con/wbnorm
wbsteps(1:jac_end)=wbsteps(1:jac_end)*scale
wbnorm=sqrt(dot_product(wbsteps(1:jac_end),wbsteps(1:jac_end)))
! undo whatever happened in the last step to lambda
if (fails.eq.0) then
lambda=lambda*mqfact
else
lambda=lambda/mqfact
endif
endif
write(6,*) wbnorm
end subroutine
!--------------------------------------------------------------------------------------
subroutine renorm_input(pat_in,npat,preserve,par,
> laystr,weistr)
implicit none
! Evaluate average and standard deviation of input set and generate
! shifts and normalization factors such that they are normalized to
! an average of 0 and a variance of 1, respectively. If an input is
! constant, do not normalize the variance.
!
! If preserve is true, the network which is assumed to already have
! been fitted will be manipulated such that, given the initial
! values of fact_in and shift_in, it will yield the same output as
! before.
!
! This works as follows: Let u,v be differently normalized versions
! of x and f(u) a function fitted using the data set {u}.
! u and v are given by
!
! u = D1^-1 (x - x1) and
! v = D2^-1 (x - x2).
!
! Since v(x) is invertible we can transform f(u) into an equivalent
! g(v) using f(u(x)) = f(u(v^-1(v(x)))) =: g(v(x))
!
! x = D2 v + x2
! => u(v) = D1^-1 (D2 v + x2 - x1)
! u(v) = D1^-1 D2( v + D2^-1 (x2 - x1))
! = D12 (v - x12)
!
! A transformation of that form can easily be pulled into the ANN
! parameters using the routine unnorm_input.
include 'params.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision par(wbcap)
double precision pat_in(maxnin,maxpats)
integer laystr(3,maxlay), weistr(2,maxlay,2)
integer npat
logical preserve
double precision old_shift(maxnin), old_fact(maxnin)
double precision diff_shift(maxnin),diff_fact(maxnin)
integer j
if (preserve) then
old_shift=shift_in
old_fact=fact_in
endif
! get mean for input data
call safe_average(pat_in,shift_in,len_in,maxnin,npat)
! get variance for input data
call safe_variance(pat_in,shift_in,fact_in,len_in,maxnin,npat)
! generate actual norms
do j=1,len_in
fact_in(j)=dsqrt(fact_in(j))
if (dbg) then
write(6,'(A,I3.3,A,F8.4)') "Computed factor #", j,
> ": ",fact_in(j)
endif
if (fact_in(j).le.zero) then
write(6,'(A,I3.3,A,ES10.2)') "WARNING: Nigh-constant"
> // " coordinate #",j,": ",fact_in(j)
if (vbs) then
write(6,'(A,I3.3)') "Skipping normalization "
> // "of coordinate #", j
endif
fact_in(j) = 1.0d0
endif
enddo
if (preserve) then
! Compute shift displacement x12
do j=1,len_in
diff_shift(j)=(old_shift(j)-shift_in(j))/fact_in(j)
enddo
! Compute factor change D12
do j=1,len_in
diff_fact(j)=old_fact(j)/fact_in(j)
enddo
write(6,'("Absorbing coordinate scaling factors into ANN: ")')
call printvec_full(diff_fact,'(ES12.4)',8,len_in,5)
write(6,'("Absorbing coordinate shift into ANN: ")')
call printvec_full(diff_shift,'(ES12.4)',8,len_in,5)
if (all(abs(diff_shift(1:len_in)).le.zero)
> .and. all(abs(diff_fact(1:len_in)-1.d0).le.zero)) then
write(6,'("REMARK: Shifts and scaling factors'
> // ' near identical to data set.")')
endif
! integrate differences into network
call unnorm_input(par,laystr,diff_shift,diff_fact,weistr)
endif
end subroutine
!--------------------------------------------------------------------------------------
subroutine init_input(lay_in,pat_in,shift,norm,len_in)
! Initialize input layer with optimized coordinates.
!
! Ideally, each coordinate should be normalized such that it has an
! average of 0 and a variance of 1.
implicit none
include 'nnparams.incl'
include 'nndbg.incl'
integer len_in
double precision lay_in(len_in),pat_in(maxnin)
double precision shift(maxnin),norm(maxnin)
integer k
do k=1,len_in
lay_in(k)=(pat_in(k)-shift(k))/norm(k)
enddo
end subroutine
!--------------------------------------------------------------------------------------
subroutine unnorm_input(par,laystr,shift_in,fact_in,weistr,
> preserve)
implicit none
! Transfer factors and shifts from input normalization to first
! weight matrix and bias, respectively. The equations read as
! follows:
!
! For any un-normalized input vector x we can find a normalized
! counterpart
!
! v = D^-1 (x - <x>),
!
! where D is a diagonal matrix of the standard deviations of the
! respective input coordinate (input layer entry) and <x> is a
! vector of the input layer averages. A feed-forward network fitted
! against the input set {v} hence initially calculates
!
! a = W v + B = W D^-1 (x - <x>) + B
! = (W D^-1) x + (B - W D^-1 <x>)
!
! W,B being the weights matrix and bias vector of the first layer.
! It follows easily that transforming W and B to W' and B' using
!
! W' = W D^-1
! B' = B - W' <x>
!
! we yield a re-parametrized network taking the original coordinates
! x as input.
!
! If preserve is true, this routine acts non-destructively on
! shift_in, fact_in. Absent is equivalent to false.
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nndbg.incl'
integer laystr(3,maxlay)
integer weistr(2,maxlay,2)
double precision par(wbcap)
double precision shift_in(maxnin),fact_in(maxnin)
logical, intent(in), optional :: preserve
integer len_in
double precision norm_in(maxnin),new_shift(maxneu)
integer j
len_in=laystr(1,1)
do j=1,len_in
norm_in(j)=1.0d0/fact_in(j)
enddo
! rescale weights:
call rescalemat_in(par(weistr(1,1,1)),norm_in,
> len_in,laystr(1,2))
call dmatvec(par(weistr(1,1,1)),shift_in,new_shift,
> len_in,laystr(1,2))
new_shift=-new_shift
! shift biases:
call shiftmat(par(weistr(1,2,2)),new_shift,laystr(1,2),1)
if ((.not.present(preserve)).or.(.not.preserve)) then
fact_in=1.0d0
shift_in=0.0d0
endif
end subroutine
!--------------------------------------------------------------------------------------
double precision function sim_score(x,y,zero)
! Function to measure similarity between two values, giving them a
! score between 1 (identical) and 0 (opposing/far apart).
!
! If both values are small enough that their abs. values are below
! the threshold argument zero, they are treated as identical
! regardless of actual value. In any other case, values which
! differ by sign are considered opposite, yielding 0.
implicit none
double precision zero,x,y
double precision sgn,maxpar,minpar
! Check whether x and y have the same sign
sgn=sign(1.0d0,x)*sign(1.0d0,y)
maxpar=max(dabs(x),dabs(y))
if (maxpar.le.zero) then
! penalize numerical zeros
sim_score=1.0d0
else if (sgn.le.0.0d0) then
sim_score=0.0d0
else
minpar=min(dabs(x),dabs(y))
sim_score=minpar/maxpar
endif
end function
end module

105
src/backprop.f Normal file
View File

@ -0,0 +1,105 @@
!--------------------------------------------------------------------------------------
subroutine backprop(del,W,deriv,laystr,nlay)
implicit none
! Backpropagates full FF-NN with given output-errors.
! nlay: number of given layers
! nprop: number of single-layer propagations
! neu_io: number of neurons in giv./prev. layer
! neu_oi: number of neurons in prev./giv. layer
! poslay: starting position of layer in L- and B-vector
! poswei: starting position of Weight-Matrix in W-vector
!
! del: Neuron Error Vector
! deriv: Activation function derivatives
! W: Weight Matrix Vector
! laystr: Layer Structure Matrix
!
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for Weight Matrix from layer N to N+1
include 'nnparams.incl'
include 'nndbg.incl'
integer nlay,laystr(3,maxlay)
double precision del(neucap),deriv(neucap)
double precision W(maxwei)
integer poslay,poswei,nprop,neu_io,neu_oi
integer k
nprop=nlay-1
! evaluate deltas
neu_io=laystr(1,nlay) !number of input neurons
do k=nprop,2,-2
neu_oi=laystr(1,k) !number of output neurons
poslay=laystr(2,k)
poswei=laystr(3,k)
call backlay(neu_io,neu_oi,del(poslay),W(poswei),
> deriv(poslay))
neu_io=laystr(1,k-1) !new number of output neurons
poslay=laystr(2,k-1)
poswei=laystr(3,k-1)
! former output neurons are now input, _io and _oi switch places!
! (done for efficiency)
call backlay(neu_oi,neu_io,del(poslay),W(poswei),
> deriv(poslay))
enddo
do k=1,mod(nprop,2) !for odd nprop one iteration is left
neu_oi=laystr(1,1)
poslay=laystr(2,1)
poswei=laystr(3,1)
call backlay(neu_oi,neu_io,del(poslay),W(poswei),
> deriv(poslay))
enddo
end
!--------------------------------------------------------------------------------------
subroutine backlay(neu_in,neu_out,del,W,deriv)
implicit none
! Backpropagates given layer in FF-NN.
! neu_in: number of neurons in layer N+1
! neu_out: number of neurons in layer N
!
!
! del: Neuron Error Vector
! W: Weight Matrix (layer N to layer N+1)
! deriv: Derivative Vector (beginning at layer N)
!
include 'nnparams.incl'
include 'nndbg.incl'
integer neu_in,neu_out
double precision del(neu_out+neu_in),deriv(neu_out)
double precision W(neu_out,neu_in)
integer j,k
do j=1,neu_out
del(j)=0.0D0
enddo
do k=1,neu_in
do j=1,neu_out
del(j)=del(j)+del(neu_out+k)*W(j,k)
enddo
enddo
do k=1,neu_out
del(k)=del(k)*deriv(k)
enddo
end

1
src/clear Symbolic link
View File

@ -0,0 +1 @@
/mnt/home.ipr/jnshuti/Documents/work/NH3+/Dipole-4-4/Dipole_NH3/Pyramidal/20few_points.genetic

51
src/common.incl Normal file
View File

@ -0,0 +1,51 @@
!.. npar: number of parameters
!.. pst: starting addresses and lengths of parameter blocks
integer npar, pst(2,100)
common /parnum/ npar, pst
******************************************************************************
**** Syntactic & Parsing parameters
***
*** keylist: Registry of keys containing the name of the key
*** and it's type information.
*** keylist(N,1): keyname. It should be in all-caps.
*** keylist(N,2): type string of the form "X#"
*** keynum: actual number of keys on keylist
*** datpos: integer array assigning read values to the keys
*** datpos(1,N): internalized type (0: I, 1: +I, 2: D, 3: +D,
*** 4: C, 5: E)
*** datpos(2,N): starting pos. in respective data array
*** datpos(3,N): length of data block
integer keynum,datpos(3,maxdat)
character*(klen) keylist(2,maxkeys)
character*64 errcat(maxerrors)
common /synt/ datpos,keynum,keylist,errcat
******************************************************************************
**** Misc. fit modifiers
***
*** zero_par: set all fitting parameters to zero
*** legacy_wt: WT:-cards are expected for each output component
*** individually
*** walk_scan: if true, map scans to the unit interval [0,1]
*** otherwise, dump full coordinate vector instead.
logical zero_par, legacy_wt
logical walk_scan
common /fitmisc/ zero_par, legacy_wt, walk_scan
******************************************************************************
**** Generic error analysis parameters
***
*** cutoff: maximal value to be considered for each output in the
*** context of an unweighted error
*** showcut: if true, calculate unweighted errors with cutoff thresholds
double precision cutoff(maxoutp),cutwei(maxoutp)
logical showcut
common /eval/ cutoff, cutwei, showcut

BIN
src/ctrans_mod.mod Normal file

Binary file not shown.

530
src/dmatrix.f Normal file
View File

@ -0,0 +1,530 @@
************************************************************************
*** dmatrix
*** generic double precision matrix operations
***
************************************************************************
subroutine permutemat(oldmat,newmat,perm_row,perm_col,nrow,ncol)
implicit none
! Allows to perform arbitrary permutations of row- and column
! entries of the matrix (corresponding to permutations of the
! underlying basis sets).
!
! Permutations are symbolized as integer vectors. They should
! contain each number from 1 to nrow/ncol in the desired new order,
! 1 meaning the originally first entry etc.
!
! (1,2,3,..) -Permutation-> (P(1),P(2),...)
!
! oldmat: matrix to be modified
! newmat: generated matrix
! nrow: dimension of row-vectors
! ncol: dimension of column vectors
! perm_*: permutation applied to row or column
!
integer nrow,ncol
integer perm_row(nrow),perm_col(ncol)
double precision oldmat(nrow,ncol),newmat(nrow,ncol)
integer j,k
! check validity of permutations (pidgeonhole principle)
do j=1,nrow
if (.not.any(perm_row.eq.j)) then
write(6,'(A)') 'ERROR: INVALID PERMUTATION'
> // ' VECTOR (permutemat)'
stop 1
endif
enddo
do j=1,ncol
if (.not.any(perm_col.eq.j)) then
write(6,'(A)') 'ERROR: INVALID PERMUTATION'
> // ' VECTOR (permutemat)'
stop 1
endif
enddo
do j=1,ncol
do k=1,nrow
newmat(k,j)=oldmat(perm_row(k),perm_col(j))
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine rescalemat_out(mat,factors,nrow,ncol)
implicit none
! Rescale output of matrix mat in each dimension with the
! corresponding entry in factors. This is equivalent to multiplying
! an appropriate diagonal matrix from the lefthand side. The
! original matrix is destroyed in the process.
!
! mat: matrix to be scaled
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), factors(ncol)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)*factors(j)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine rescalemat_in(mat,factors,nrow,ncol)
implicit none
! Rescale input of matrix mat in each dimension with the
! corresponding entry in factors. This is equivalent to multiplying
! an appropriate diagonal matrix from the righthand side. The
! original matrix is destroyed in the process.
!
! mat: matrix to be scaled
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), factors(nrow)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)*factors(k)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine dmatvec(mat,vec_in,vec_out,nrow,ncol)
implicit none
! Multiply matrix vec with compatible vector vec_in, yielding
! vec_out.
!
! mat: matrix to be scaled
! vec_*: vectors as describe above
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), vec_in(nrow), vec_out(ncol)
integer j,k
vec_out=0.0d0
do j=1,ncol
do k=1,nrow
vec_out(j)=vec_out(j) + mat(k,j)*vec_in(k)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine shiftmat(mat,shift,nrow,ncol)
implicit none
! Add two identically dimensioned matrices mat and shift,
! overwriting mat.
!
! mat: matrix to which shift is added
! shift: addend
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), shift(nrow,ncol)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)+shift(k,j)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine phaselock_maxpos(vectors,vecdim,nvec,maxdim)
implicit none
! Normalizes phases of an array of vectors according to molpro standard,
! meaning that the value furthest from 0 is positive in each vector.
!
! vectors: matrix containing all vectors.
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec)
double precision maxelem,minelem
integer j
do j=1,nvec
maxelem=maxval(vectors(1:vecdim,j))
minelem=minval(vectors(1:vecdim,j))
if (dabs(minelem).gt.maxelem) then
vectors(1:vecdim,j)=-vectors(1:vecdim,j)
endif
enddo
end
!--------------------------------------------------------------------------
subroutine orderlock_maxolap(vectors,ref_vectors,vecdim,
> nvec,maxdim)
implicit none
! Normalizes the order of an array of vectors such that
! similar vectors appear in similar positions.
! The first reference vector takes priority over the second,
! the 2nd over the 3rd etc.
! vectors: matrix containing all vectors.
! ref_vectors: reference vector set
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec),ref_vectors(maxdim,nvec)
double precision olap, maxolap
double precision swap(maxdim)
integer best
integer j,k
do j=1,nvec
! find the vector most similar to reference, using scalar products
maxolap=0.0D0
best=j
do k=j,nvec
! calculate overlap
olap=dabs(dot_product(vectors(1:vecdim,k),
> ref_vectors(1:vecdim,j)))
if (olap.gt.maxolap) then
! update best overlap and mark vector
maxolap=olap
best=k
endif
enddo
! swap places of vectors accordingly
swap=vectors(:,j)
vectors(:,j)=vectors(:,best)
vectors(:,best)=swap
enddo
end
!--------------------------------------------------------------------------
subroutine phaselock_maxolap(vectors,ref_vectors,vecdim,
> nvec,maxdim)
implicit none
! Normalizes phases of an array of vectors such that scalar products
! of corresponding reference vectors are always non-negative.
! vectors: matrix containing all vectors.
! ref_vectors: reference vector set
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec),ref_vectors(maxdim,nvec)
double precision olap
integer j
do j=1,nvec
! calculate overlap
olap=dot_product(vectors(1:vecdim,j),
> ref_vectors(1:vecdim,j))
if (olap.lt.0.0D0) then
vectors(1:vecdim,j) = -1.0D0*vectors(1:vecdim,j)
endif
enddo
end
!--------------------------------------------------------------------------
subroutine safe_average(points,avrg,dim,maxdim,npoints)
implicit none
! Generates the average over a set of dim-dimensional vectors in a
! safe fashion using Kahan Summation.
!
! maxdim: physical dimension of vectors
! dim: actual dimension of vectors
! npoints: number of vectors
! points: array of vectors of length (max)dim.
! avrg: final mean vector
!
integer maxdim
integer dim,npoints
double precision points(maxdim,*), avrg(maxdim)
double precision tmp(maxdim)
double precision norm
integer j,k
norm=dble(npoints)
tmp=0.0d0
avrg=0.0d0
do j=1,npoints
do k=1,dim
call KahanAdd(points(k,j),avrg(k),tmp(k))
enddo
enddo
do k=1,dim
avrg(k)=avrg(k)/norm
enddo
end
!--------------------------------------------------------------------------
subroutine safe_variance(points,avrg,var,dim,maxdim,npoints)
implicit none
! Generates the variance over a set of dim-dimensional vectors in a
! safe fashion using Kahan Summation.
!
! maxdim: physical dimension of vectors
! dim: actual dimension of vectors
! npoints: number of vectors
! points: array of vectors of length (max)dim.
! avrg: mean vector
! var: final variance vector
!
integer maxdim
integer dim,npoints
double precision points(maxdim,*), avrg(maxdim), var(maxdim)
double precision tmp(maxdim)
double precision norm
integer j,k
norm=dble(npoints)
tmp=0.0d0
var=0.0d0
do j=1,npoints
do k=1,dim
call KahanAdd((points(k,j)-avrg(k))**2,var(k),tmp(k))
enddo
enddo
do k=1,dim
var(k)=var(k)/norm
enddo
end
!--------------------------------------------------------------------------
subroutine KahanSum(terms,nterms,sum)
implicit none
! Sums over all nterms entries in the vector terms using Kahan Summation.
! It utilizes an algorithm recovering low-order digits of added terms
! Taken from Wikipedia.
! Algebraically, the variable corr should always be zero. Beware
! overly-aggressive optimizing compilers.
integer nterms
double precision terms(nterms)
double precision sum
double precision corr,tmp,newsum
integer j
sum=0.0d0
corr=0.0d0 ! A running compensation for lost low-order bits.
do j=1,nterms
tmp = terms(j) - corr ! try to add collected lost lower digit summations to sum
newsum = sum + tmp ! low-order digits of tmp are lost to summation
! cancels high-order part of tmp
! subtracting tmp recovers low part of the term
corr = (newsum - sum) - tmp
sum = newsum
enddo
end
!--------------------------------------------------------------------------
subroutine KahanAdd(term,sum,corr)
implicit none
! Add term to sum using Kahan Summation.
! It utilizes an algorithm recovering low-order digits of added terms
! Taken from Wikipedia.
! Algebraically, the variable corr should always be zero. Beware
! overly-aggressive optimizing compilers.
double precision term,sum,corr
double precision tmp,newsum
tmp = term - corr ! try to add collected lost lower digit summations to sum
newsum = sum + tmp ! low-order digits of tmp are lost to summation
! cancels high-order part of tmp
! subtracting tmp recovers low part of the term
corr = (newsum - sum) - tmp
sum = newsum
end
!--------------------------------------------------------------------------
subroutine writemat(funit,mat,matfmt,flen,nrow,ncol,
> nrow_print,ncol_print)
implicit none
! Write (submatrix of) matrix mat using format matfmt on each
! individual value to file unit funit.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen,funit
integer nrow,ncol
integer nrow_print,ncol_print
double precision mat(nrow,ncol)
character*(flen) matfmt
integer j,k
if (nrow_print.gt.nrow) then
write(6,'(A)') 'ERROR: CANNOT PRINT BEYOND MATRIX WIDTH'
> // ' (printmat)'
stop 1
else if (ncol_print.gt.ncol) then
write(6,'(A)') 'ERROR: CANNOT PRINT BEYOND MATRIX HEIGHT'
> // ' (printmat)'
stop 1
endif
do j=1,ncol_print
do k=1,nrow_print
write(unit=funit,fmt=matfmt,advance='NO') mat(k,j)
enddo
write(funit,'()')
enddo
end
!--------------------------------------------------------------------------
subroutine printmat_full(mat,matfmt,flen,nrow,ncol)
implicit none
! Print matrix mat using format matfmt on each
! individual value.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen
integer nrow,ncol
double precision mat(nrow,ncol)
character*(flen) matfmt
integer stdin
parameter (stdin=6)
call writemat(stdin,mat,matfmt,flen,nrow,ncol,nrow,ncol)
end
!--------------------------------------------------------------------------
subroutine writevec(funit,vec,vecfmt,flen,len,wraplen)
implicit none
! Write vector vec of length len in blocks of length wraplen.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen,funit
integer len,wraplen
double precision vec(len)
character*(flen) vecfmt
integer wordcount
integer j
wordcount=0
do while (wordcount.lt.len)
do j=1,min(wraplen,len-wordcount)
wordcount=wordcount+1
write(unit=funit,fmt=vecfmt,advance='NO') vec(wordcount)
enddo
write(funit,'()')
enddo
end
!--------------------------------------------------------------------------
subroutine printvec_full(vec,vecfmt,flen,len,wraplen)
implicit none
! Print vector vec of length len in blocks of length wraplen.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen
integer len,wraplen
double precision vec(len)
character*(flen) vecfmt
integer stdin
parameter (stdin=6)
call writevec(stdin,vec,vecfmt,flen,len,wraplen)
end

196
src/error.f Normal file
View File

@ -0,0 +1,196 @@
*** Define subroutine to generate output layer error for one pattern,
*** as well as the derivate of the error in respect to the neuronal output
***
***
***
****Conventions:
***
*** Most of the data structures are larger than declared;
*** however, only their relevant subsection is passed to the
*** subroutine and hence considered.
***
*** nnerror: subroutine evaluating the output layer's error.
***
*** nnweight: system specific weight adaptions for fit
***
*** pat_err: segment of the total error vector for one pattern.
***
*** len_in: Actual number of input neurons
*** len_out: Actual number of output neurons
***
*** pat_in: Input pattern
*** pat_in(i): value of ith input neuron for given pattern
***
*** pat_out: Desired output pattern
*** pat_out(i): desired value of ith output neuron for given pattern
***
*** L: Final layer, starting at the first neuron
***************************************************************************
****Note:
*** neu_in and neu_out, if needed, should ideally not be hardcoded.
*** Instead they should be passed by the main program to ensure
*** matching dimensionalities.
***
***************************************************************************
subroutine nnerror(pat_err,pat_in,pat_out,nn_out)
implicit none
! Generate error vector from adiabatic model.
!
! nn_out: output from neural network
! pat_err: error vector for single pattern
!
include 'nnparams.incl'
include 'nndbg.incl'
include 'nncommon.incl'
double precision nn_out(maxnout)
double precision pat_in(maxnin),pat_out(maxpout),pat_err(maxpout)
double precision adiaoutp(maxpout)
integer j
call nnadia(pat_in,nn_out,adiaoutp)
do j=1,inp_out
pat_err(j) = pat_out(j) - adiaoutp(j)
enddo
end
!--------------------------------------------------------------------------------------
subroutine nnweight(wterr,pat_out)
implicit none
! Evaluate system specific weighting for 1 pattern.
include 'params.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'JTmod.incl'
double precision wterr(maxpout),pat_out(maxpout)
double precision eref(nstat)
double precision wten(3)
integer j
wten=1
eref(1)=E0_sig
eref(2:3)=E0_pi
! eref(1:3)=eref(1:3)+600.d0*icm2hart
eref(1:3)=eref(1:3)+1000.d0*icm2hart
!! kill state 2 and 3
! wten(2:3)=0
do j=1,3
! weighting of energies
wterr(j)=wdamp(pat_out(j)-eref(j))*wterr(j)*wten(j)
enddo
contains
double precision function wdamp(dE)
implicit none
include 'nnparams.incl'
double precision dE
! Weight decay rate
double precision, parameter :: unit=eV2hart
! ln(3)/2 = artanh(1/2)
! double precision, parameter :: alpha=0.5d0*log(3.d0)/unit
! (1+tanh(-x))/2 ~ exp(-2x)
! double precision, parameter :: alpha=0.5d0*log(2.d0)/unit
!
double precision, parameter :: alpha=log(10.d0)/unit
! cutoff
double precision, parameter :: minweight=1.d-4
! asymptotically,
! wdamp=(1.d0+tanh(-alpha*dE))*0.5d0 + minweight
wdamp=1.0d0
if (dE.lt.0) then
wdamp=1.d0
else if (dE.lt.(4*eV2hart)) then
wdamp=exp(-alpha*dE)+minweight
else
wdamp=0
endif
end function wdamp
end subroutine
!--------------------------------------------------------------------------------------
subroutine nnoutgrad(ad_grads,pat_in,nn_out)
implicit none
! Compute the derivative of each output value (i.e. adiab. energies)
! with respect to the Neural Network output-neurons.
!
! nn_out: output from neural network
! ad_grads: derivatives as described above
! ad_grads(:,i): gradient of energy i
! eps: finite differences for derivatives
! eps(i): finite difference for output neuron i
! dis_out: ANN output displaced by finite differences
! dis_out(:,1): equivalent to L + eps
! dis_out(:,2): equivalent to L - eps
! dis_ad: yielded adiabatic output for current displacements
!
! ddelta: factor used to determine eps.
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision nn_out(maxnout)
double precision pat_in(maxnin)
double precision ad_grads(maxnout,maxpout)
double precision eps(maxnout),dis_out(maxnout,2)
double precision dis_ad(maxpout,2)
double precision ddelta
integer n,j,k
parameter (ddelta = 1.0D-2) !reduce again if appropriate
! determine appropriate finite differences for each parameter:
do k=1,len_out
eps(k)=abs(nn_out(k))*ddelta
if (eps(k).lt.zero) then
eps(k)=zero
endif
enddo
do n=1,len_out
do k=1,2
! copy ANN-output
do j=1,len_out
dis_out(j,k) = nn_out(j)
enddo
enddo
! apply finite difference for output-neuron n
dis_out(n,1) = dis_out(n,1) + eps(n)
dis_out(n,2) = dis_out(n,2) - eps(n)
do k=1,2
! get energies and ci-values
call nnadia(pat_in,dis_out(1,k),dis_ad(1,k))
enddo
! apply finite differences to generate numerical gradient
do k=1,inp_out
ad_grads(n,k) = (dis_ad(k,1)-dis_ad(k,2))/(2.0d0*eps(n))
enddo
enddo
end

204
src/essential_params.incl Normal file
View File

@ -0,0 +1,204 @@
!**** Declarations
double precision pi,infty,zero
double precision scan_res
double precision hart2eV, eV2hart
double precision hart2icm, icm2hart
double precision eV2icm, icm2eV
double precision deg2rad, rad2deg
integer maxneu,maxlay,maxtypes,maxtpar
integer maxpats
integer maxnin,maxnout,maxpout
integer maxwei,neucap,wbcap
integer maxset, maxnnkeys
integer maxxrmeta,xrcap
integer iinfty
integer iout,nnunit,perfunit,fitunit
integer ec_error,ec_read,ec_dim,ec_log
integer ec_dimrd
integer record_read,record_write,record_overwrite
integer record_update
character*2 newline
character*8 stdfmt
character*8 nnldir
character*8 nntag
character*16 prim_tag
character*16 nnfdir,nnsdir
character*16 sline,asline,hline
character*16 mform,smform,miform
character*16 lrfmt,lifmt
character*32 nndmpfile,nnexpfile
character*32 nndatfile,nnreffile
character*32 sampfile,perfile
character*32 nnparfile,nnp10file
character*32 nnrecfile
!**********************************************************
!**** Parameters
!*** maxneu: max. number of neurons per hidden layer
!*** maxnin: max. number of neurons in input layer
!*** maxnout: max. number of neurons in output layer
!*** maxset: max. number of neural networks to fit
!*** maxpout: max. number of values in output pattern
!*** maxlay: max. number of layers (always >2)
!*** maxtypes: max. number of neuron types
!*** maxtpar: max. number of parameters for each neuron type
!*** maxpats: max. number of learning patterns
!*** maxxrmeta: max. number of metadata-blocks in xranges
!*** WARNING: maxnout should not be > maxneu, deriv-like structures
!*** assume so.
parameter (maxneu=150,maxnin=20,maxnout=15)
parameter (maxpout=15,maxset=10000)
parameter (maxlay=3,maxtypes=2,maxtpar=1)
parameter (maxpats=50000)
parameter (maxxrmeta=3)
!**********************************************************
!**** Inferred Parameters
!*** maxwei: max. total number of weight matrix elements
!*** neucap: max. total number of neurons
!*** wbcap: max. total number of weights and biases
!*** xrcap: max. total number of used dimensions in xranges
parameter (maxwei=(maxlay-3)*maxneu**2+maxneu*(maxnin+maxnout))
parameter (neucap=(maxlay-2)*maxneu+maxnin+maxnout)
parameter (wbcap=maxwei+neucap)
parameter (xrcap=2+maxxrmeta)
parameter (maxnnkeys=4*maxlay)
!*** WARNING: maxwei may fail for 2-layered networks
!*** if maxnin*maxnout is sufficiently large!
!**********************************************************
!**** Numerical Parameters
!*** infty: largest possible double precision real value.
!*** iinfty: largest possible integer value.
!*** zero: sets what is considered an irrelevant difference
!*** in size. use for comarison of reals, to determine
!*** 'dangerously small' values, etc
!*** scan_res: maximum precision for geometric boundary algorithm
! 3.14159265358979323846264338327950...
parameter (pi=3.1415926536D0)
parameter (infty=huge(1.0D0),iinfty=huge(1))
parameter (zero=1.0D-8,scan_res=1.0D-8)
!**********************************************************
!**** Unit Conversion Parameters
!*** X2Y: convert from X to Y.
!***
!**** !? currently inexact. FIX THIS.
!*** hart: hartree
!*** eV: electron volt
!*** icm: inverse centimeters (h*c/cm)
!****
!*** deg: degree
!*** rad: radians
parameter (hart2icm=219474.69d0)
parameter (hart2eV=27.211385d0)
parameter (eV2icm=hart2icm/hart2eV)
parameter (icm2hart=1.0d0/hart2icm)
parameter (eV2hart=1.0d0/hart2eV)
parameter (icm2eV=1.0d0/eV2icm)
parameter (deg2rad=pi/180.0d0)
parameter (rad2deg=1.0d0/deg2rad)
!**********************************************************
!**** I/O Parameters
!*** iout: standard output for vranf error messages
!*** nnunit: temporary UNIT for misc. output files
!*** nnuit + [0..99] are reserved for futher
!*** unspecific misc. files.
!*** perfunit: UNIT for performance logfile
!*** fitunit: UNIT added to random positive integer
!*** identifying a single core fit UNIQUELY
!***
!*** lrfmt: format for long real output
!*** lifmt: format for long integer output
!***
!*** nndatfile: filename for DATA-files
!*** (without file extension)
!*** nnreffile: filename for reference DATA-blocks
!*** (without file extension)
!*** nnparfile: filename for best fitted parameters to be
!*** written on (without file extension)
!*** nnp10file: filename for the 10th percentile parameters to
!*** be written on (without file extension)
!*** nnexpfile: filename for modified neural network parameters
!*** (without file extension)
!*** sampfile: filename for displaying sampled points in
!*** configuration space
!*** nndmpfile: filename for dumping data point pairs
!*** nnrecfile: filename for writing parameter records.
!*** perfile: filename for logged fitting performances.
!*** nntag: infix for various filenames to mark their origin
!*** program should end with a trailing '_' if nonempty.
!*** prim_tag: tag added to the '***' line of primitive par-files
!*** nnfdir: directory for dumping fit files
!*** nnsdir: directory for dumping scans.
!*** nnldir: directory for dumping logfiles for each fit
parameter (nndatfile='DATA_ANN')
parameter (nnreffile='REF_ANN')
parameter (nnparfile='../nnfits/fit_pars')
parameter (nnp10file='../nnfits/fit_10p')
parameter (nnexpfile='../nnfits/exp_pars')
parameter (nndmpfile='../nnfits/fit_dump.dat')
parameter (sampfile='../scans/samples.dat')
parameter (perfile='../logs/performance.log')
parameter (nnrecfile='../nnfits/record')
parameter (nnfdir='../nnfits/',nnsdir='../scans/')
parameter (nnldir='../logs/')
parameter (nntag='',prim_tag=' Time-stamp: " "')
parameter (lrfmt='(ES20.12)',lifmt='(I12)')
parameter (iout=6,perfunit=700,nnunit=800,fitunit=8000)
!**********************************************************
!**** Debugging Parameters
!*** sline: separation line
!*** asline: alternative sep. line
!*** hline: simple horizontal line
!*** newline: a single blank line
!*** mform: standard form for matrix output
!*** miform: standard form for integer matrix output
!*** smform: shortened form for matrix output
!*** stdfmt: standard format for strings
parameter (sline='(75("*"))',asline='(75("#"))')
parameter (hline='(75("-"))')
parameter (newline='()')
parameter (mform='(5ES12.4)',smform='(5ES10.2)')
parameter (miform='(5I12)')
parameter (stdfmt='(A)')
!**********************************************************
!**** Continuation Parameters
!*** record_*: Various possible values for the common block variable
!*** record_state. See the parser for more.
parameter (record_read=0,record_write=1,record_overwrite=-1)
parameter (record_update=-2)
!**********************************************************
!**** Error Codes
!*** Codes should be powers of 2. Binary representation of return value
!*** should correspond to all exceptions invoked. ec_error should never
!*** be invoked with any other.
!***
!*** ec_error: generic error (catch-all, avoid!)
!*** ec_read: parsing error during les()
!*** ec_dim: dimensioning error
!*** ec_log: logic error
!***
!**** Inferred error codes
!*** ec_dimrd: ec_dim+ec_read
parameter (ec_error=1,ec_read=2,ec_dim=4,ec_log=8)
parameter (ec_dimrd=ec_dim+ec_read)

BIN
src/exe Executable file

Binary file not shown.

153
src/ff_neunet.f Normal file
View File

@ -0,0 +1,153 @@
!--------------------------------------------------------------------------------------
subroutine propagate(W,B,L,deriv,typop,laystr,nlay)
implicit none
! Propagates full FF-NN.
! nlay: number of given layers
! nprop: number of single-layer propagations
! neu_io: number of neurons in giv./prev. layer
! neu_oi: number of neurons in prev./giv. layer
! poslay: starting position of layer in L- and B-vector
! poswei: starting position of Weight-Matrix in W-vector
!
! W: Weight Matrix Vector
! B: Bias Vector
! L: Layer Vector
! deriv: Activation function derivatives
! typop: Type Population Matrix
! laystr: Layer Structure Matrix
!
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for Weight Matrix from layer N to N+1
!
include 'nnparams.incl'
include 'nndbg.incl'
integer nlay,laystr(3,maxlay),typop(maxtypes,maxlay)
double precision W(maxwei),B(neucap),L(neucap),deriv(neucap)
integer poslay,poswei,nprop,neu_io,neu_oi
integer k
nprop=nlay-1
neu_io=laystr(1,1) !number of input neurons
poslay=laystr(2,1)
poswei=laystr(3,1)
do k=2,2*(nprop/2),2
neu_oi=laystr(1,k) !number of output neurons
call proplay(neu_io,neu_oi,W(poswei),B(poslay),L(poslay),
> deriv(poslay),typop(1,k))
poslay=laystr(2,k)
poswei=laystr(3,k)
neu_io=laystr(1,k+1) !new number of output neurons
! former output neurons are now input, _io and _oi switch places!
! (done for efficiency)
call proplay(neu_oi,neu_io,W(poswei),B(poslay),L(poslay),
> deriv(poslay),typop(1,k+1))
poslay=laystr(2,k+1)
poswei=laystr(3,k+1)
enddo
do k=1,mod(nprop,2) !for odd nprop one iteration is left
neu_oi=laystr(1,nlay)
call proplay(neu_io,neu_oi,W(poswei),B(poslay),L(poslay),
> deriv(poslay),typop(1,nlay))
enddo
end
!--------------------------------------------------------------------------------------
subroutine proplay(neu_in,neu_out,W,B,L,deriv,typop)
implicit none
! Evaluates given layer in FF-NN.
!
! neu_in: number of neurons in previous Layer
! neu_out: number of neurons in given Layer
!
! W: Weight Matrix Vector
! B: Bias Vector (beginning at prev. layer)
! L: Layer Vector (beginning at prev. layer)
! deriv: Activation function derivatives
! typop: Type Population Matrix (beginning at curr. layer)
include 'nnparams.incl'
include 'nndbg.incl'
integer neu_in,neu_out,typop(maxtypes)
double precision L(neu_in+neu_out),deriv(neu_in+neu_out)
double precision W(neu_in,neu_out),B(neu_in+neu_out)
integer neu_tot,pos_out
integer j,k
neu_tot=neu_in+neu_out !total number of neurons in both layers
pos_out=neu_in+1 !pos. of current layer's first element
do j=pos_out,neu_tot
L(j)=B(j) !add bias
do k=1,neu_in
L(j)=L(j)+W(k,j-neu_in)*L(k) !matrix x vector
enddo
enddo
! apply nonlin. functions to vector elements
call neurons(neu_out,L(pos_out),deriv(pos_out),typop)
end
!--------------------------------------------------------------------------------------
subroutine neurons(neu_out,L,deriv,typop)
implicit none
! Applies non-linear activation functions to given layer.
! type-unspecified neurons have the activation function f(x)=x.
!
! ni: Number of neurons of type i in given layer.
!
! L: Layer Vector containing accumulated neuronal input
! deriv: Activation function derivatives
! typop: Type Population Matrix
include 'nnparams.incl'
include 'nndbg.incl'
integer neu_out
double precision L(neu_out),deriv(neu_out)
integer typop(maxtypes)
integer n1,n2!,n3
integer j
n1=typop(1)
n2=typop(2)
! n3=typop(3)
call deriv1(L(1),deriv(1),n1)
call neuron1(L(1),n1)
! type 2 is as of now type 0 synonym
do j=n1+1,neu_out
deriv(j)=1.0D0
enddo
! terrible idea to do deriv(n1+1), it can (and will) overstep boundaries by 1
! call deriv2(deriv(n1+1),n2) !deriv2 is L-independent
! call neuron2(L(n1+1),n2)
! call deriv3(L(n1+n2+1),deriv(n1+n2+1),n3)
! call neuron3(L(n1+n2+1),n3)
end

226648
src/fit-NN_2018.in Normal file

File diff suppressed because it is too large Load Diff

268
src/geNNetic.f Normal file
View File

@ -0,0 +1,268 @@
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
! c
! PROGRAM GENETIC c
! c
! A program for non-linear fitting in multiple dimensions based on a c
! Marquardt-Levenberg non-linear least-squares fit and parameter c
! selection by a genetic algorithm c
! c
! Written by Wolfgang Eisfeld, Dec. 2002 c
! c
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
!
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
! c
! Version 1.0 c
! c
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
!*****************************************************************************
!** ***
!** nstat: number of states ***
!** maxpout: maximum number of output values ***
! ***
!** pat_in: ***
!** pat_out: ***
! ***
!** wterr: Vector containing the individual weights of data points ***
!** par: Matrix containing the parameter vectors ***
!** npar: actual number of parameters ***
!** num: actual number of data points y ***
!** act: vector that selects which parameters are active ***
!** seed: integer to select random seed ***
!** nset: number of parameter sets ***
!** sets: number of data sets for plotting ***
!** ndata: contains the number of data points for each block for plot ***
!** par_spread: factor by which each parameter spreads around its centre ***
!** ***
!** Special UNIT values ***
!** 8xxx and above: automatically generated. DO NOT ASSIGN MANUALLY. ***
!*****************************************************************************
!** Structural ANN constants:
!**
!** laystr: layer structure matrix
!** laystr(1,N): number of neurons in layer N
!** laystr(2,N): starting pos. for layer N
!** laystr(3,N): starting pos. for weight matrix from layer N to N+1
!**
!** weistr: weight structure matrix
!** weistr(1,N,1): starting pos. of weight matrix N in memory (layer N to N+1)
! identical to laystr(3,N)
!** weistr(2,N,1): end pos. of weight matrix N in memory
!** weistr(1,N,2): starting pos. of bias vector of layer N in memory
!** weistr(2,N,2): end pos. of bias vector of layer N in memory
!**
!** typop: type population matrix
!**
!** nlay: number of given layers
!*****************************************************************************
program genetic
use axel, only: renorm_input,unnorm_input
implicit none
include 'params.incl' !this includes the size definitions,
!number of states and modes
include 'common.incl'
include 'nnparams.incl' !this includes ANN-parameters
include 'nncommon.incl' !this includes ANN struture variables
include 'nndbg.incl' !this includes debug-mode specifics
!.....Genetic-specific variables
double precision, dimension(:,:), allocatable :: par
double precision, dimension(:), allocatable :: par_spread
double precision, dimension(:), allocatable :: rms,ref_rms
double precision, dimension(:,:), allocatable :: wterr
integer, dimension(:), allocatable :: act
integer seed, nset
logical freeze
logical lrnd
!.....ANN-specific variables
double precision, dimension(:,:), allocatable :: pat_in,pat_out
integer, dimension(:,:), allocatable :: laystr,typop
integer, dimension(:,:,:), allocatable :: weistr
integer nlay
!.....validation set for convergence testing
double precision, dimension(:,:), allocatable :: ref_in,ref_out
double precision rmsopt,mingrad,minwbstep
integer npat,nref
logical dry_run
integer init_rtype
integer tenptile
integer ntot
integer j
include 'keylist.incl' !this defines all special input keys
include 'errcat.incl' !this defines generic parser error messages
!.....(manual) allocation of all large arrays (prevents stack overflow)
allocate(par(wbcap,maxset))
allocate(par_spread(wbcap),rms(maxset), ref_rms(maxset))
allocate(wterr(maxpout,maxpats))
allocate(act(wbcap))
allocate(pat_in(maxnin,maxpats),pat_out(maxpout,maxpats))
allocate(laystr(3,maxlay),typop(maxtypes,maxlay))
allocate(weistr(2,maxlay,2))
allocate(ref_in(maxnin,maxpats),ref_out(maxpout,maxpats))
freeze=.false.
call nninit_mod()
if (dbg) write(6,'(A)') 'Reading input...'
!.. read input file and initialize data structures:
call read_input(wterr,par,act,seed,nset,
> par_spread,lrnd,dry_run,npat,nref,
> pat_in,pat_out,ref_in,ref_out,
> typop,laystr,weistr,nlay,
> rmsopt,mingrad,minwbstep,freeze)
if (dbg) write(6,'(A)') 'Input file read: OK'
!.. transform input
ntot=npat+nref
call trans_in(pat_in,ntot)
! NOTE: create API trans_out
!.. copy reference part
do j=1,nref
ref_in(:,j)=pat_in(:,npat+j)
enddo
!.. generate normalization factors for network inputs
if (norm_inp) then
! If scales and shifts are given, preserve them, if not, generate
! new.
call renorm_input(pat_in,npat,pres_inp,
> par,laystr,weistr)
endif
if (freeze) then
write(6,'(A)') 'Parameters frozen. Skipping fit.'
endif
if (use_record.and.((record_state.eq.record_read)
> .or.(record_state.eq.record_update))) then
! instead of random parameter sets, use the record.
call read_record(par,weistr,nlay,nset)
else if (lrnd) then
! create initial nset random parameter sets:
write(6,'(A)') 'Generating initial parameter sets..'
if (freeze) then
init_rtype=3
else if (any(act(1:npar).eq.0)) then
write(6,'(A)') 'Inactive Parameters found, '
> // 'skipping parameter normalization.'
init_rtype=0
write(6,'(A)') 'ERROR: Individual freezing of parameters '
> // 'not implemented.'
stop 1
else
init_rtype=3
endif
do j=1,nset
call mkpars(par(1,j),par_spread,laystr,typop,weistr,
> nlay,init_rtype)
enddo
if (dbg) write(6,*) 'done.'
endif
if (dry_run) then
! DRYRUN:
write(6,'(A)') 'Running model...'
call NNerr(par,pat_in,pat_out,ref_in,ref_out,
> wterr,typop,laystr,weistr,nlay,
> rms(1),ref_rms(1),npat,nref)
write(6,'(A)') 'Done. Exiting..'
else if (.not.freeze) then
!.. train ANNs and move the best to the top.
call traiNNsets(nset,npat,nref,par,act,rms,ref_rms,
> pat_in,pat_out,ref_in,ref_out,
> wterr,
> typop,laystr,weistr,nlay,
> rmsopt,mingrad,minwbstep)
write(6,'(A)') 'Writing best parameters to ''' //
> trim(nnparfile) // ''' ...'
call punch_net(0,nnparfile,par,
> typop,laystr,weistr,nlay,.false.,.false.)
if (nset.gt.10) then
! evaluate 10th percentile position
tenptile=ceiling(0.1D0*dble(nset))
write(6,'(A)') 'Writing 10th percentile parameters to '''
> // trim(nnp10file) // ''' ...'
call punch_net(0,nnp10file,par(1,tenptile),
> typop,laystr,weistr,nlay,
> .false.,.false.)
endif
! generate plotfiles for the best result
call punch_fitscans(par,pat_in,pat_out,wterr,
> typop,laystr,weistr,
> nlay,walk_scan)
else
! RANDOM: and FREEZE: or
! FREEZE: only
if (dbg) then
write(6,asline)
write(6,'(A)') 'NEUPOP:'
write(6,miform) laystr(1,1:nlay)
write(6,'(A)') 'INSHIFT:'
write(6,mform) shift_in(1:laystr(1,1))
write(6,'(A)') 'INSCALE:'
write(6,mform) fact_in(1:laystr(1,1))
write(6,'(A)') 'FINAL W:'
write(6,mform) par(weistr(1,1,1):weistr(2,nlay-1,1),1)
write(6,'(A)') 'FINAL B:'
write(6,mform) par(weistr(1,2,2):weistr(2,nlay,2),1)
write(6,asline)
endif
call NNerr(par,pat_in,pat_out,ref_in,ref_out,
> wterr,typop,laystr,weistr,nlay,
> rms(1),ref_rms(1),npat,nref)
call NNstat(1,npat,nref,par,rms,ref_rms,
> pat_in,pat_out,ref_in,ref_out,
> typop,laystr,weistr,nlay,nntag)
call punch_fitscans(par,pat_in,pat_out,wterr,
> typop,laystr,weistr,
> nlay,walk_scan)
call punch_fitpoints(par,pat_in,pat_out,
> typop,laystr,weistr,nlay,npat,nndmpfile)
call punch_net(0,nnparfile,par,
> typop,laystr,weistr,nlay,.false.,.false.)
call punch_netdistrib(nnfdir,par,pat_in,typop,laystr,weistr,
> nlay,npat,nntag)
endif
write(6,'(A)') 'Writing successful.'
deallocate(par)
deallocate(par_spread,rms, ref_rms)
deallocate(wterr)
deallocate(act)
deallocate(pat_in,pat_out)
deallocate(laystr,typop)
deallocate(weistr)
deallocate(ref_in,ref_out)
end

974
src/iNNterface.f Normal file
View File

@ -0,0 +1,974 @@
******************************************************************************
*** iNNterface
*** connecting ANN with genetic
*** by David Williams
*** & Jerome Collet
***
*** name(s) [synonyms or equivalents]
*** wertnum [npat]
*** q,x1 [pat_in]
*** y [pat_out]
*** par [W,B]
*** num [npat]
***
***
***
******************************************************************************
subroutine NNmin(npat,nref,par,act,rms,ref_rms,pat_in,pat_out,
> ref_in,ref_out,wterr,
> typop,laystr,weistr,nlay,rmsopt,
> mingrad,minwbstep,fit_id,skip)
implicit none
! Non-linear least-squares fitting using feed forward NN and
! Marquardt-Levenberg learning.
!
! fit_id: unique identifying integer for a given fit
!
! parnum: number of parameters
! par: Parameter vector containing all weights and biases
! (weights first, biases second). Weights are in the
! natural order of the memory:
! W1(1,1) W1(2,1) ... W1(1,2) ... W2(1,1) ...
! ... B1(1) B1(2) ... B2(1) ...
! these may be followed by further parameters
! *not* used by ANN.
! act: vector, indicating the active parameters
! rms: (weighted) root mean square
! ref_rms: rms of reference data
! skip: failure state on exit
!
!
! name [ANN-synonym]
!******************************************************************
! npat: number of given pattern pairs
! nref: number of reference patterns
! rms: (weighted) root mean square error
! rmsopt: error threshold
! mingrad: error gradient threshold
! minwbstep: threshold for wbnorm
!
! pat_in: input patterns
! pat_out: desired output patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
! ref_*: in analogy to pat_in/out for reference data
! (convergence tests)
!
! wterr: weight factors for each element of the error vector e
!
! wbsteps: Steps for weights and biases, same order as a single jacobian-row.
! mqpar: initial parameter (lambda) for Marquard-Levenberg
! mqfact: factor by which lambda is multiplied/divided after each iteration
!
! par [W]: weight matrix vector
! par [B]: bias vector
!
! common-block /ann/
!******************************************************************
! nlay: number of given layers
! typop: type population matrix
! laystr: layer structure matrix
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for weight matrix from layer N to N+1
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision par(wbcap)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
double precision ref_in(maxnin,*),ref_out(maxnout,*)
double precision wterr(maxpout,maxpats)
double precision rms,ref_rms,rmsopt
double precision mingrad,minwbstep
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer npat,nref
integer act(wbcap)
integer fit_id
logical skip
double precision mqpar,mqfact
integer pos_out,inact_num
integer lay_end,wei_end,bi_pos,bi_end
integer funit
character*32 fname
integer k
pos_out=laystr(2,nlay)-1 !increment leading to output layer pos.
! total number of neurons / W-matrix elements
lay_end=pos_out+len_out
! total number of neurons / W-matrix elements in vector par
wei_end=weistr(2,nlay-1,1)
! starting position and end position of Bias vector in par
bi_pos=weistr(1,1,2)
bi_end=weistr(2,nlay,2)
if (dbg) write(6,*) 'NNmin entered'
if (dbg) write(6,*) 'NPAT:', npat
rms=infty
! initialize MQL-factor and parameter
mqpar=lambda_initial
mqfact=mqfact_default
! fits currently pattern pairs (x1,y)
if (all(act(1:bi_end).eq.0)) then
write(6,'(A)') 'Parameters frozen, skip to output'
return
else if (any(act(1:bi_end).eq.0)) then
write(6,'(A)') 'Some parameters set inactive'
inact_num=0
do k=1,bi_end
if (act(k).eq.0) then
inact_num=inact_num+1
endif
enddo
write(6,'(A,I5.5)') "Total inactive: ",inact_num
endif
if (ldbg) then
write(6,sline)
write(6,'(A)') 'W:'
write(6,mform) par(1:wei_end)
write(6,sline)
write(6,'(A)') 'B:'
write(6,mform) par(bi_pos:bi_end)
write(6,sline)
write(6,'(A)') 'TYPOP:'
do k=1,nlay
write(6,'(2I6,:)') typop(1:2,k)
enddo
write(6,sline)
write(6,*)
write(6,'(A)') 'X,Y'
do k=1,npat
write(unit=6,advance='no',fmt='(A2,1000(ES14.6,:))') 'X:',
> pat_in(1:len_in,k)
write(6,'(A3,1000(ES14.6,:))') ' Y:', pat_out(1:inp_out,k)
enddo
write(6,asline)
write(6,'(A)') 'Entering nnmqo..'
endif
! W , B
call nnmarq(rms,ref_rms,mqpar,mqfact,par,par(bi_pos),act,
> wterr,pat_in,pat_out,ref_in,ref_out,
> typop,laystr,weistr,nlay,
> rmsopt,npat,nref,mingrad,minwbstep,fit_id,skip)
if (rats) then
funit=fitunit+fit_id
fname=trim(nnfdir) // '.fit_'
write(fname,'(A,I5.5)') trim(fname), fit_id
call punch_net(funit,fname,par,
> typop,laystr,weistr,nlay,.false.,.true.)
endif
end subroutine
!--------------------------------------------------------------------------------------
subroutine neunet(x,y,par,typop,laystr,weistr,nlay)
use axel, only: init_input
implicit none
! Wrapper for ANN's propagate
!
! y: neural network output value(s)
! x: input coordinate set
! par: Parameter vector containing all weights and biases
! (weights first, biases second). Weights are in the
! natural order of the memory:
! W1(1,1) W1(2,1) ... W1(1,2) ... W2(1,1) ...
!
! nlay: number of given layers (in common block /ann/)
!
! L: layer vector
! deriv: activation function derivatives (currently discarded)
! typop: type population matrix (in common black /ann/)
! laystr: layer structure matrix (in common block /ann/)
!
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for Weight Matrix from layer N to N+1
include 'nnparams.incl'
include 'nncommon.incl'
double precision y(maxnout),x(maxnin),par(wbcap)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
double precision L(neucap)
double precision deriv(neucap)
integer wei_end,lay_end
integer pos_out
integer bi_pos,bi_end
pos_out=laystr(2,nlay)-1 !increment leading to output layer pos.
! total number of neurons / W-matrix elements
lay_end=pos_out+len_out
wei_end=weistr(2,nlay-1,1)
! starting position and end position of Bias vector in par
bi_pos=weistr(1,1,2)
bi_end=weistr(2,nlay,2)
! write coordinate values on input neurons
call init_input(L,x,shift_in,fact_in,len_in)
call propagate(par(1),par(bi_pos),L,deriv,typop,laystr,nlay)
! write output on y
y(1:len_out)=L(pos_out+1:pos_out+len_out)
end subroutine
!--------------------------------------------------------------------------------------
subroutine neunet_full(x,L,deriv,par,typop,laystr,weistr,nlay)
use axel, only: init_input
implicit none
! Wrapper for ANN's propagate, containing all outputs
!
! x: input coordinate set
! par: Parameter vector containing all weights and biases
! (weights first, biases second). Weights are in the
! natural order of the memory:
! W1(1,1) W1(2,1) ... W1(1,2) ... W2(1,1) ...
!
! nlay: number of given layers (in common block /ann/)
!
! L: layer vector
! deriv: activation function derivatives (currently discarded)
! typop: type population matrix (in common black /ann/)
! laystr: layer structure matrix (in common block /ann/)
!
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for Weight Matrix from layer N to N+1
include 'nnparams.incl'
include 'nncommon.incl'
double precision x(maxnin),par(wbcap)
double precision L(neucap)
double precision deriv(neucap)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer wei_end,lay_end
integer pos_out
integer bi_pos,bi_end
pos_out=laystr(2,nlay)-1 !increment leading to output layer pos.
! total number of neurons / W-matrix elements
lay_end=pos_out+len_out
wei_end=weistr(2,nlay-1,1)
! starting position and end position of Bias vector in par
bi_pos=weistr(1,1,2)
bi_end=weistr(2,nlay,2)
! write coordinate values on input neurons
call init_input(L,x,shift_in,fact_in,len_in)
call propagate(par(1),par(bi_pos),L,deriv,typop,laystr,nlay)
end subroutine
!--------------------------------------------------------------------------------------
subroutine traiNNsets(nset,npat,nref,par,act,rms,ref_rms,
> pat_in,pat_out,ref_in,ref_out,
> wterr,
> typop,laystr,weistr,nlay,
> rmsopt,mingrad,minwbstep)
implicit none
! Uses NNmin to train all nset initialized neural networks using NNmin.
! The first parameterset will be overwritten with the ANN yielding the
! smallest rms. Remaining sets will be sorted in ascending order.
!
! par: Parameter vector containing all weights and biases
! (weights first, biases second). Weights are in the
! natural order of the memory:
! W1(1,1) W1(2,1) ... W1(1,2) ... W2(1,1) ...
! ... B1(1) B1(2) ... B2(1) ...
! these may be followed by further parameters
! *not* used by ANN.
! act: vector, indicating the active parameters
! rms: (weighted) root mean square for each parameter set.
! rms(1): best rms achieved, overwrites set #1.
! rms(n): final rms of set #n.
! ref_rms: rms of reference data
!
!
! name [ANN-synonym]
!******************************************************************
! nset: number of ANNs to be optimized.
! npat: number of given pattern pairs
! nref: number of reference patterns
! rms: (weighted) root mean square error
! rmsopt: error threshold
! mingrad: error gradient threshold
! minwbstep: threshold for wbnorm
!
! pat_in: input patterns
! pat_out: desired output patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
! ref_*: in analogy to pat_in/out for reference data
! (convergence tests)
!
! wterr: weight factors for each element of the error vector e
!
! wbsteps: Steps for weights and biases, same order as a single jacobian-row.
! mqpar: initial parameter (lambda) for Marquard-Levenberg
! mqfact: factor by which lambda is multiplied/divided after each iteration
!
! par [W]: weight matrix vector
! par [B]: bias vector
!
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nndbg.incl'
include 'nncommon.incl'
double precision par(wbcap,maxset),rms(maxset),ref_rms(maxset)
double precision wterr(maxpout,maxpats)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
double precision ref_in(maxnin,*),ref_out(maxnout,*)
double precision rmsopt,mingrad,minwbstep
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer act(wbcap)
integer nset,nref,npat
integer wei_end, bi_pos, bi_end
double precision loc_par(wbcap),loc_rms,loc_ref_rms
logical loc_skip
integer i,k
if (rats) then
! create logfile
open(unit=perfunit,file=trim(perfile),status='REPLACE')
write(perfunit,'(A)') '# UNIT: ' // trim(unit_string)
write(unit=perfunit,fmt='("#",A9,3A10,A17,A10)') 'RMS',
> 'RMS(REF)', 'WBNORM','GRADNORM', 'UPDATE/IT.',
> 'FIT#'
endif
! total number of neurons / W-matrix elements in vector par
wei_end=weistr(2,nlay-1,1)
! starting position and end position of Bias vector in par
bi_pos=weistr(1,1,2)
bi_end=weistr(2,nlay,2)
if (mprun) write(6,asline)
! initialize rms to impossible value
rms(1:nset)=-1.0d0
ref_rms(1:nset)=-1.0d0
if ((from_fit.gt.1).or.(to_fit.lt.nset)) then
write(6,'(A)') 'Detected continuation.'
write(6,'(A,ES10.2)') 'Setting all undefined RMS values to:',
> infty
do i=1,from_fit-1
rms(i)=infty
ref_rms(i)=infty
enddo
do i=to_fit+1,nset
rms(i)=infty
ref_rms(i)=infty
enddo
endif
!$omp parallel do default(shared) private(i,loc_par,loc_rms,
!$omp& loc_ref_rms,loc_skip)
!$omp& schedule(dynamic)
do i=from_fit, to_fit
if (.not.mprun) write(6,asline)
write(6,'(A,I4.4,A)')'Neural Network #',i,': Start!'
! make a local copy of current parameter set
do k=1,bi_end
loc_par(k)=par(k,i)
enddo
! initialize failure state
loc_skip=.false.
! train ANN with ith parameter set
call NNmin(npat,nref,loc_par,act,loc_rms,loc_ref_rms,pat_in,
> pat_out,ref_in,ref_out,
> wterr,typop,laystr,weistr,nlay,
> rmsopt,mingrad,minwbstep,i,loc_skip)
if (.not.loc_skip) then
write(6,'("Final rms:",ES21.14,X,A,"(#",I4.4,")")')
> loc_rms*unit_con,unit_string,i
! return optimized values to global data structures.
par(:,i)=loc_par
rms(i)=loc_rms
ref_rms(i)=loc_ref_rms
else
rms=infty
ref_rms=infty
endif
enddo
!$omp end parallel do
if (rats) then
close(unit=perfunit)
endif
if (use_record) then
write(6,sline)
if (record_state.eq.record_write) then
call punch_record(par,weistr,nlay,nset,.true.)
else if (record_state.eq.record_overwrite) then
call punch_record(par,weistr,nlay,nset,.false.)
else if (record_state.eq.record_update) then
call punch_record(par,weistr,nlay,nset,.false.)
endif
endif
write(6,newline)
write(6,asline)
write(6,'(A)') 'Training complete.'
! sort parameter sets
call NNrank(nset,nref,par,rms,ref_rms)
call NNstat(nset,npat,nref,par,rms,ref_rms,
> pat_in,pat_out,ref_in,ref_out,
> typop,laystr,weistr,nlay,nntag)
write(6,'(/,A)') 'Done.'
end subroutine
!--------------------------------------------------------------------------------------
subroutine NNrank(nset,nref,par,rms,ref_rms)
implicit none
! Sorts the parameter sets from best to worst, as well as the
! corresponding rms and ref_rms values. Prints an excerpt from the
! resulting ranking.
!
! nset: number of optimized ANNs
! nref: number of reference patterns
! rms: (weighted) root mean square errors
! ref_rms: (weighted) root mean square errors of validation set
! tenptile: position of the 10th percentile
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nndbg.incl'
include 'nncommon.incl'
double precision par(wbcap,nset),rms(nset),ref_rms(nset)
integer nset,nref
double precision, dimension(:,:), allocatable :: par_copy
double precision rms_copy(nset),ref_copy(nset)
integer rms_pos(nset)
integer tenptile,rank_end
double precision rms_avrg,ref_avrg
integer k
allocate(par_copy(wbcap,nset))
tenptile=ceiling(0.1D0*dble(nset))
rms_copy=0.0d0
! create copy of rms-vector to be sorted
do k=1,nset
par_copy(:,k)=par(:,k)
rms_copy(k)=rms(k)
ref_copy(k)=ref_rms(k)
rms_pos(k)=k
enddo
! rank individual trained NNs by rms error.
write(6,'(A)') 'Searching for best fit..'
call dqsort2(nset,rms_copy,rms_pos)
write(6,'(A,ES21.4,X,A)') 'Best rms found:', rms_copy(1)*unit_con,
> trim(unit_string)
if (nref.gt.0) then
write(6,'(A,ES21.4,X,A)') 'Reference rms: ',
> ref_rms(rms_pos(1))*unit_con,
> trim(unit_string)
! produce easy-to-grep rms summary
write(6,'(A,ES12.4,X,A,X,"(",ES14.4,X,A,")")') 'RESULT:',
> rms_copy(1)*unit_con, trim(unit_string),
> ref_rms(rms_pos(1))*unit_con, trim(unit_string)
else
write(6,'(A,ES12.4,X,A)') 'RESULT:',
> rms_copy(1)*unit_con, trim(unit_string)
endif
write(6,sline)
if (dbg) then
write(6,'(/,A)') 'Ranking errors:'
rank_end=nset
else
write(6,'(/,A,/)') 'Ranking errors (top 10%):'
rank_end=tenptile
endif
write(6,'(A15,2A12)') 'FIT#','RMS ['//trim(unit_string)//']',
> 'REF ['//trim(unit_string)//']'
rms_avrg=0.0D0
ref_avrg=0.0D0
do k=1,rank_end
write(6,'(I15,2ES12.4)') rms_pos(k),
> rms_copy(k)*unit_con, ref_rms(rms_pos(k))*unit_con
rms_avrg=rms_avrg + rms_copy(k)
ref_avrg=ref_avrg + ref_rms(rms_pos(k))
enddo
rms_avrg=rms_avrg/dble(rank_end)
ref_avrg=ref_avrg/dble(rank_end)
if (.not.dbg) then
write(6,hline)
write(6,'(A15,2ES12.4)') 'AVERAGE ['//trim(unit_string)//']:',
> rms_avrg*unit_con,ref_avrg*unit_con
endif
write(6,sline)
do k=1,nset
par(:,k)=par_copy(:,rms_pos(k))
rms(k)=rms_copy(k)
ref_rms(k)=ref_copy(rms_pos(k))
enddo
deallocate(par_copy)
end subroutine
!--------------------------------------------------------------------------------------
subroutine NNstat(nset,npat,nref,par,rms,ref_rms,
> pat_in,pat_out,ref_in,ref_out,
> typop,laystr,weistr,nlay,ftag)
implicit none
! Writes files presenting the distributions of error for the best
! fits, assuming par has already been sorted.
!
! nset: number of optimized ANNs
! npat: number of given pattern pairs
! npar: number of parameters
! nref: number of reference patterns
! rms: (weighted) root mean square errors
! ref_rms: (weighted) root mean square errors of validation set
! tenptile: position of the 10th percentile
! ftag: infix for generated filenames
!
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nndbg.incl'
include 'nncommon.incl'
double precision par(wbcap,maxset),rms(maxset),ref_rms(maxset)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
double precision ref_in(maxnin,*),ref_out(maxnout,*)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
character*8 ftag
integer nset,npat,nref
double precision, dimension(:), allocatable :: err_vec
double precision, dimension(:), allocatable :: ref_vec
double precision med, med_ref
integer med_pos(2), med_ref_pos(2)
integer tenptile,rank_end
character*64 fname
character*8 unit
integer k
allocate(err_vec(maxpats))
allocate(ref_vec(maxpats))
tenptile=ceiling(0.1D0*dble(nset))
rank_end=min(tenptile,1000)
unit = '[' // trim(unit_string) // ']'
write(6,'(A)') 'Generating error statistic..'
write(6,sline)
write(6,'(A15,6A12)') 'NETWORK#',
> 'RMS ' // trim(unit), 'MED. ' // trim(unit),
> 'MAX ' // trim(unit),
> 'REF ' // trim(unit), 'MED. ' // trim(unit),
> 'MAX ' // trim(unit)
if (1.eq.modulo(npat,2)) then
med_pos = (npat+1)/2
else
med_pos(1) = npat/2
med_pos(2) = med_pos(1) + 1
endif
if (nref.le.1) then
med_ref_pos = 1
else if (1.eq.modulo(nref,2)) then
med_ref_pos = (nref+1)/2
else
med_ref_pos(1) = nref/2
med_ref_pos(2) = med_ref_pos(1) + 1
endif
do k=1,rank_end
write(fname,'(A32)') ''
write(fname,'(I4.4)') k
fname = trim(nnfdir) // 'errors_' // trim(ftag)
> // trim(fname) // '.out'
call punch_fitstat(fname,par(1,k),pat_in,pat_out,err_vec,npat,
> typop,laystr,weistr,nlay,
> .false.)
! get median
med=0.5d0*(err_vec(med_pos(1))+err_vec(med_pos(2)))
if (nref.gt.0) then
open(nnunit,file=trim(fname),status='old',position='append')
write(nnunit,'(A)') ''
write(nnunit,asline)
write(nnunit,'(A)') '# REF:'
close(nnunit)
call punch_fitstat(fname,par(1,k),ref_in,ref_out,
> ref_vec,nref,
> typop,laystr,weistr,nlay,.true.)
else
ref_vec(1)=0.0d0
endif
! get median
if (nref.eq.0) then
med_ref=0.0d0
else
med_ref=0.5d0*(ref_vec(med_ref_pos(1))
> + ref_vec(med_ref_pos(2)))
endif
write(6,'(I15,6ES12.4)') k,
> rms(k)*unit_con, med*unit_con, err_vec(1)*unit_con,
> ref_rms(k)*unit_con, med_ref*unit_con, ref_vec(1)*unit_con
enddo
deallocate(err_vec)
deallocate(ref_vec)
end subroutine
!--------------------------------------------------------------------------------------
subroutine NNerr(par,pat_in,pat_out,ref_in,ref_out,
> wterr,
> typop,laystr,weistr,nlay,rms,ref_rms,npat,nref)
implicit none
! Evaluates error of given ANN using nnmqo's mkerr subroutine,
! and generates an output file.
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision par(wbcap),wterr(maxpout,maxpats)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
double precision ref_in(maxnin,*),ref_out(maxpout,*)
double precision rms,ref_rms
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer npat,nref
integer wei_end,bi_pos,bi_end
! total number of neurons / W-matrix elements in vector par
wei_end=weistr(2,nlay-1,1)
! starting position and end position of Bias vector in par
bi_pos=weistr(1,1,2)
bi_end=weistr(2,nlay,2)
! W, B
call mkerr(par(1),par(bi_pos),wterr,rms,
> pat_in,pat_out,
> typop,laystr,nlay,npat)
write(6,newline)
write(6,asline)
write(6,400) rms*unit_con, trim(unit_string)
if (nref.gt.0) then
call mkerr(par(1),par(bi_pos),wterr(1,npat+1),ref_rms,
> ref_in,ref_out,
> typop,laystr,nlay,nref)
write(6,401) ref_rms*unit_con, trim(unit_string)
else
write(6,403) rms*unit_con, trim(unit_string)
endif
! produce easy-to-grep rms summary
write(6,402) rms*unit_con, trim(unit_string),
> ref_rms*unit_con, trim(unit_string)
write(6,sline)
400 format('RMS of given data and parameter set:',ES12.4,X,A)
401 format('VALIDATION-RMS:',ES12.4,X,A)
402 format('RESULT:',ES12.4,X,A,X,'(',ES12.4,X,A,')')
403 format('RESULT:',ES12.4,X,A)
if (showcut) then
call NNcuterr(par,pat_in,pat_out,npat,
> typop,laystr,weistr,
> nlay)
endif
end subroutine
!--------------------------------------------------------------------------------------
subroutine NNerrvec(par,pat_err,pat_in,pat_out,
> typop,laystr,weistr,nlay)
implicit none
! Evaluates error vector of given ANN for a *single* pattern using
! nnmqo's mkerrvec subroutine.
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision par(wbcap)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
double precision pat_err(maxpout)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer wei_end,bi_pos,bi_end
! total number of neurons / W-matrix elements in vector par
wei_end=weistr(2,nlay-1,1)
! starting position and end position of Bias vector in par
bi_pos=weistr(1,1,2)
bi_end=weistr(2,nlay,2)
! W, B
call mkerrvec(par(1),par(bi_pos),pat_err,pat_in,pat_out,
> typop,laystr,nlay)
end subroutine
!--------------------------------------------------------------------------------------
subroutine NNkeygen(nnkeylist,nnkeynum,nlay,force)
implicit none
! Automatically generate a key list for parsing ANN parameters.
! Force, if true, will make the W(*,*) and B(*) keys mandatory.
!
!.....Keys generated are:
! W(i,i+1): B(i):
! where i=01,02,...
include 'params.incl'
include 'nnparams.incl'
include 'nndbg.incl'
integer nlay
integer nnkeynum
character*(klen) nnkeylist(2,maxnnkeys)
logical force
integer j
nnkeylist=' '
! To utilize the standard keyread utilities, we need the key
! signalizing the EOF
nnkeylist(1,1)='DATA:'
nnkeylist(2,1)='E!'
nnkeynum=1
! Next, we generate all standard weight and bias keys
! Weights first
do j=1,nlay-1
nnkeynum=nnkeynum+1
! keys for weight matrix elements (layer j->j+1)
write(nnkeylist(1,nnkeynum)(1:10),
> '("W(",I2.2,",",I2.2,"):")') j,j+1
! expects: arbitrary number of reals
if (force) then
nnkeylist(2,nnkeynum)='D!N'
else
nnkeylist(2,nnkeynum)='DN'
endif
enddo
! Biases next
do j=1,nlay-1
nnkeynum=nnkeynum+1
! keys for bias vector (layer j+1)
write(nnkeylist(1,nnkeynum)(1:7),
> '("B(",I2.2,"):")') j+1
! expects: arbitrary number of reals
if (force) then
nnkeylist(2,nnkeynum)='D!N'
else
nnkeylist(2,nnkeynum)='DN'
endif
enddo
! Weight spreads
do j=1,nlay-1
nnkeynum=nnkeynum+1
write(nnkeylist(1,nnkeynum)(1:10),
> '("SW(",I2.2,",",I2.2,"):")') j,j+1
! expects: one positive real
nnkeylist(2,nnkeynum)='+D1'
enddo
! Bias spreads
do j=1,nlay-1
nnkeynum=nnkeynum+1
write(nnkeylist(1,nnkeynum)(1:7),
> '("SB(",I2.2,"):")') j+1
! expects: one positive real
nnkeylist(2,nnkeynum)='+D1'
enddo
end subroutine
!--------------------------------------------------------------------------------------
subroutine NNcuterr(par,pat_in,pat_out,npat,
> typop,laystr,weistr,
> nlay)
implicit none
! Subroutine providing rms error of all output pattern entries which
! lie below a fixed cutoff threshold provided by common block
! variable cutoff.
!
! pat_in: input patterns
! pat_out: desired output patterns
! npat: number of given pattern pairs
! inp_in: number of coordinates written into input.
! inp_out: number of values written to output
!
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
integer npat
double precision par(wbcap)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer fmtlen
parameter (fmtlen=16)
character*(fmtlen) intfmt,dblefmt
parameter (intfmt='(I8)',dblefmt='(ES14.2)')
double precision pat_err(maxpout),rms_vec(maxpout)
double precision cut_rms,cut_norm
integer err_count(maxpout)
integer n,j
rms_vec=0.0d0
cut_rms=0.0d0
cut_norm=0.0d0
err_count=0
write(6,'(A)') 'Calculating cutoff-rms..'
! accumulate errors sorted by corresponding output
do n=1,npat
call NNerrvec(par,pat_err,pat_in(1,n),pat_out(1,n),
> typop,laystr,weistr,nlay)
! count only errors actually contributing to cutoff-rms
do j=1,inp_out
if (pat_out(j,n).le.cutoff(j)) then
rms_vec(j)=rms_vec(j)+pat_err(j)**2
err_count(j)=err_count(j)+1
endif
enddo
enddo
! calculate rms-errors
do j=1,inp_out
if (err_count(j).le.0) then
write(6,'(A,I3.3)') 'WARNING: NO OUTPUT FOUND WITHIN'
> // ' CUTOFF FOR OUTPUT VALUE #',j
rms_vec(j)=-1.0d0
else
cut_rms=cut_rms+rms_vec(j)*cutwei(j)
cut_norm=cut_norm+cutwei(j)*dble(err_count(j))
rms_vec(j)=dsqrt(rms_vec(j)/dble(err_count(j)))*unit_con
endif
enddo
if (all(err_count(1:inp_out).le.0)) then
write(6,'(A)') 'WARNING: NO PATTERN WITHIN CUTOFF RANGE(S).'
else
cut_rms=dsqrt(cut_rms/cut_norm)*unit_con
endif
write(6,'(A)') 'Number of outputs within cutoff range:'
call printivec_full(err_count,intfmt,fmtlen,inp_out,5)
write(6,'(A)') 'Individual unweighted RMS-errors ['//
> trim(unit_string)//']:'
call printvec_full(rms_vec,dblefmt,fmtlen,inp_out,5)
write(6,'(A,ES14.2)') 'Total cutoff-RMS ['
> //trim(unit_string)//']:',cut_rms
write(6,newline)
write(6,'(A)') '((RMS of -1 means undefined value))'
write(6,sline)
end subroutine

BIN
src/invariants_mod.mod Normal file

Binary file not shown.

153
src/lib/choldc.f Normal file
View File

@ -0,0 +1,153 @@
*** Implementation of cholesky decomposition as described in
!?*** (Add Book Info!)
subroutine choldcsol(A,b,x,n,np,err_stat)
implicit none
! Minimalistic interface to solve a set of linear equations using
! Cholesky decomposition. Like choldc and cholsl it destroys
! Matrix A in the process.
!
! The linear equation is assumed to have the form
! A x = b
!
! n: logical dimension of A
! np: physical dim. of A
!
! A,p: input matrix and diagonal elements
! b: input vector
! x: solution vector
! err_stat: failure state of choldcsol.
! set to true if fatal error occurs.
!
! dstat: real-valued output status of choldc.
! 1.0D0 if successful.
! dstat < 0.0D0 is a failure state where dstat is
! the found negative squared diagonal element of L.
integer np,n
double precision A(np,np),b(n),x(n)
logical err_stat
double precision dstat
double precision p(n)
! Solve A = L L^T
call choldc(A,n,np,p,dstat)
if (dstat.lt.0.0D0) then
write(6,'(A)') 'ERROR (choldcsol): '
> // 'MATRIX NOT POSITIVE DEFINITE'
write(6,'("OFFENDING VALUE:",ES11.2)') dstat
err_stat=.true.
return
endif
! Solve A x = b
call cholsl(A,n,np,p,b,x)
end
!--------------------------------------------------------------------------------------
subroutine choldc(A,n,np,p,dstat)
implicit none
! Given a positive-definite symmetric matrix A(1:n,1:n) with
! physical dimension np this routine constructs its Cholesky
! decomposition A = L L^T. On input, only the upper triangle
! of A need be given; it is not modified. The Cholesky factor L
! is returned in the lower triangle of A, except for it's
! diagonal elements which are returned in p(1:n).
!
! Pivoting is not required due to the method's numerical stability.
!
! n: logical dimension of A
! np: physical dim. of A
! dstat: real-valued output status on exit
! 1.0D0 if successful.
! dstat < 0.0D0 is a failure state where dstat is
! the found negative squared diagonal element of L.
! (not yet implemented)
!
! A: positive-definite symmetric matrix
! A(j,i): elements to be overwritten with L(j,i) iff j<i
! p: diagonal elements L(i,i)
!
integer np,n
double precision A(np,np),p(n),dstat
double precision zero
double precision sum
integer i,j,k
parameter (zero=1.0D-10)
dstat=1.0D0
do i=1,n
! A is symmetric, only regard j>=i.
do j=i,n
sum=A(i,j)
do k=i-1,1,-1
sum=sum - A(i,k)*A(j,k)
enddo
if (i.eq.j) then
if (sum.le.zero) then
! if A including rounding is not
! positive definite, stop
dstat=sum
return
endif
p(i)=dsqrt(sum)
else
A(j,i)=sum/p(i)
endif
enddo
enddo
end
!--------------------------------------------------------------------------------------
subroutine cholsl(A,n,np,p,b,x)
implicit none
! Solves a set of n linear equations A x = b, where A is
! a positive-definite symmetric matrix with physical dimension np.
! A and p are input as the output of the routine choldc.
! Only the lower triangle of A is accessed. b(1:n) is input as
! the right-hand side vector. The solution vector is returned
! in x(1:n). A,n,np and p are not modified ans can be left in place
! for successive calls with different right-hand sides b.
! b is not modified unless you identify b and x in in the calling
! sequence, which is allowed.
!
! n: logical dimension of A
! np: physical dim. of A
!
! A,p: input matrix and diagonal elements
! b: input vector
! x: solution vector
integer n,np
double precision A(np,np),b(n),p(n),x(n)
integer i,k
double precision sum
! Solve L y = b, storing y in x.
do i=1,n
sum=b(i)
do k=i-1,1,-1
sum=sum - A(i,k)*x(k)
enddo
x(i)=sum/p(i)
enddo
! Solve L^T x = y.
do i=n,1,-1
sum=x(i)
do k=i+1,n
sum=sum - A(k,i)*x(k)
enddo
x(i)=sum/p(i)
enddo
end

102
src/lib/diag.f Normal file
View File

@ -0,0 +1,102 @@
subroutine ddiag(matrix,E,U,pdim,mdim)
implicit none
! Diagonalization wrapper: double precision matrix diagonalization.
!
! Physical dimension of array
integer, intent(in) :: pdim
! Order of the matrix.
integer, intent(in) :: mdim
! Matrix
double precision, intent(in) :: matrix(pdim,mdim)
! Eigenvalues & Eigenvectors
double precision, intent(out) :: E(mdim)
double precision, intent(out) :: U(pdim,mdim)
! lapack variables
integer,parameter :: lwork = 1000 ! ~300x300 matrices
double precision work(lwork)
double precision avrg
integer info
integer j
! Compute barycenter tr(M)/mdim
avrg=0
do j=1,mdim
avrg=avrg+matrix(j,j)
enddo
avrg=avrg/dble(mdim)
U=matrix
do j=1,mdim
U(j,j)=U(j,j)-avrg
enddo
call dsyev('V','U',mdim,U,pdim,E,work,lwork,info)
E=E+avrg
if (info.gt.0) then
write(6,100) info
else if (info.lt.0) then
write(6,101) -info
stop 1
endif
100 format("WARNING: DDIAG: Failed to converge ",I0,
> " diagonal elements")
101 format("ERROR: DDIAG: Invalid argument, argument #",I0)
end subroutine
!-------------------------------------------------------------------------------
subroutine deigen(matrix,E,mdim)
implicit none
! Diagonalization wrapper: double precision matrix diagonalization.
!
! Order of the matrix. Assumed to be physical dimension.
integer, intent(in) :: mdim
! Matrix
double precision, intent(in) :: matrix(mdim,mdim)
! Eigenvalues only
double precision, intent(out) :: E(mdim)
! lapack variables
integer,parameter :: lwork = 1000
double precision work(lwork)
double precision :: U(mdim,mdim)
double precision avrg
integer info
integer j
! Compute barycenter tr(M)/mdim
avrg=0
do j=1,mdim
avrg=avrg+matrix(j,j)
enddo
avrg=avrg/dble(mdim)
U=matrix
do j=1,mdim
U(j,j)=U(j,j)-avrg
enddo
call dsyev('N','U',mdim,U,mdim,E,work,lwork,info)
E=E+avrg
if (info.gt.0) then
write(6,100) info
else if (info.lt.0) then
write(6,101) -info
stop 1
endif
100 format("WARNING: DEIGEN: Failed to converge ",I0,
> " diagonal elements")
101 format("ERROR: DEIGEN: Invalid argument, argument #",I0)
end subroutine

530
src/lib/dmatrix.f Normal file
View File

@ -0,0 +1,530 @@
************************************************************************
*** dmatrix
*** generic double precision matrix operations
***
************************************************************************
subroutine permutemat(oldmat,newmat,perm_row,perm_col,nrow,ncol)
implicit none
! Allows to perform arbitrary permutations of row- and column
! entries of the matrix (corresponding to permutations of the
! underlying basis sets).
!
! Permutations are symbolized as integer vectors. They should
! contain each number from 1 to nrow/ncol in the desired new order,
! 1 meaning the originally first entry etc.
!
! (1,2,3,..) -Permutation-> (P(1),P(2),...)
!
! oldmat: matrix to be modified
! newmat: generated matrix
! nrow: dimension of row-vectors
! ncol: dimension of column vectors
! perm_*: permutation applied to row or column
!
integer nrow,ncol
integer perm_row(nrow),perm_col(ncol)
double precision oldmat(nrow,ncol),newmat(nrow,ncol)
integer j,k
! check validity of permutations (pidgeonhole principle)
do j=1,nrow
if (.not.any(perm_row.eq.j)) then
write(6,'(A)') 'ERROR: INVALID PERMUTATION'
> // ' VECTOR (permutemat)'
stop 1
endif
enddo
do j=1,ncol
if (.not.any(perm_col.eq.j)) then
write(6,'(A)') 'ERROR: INVALID PERMUTATION'
> // ' VECTOR (permutemat)'
stop 1
endif
enddo
do j=1,ncol
do k=1,nrow
newmat(k,j)=oldmat(perm_row(k),perm_col(j))
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine rescalemat_out(mat,factors,nrow,ncol)
implicit none
! Rescale output of matrix mat in each dimension with the
! corresponding entry in factors. This is equivalent to multiplying
! an appropriate diagonal matrix from the lefthand side. The
! original matrix is destroyed in the process.
!
! mat: matrix to be scaled
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), factors(ncol)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)*factors(j)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine rescalemat_in(mat,factors,nrow,ncol)
implicit none
! Rescale input of matrix mat in each dimension with the
! corresponding entry in factors. This is equivalent to multiplying
! an appropriate diagonal matrix from the righthand side. The
! original matrix is destroyed in the process.
!
! mat: matrix to be scaled
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), factors(nrow)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)*factors(k)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine dmatvec(mat,vec_in,vec_out,nrow,ncol)
implicit none
! Multiply matrix vec with compatible vector vec_in, yielding
! vec_out.
!
! mat: matrix to be scaled
! vec_*: vectors as describe above
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), vec_in(nrow), vec_out(ncol)
integer j,k
vec_out=0.0d0
do j=1,ncol
do k=1,nrow
vec_out(j)=vec_out(j) + mat(k,j)*vec_in(k)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine shiftmat(mat,shift,nrow,ncol)
implicit none
! Add two identically dimensioned matrices mat and shift,
! overwriting mat.
!
! mat: matrix to which shift is added
! shift: addend
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), shift(nrow,ncol)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)+shift(k,j)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine phaselock_maxpos(vectors,vecdim,nvec,maxdim)
implicit none
! Normalizes phases of an array of vectors according to molpro standard,
! meaning that the value furthest from 0 is positive in each vector.
!
! vectors: matrix containing all vectors.
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec)
double precision maxelem,minelem
integer j
do j=1,nvec
maxelem=maxval(vectors(1:vecdim,j))
minelem=minval(vectors(1:vecdim,j))
if (dabs(minelem).gt.maxelem) then
vectors(1:vecdim,j)=-vectors(1:vecdim,j)
endif
enddo
end
!--------------------------------------------------------------------------
subroutine orderlock_maxolap(vectors,ref_vectors,vecdim,
> nvec,maxdim)
implicit none
! Normalizes the order of an array of vectors such that
! similar vectors appear in similar positions.
! The first reference vector takes priority over the second,
! the 2nd over the 3rd etc.
! vectors: matrix containing all vectors.
! ref_vectors: reference vector set
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec),ref_vectors(maxdim,nvec)
double precision olap, maxolap
double precision swap(maxdim)
integer best
integer j,k
do j=1,nvec
! find the vector most similar to reference, using scalar products
maxolap=0.0D0
best=j
do k=j,nvec
! calculate overlap
olap=dabs(dot_product(vectors(1:vecdim,k),
> ref_vectors(1:vecdim,j)))
if (olap.gt.maxolap) then
! update best overlap and mark vector
maxolap=olap
best=k
endif
enddo
! swap places of vectors accordingly
swap=vectors(:,j)
vectors(:,j)=vectors(:,best)
vectors(:,best)=swap
enddo
end
!--------------------------------------------------------------------------
subroutine phaselock_maxolap(vectors,ref_vectors,vecdim,
> nvec,maxdim)
implicit none
! Normalizes phases of an array of vectors such that scalar products
! of corresponding reference vectors are always non-negative.
! vectors: matrix containing all vectors.
! ref_vectors: reference vector set
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec),ref_vectors(maxdim,nvec)
double precision olap
integer j
do j=1,nvec
! calculate overlap
olap=dot_product(vectors(1:vecdim,j),
> ref_vectors(1:vecdim,j))
if (olap.lt.0.0D0) then
vectors(1:vecdim,j) = -1.0D0*vectors(1:vecdim,j)
endif
enddo
end
!--------------------------------------------------------------------------
subroutine safe_average(points,avrg,dim,maxdim,npoints)
implicit none
! Generates the average over a set of dim-dimensional vectors in a
! safe fashion using Kahan Summation.
!
! maxdim: physical dimension of vectors
! dim: actual dimension of vectors
! npoints: number of vectors
! points: array of vectors of length (max)dim.
! avrg: final mean vector
!
integer maxdim
integer dim,npoints
double precision points(maxdim,*), avrg(maxdim)
double precision tmp(maxdim)
double precision norm
integer j,k
norm=dble(npoints)
tmp=0.0d0
avrg=0.0d0
do j=1,npoints
do k=1,dim
call KahanAdd(points(k,j),avrg(k),tmp(k))
enddo
enddo
do k=1,dim
avrg(k)=avrg(k)/norm
enddo
end
!--------------------------------------------------------------------------
subroutine safe_variance(points,avrg,var,dim,maxdim,npoints)
implicit none
! Generates the variance over a set of dim-dimensional vectors in a
! safe fashion using Kahan Summation.
!
! maxdim: physical dimension of vectors
! dim: actual dimension of vectors
! npoints: number of vectors
! points: array of vectors of length (max)dim.
! avrg: mean vector
! var: final variance vector
!
integer maxdim
integer dim,npoints
double precision points(maxdim,*), avrg(maxdim), var(maxdim)
double precision tmp(maxdim)
double precision norm
integer j,k
norm=dble(npoints)
tmp=0.0d0
var=0.0d0
do j=1,npoints
do k=1,dim
call KahanAdd((points(k,j)-avrg(k))**2,var(k),tmp(k))
enddo
enddo
do k=1,dim
var(k)=var(k)/norm
enddo
end
!--------------------------------------------------------------------------
subroutine KahanSum(terms,nterms,sum)
implicit none
! Sums over all nterms entries in the vector terms using Kahan Summation.
! It utilizes an algorithm recovering low-order digits of added terms
! Taken from Wikipedia.
! Algebraically, the variable corr should always be zero. Beware
! overly-aggressive optimizing compilers.
integer nterms
double precision terms(nterms)
double precision sum
double precision corr,tmp,newsum
integer j
sum=0.0d0
corr=0.0d0 ! A running compensation for lost low-order bits.
do j=1,nterms
tmp = terms(j) - corr ! try to add collected lost lower digit summations to sum
newsum = sum + tmp ! low-order digits of tmp are lost to summation
! cancels high-order part of tmp
! subtracting tmp recovers low part of the term
corr = (newsum - sum) - tmp
sum = newsum
enddo
end
!--------------------------------------------------------------------------
subroutine KahanAdd(term,sum,corr)
implicit none
! Add term to sum using Kahan Summation.
! It utilizes an algorithm recovering low-order digits of added terms
! Taken from Wikipedia.
! Algebraically, the variable corr should always be zero. Beware
! overly-aggressive optimizing compilers.
double precision term,sum,corr
double precision tmp,newsum
tmp = term - corr ! try to add collected lost lower digit summations to sum
newsum = sum + tmp ! low-order digits of tmp are lost to summation
! cancels high-order part of tmp
! subtracting tmp recovers low part of the term
corr = (newsum - sum) - tmp
sum = newsum
end
!--------------------------------------------------------------------------
subroutine writemat(funit,mat,matfmt,flen,nrow,ncol,
> nrow_print,ncol_print)
implicit none
! Write (submatrix of) matrix mat using format matfmt on each
! individual value to file unit funit.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen,funit
integer nrow,ncol
integer nrow_print,ncol_print
double precision mat(nrow,ncol)
character*(flen) matfmt
integer j,k
if (nrow_print.gt.nrow) then
write(6,'(A)') 'ERROR: CANNOT PRINT BEYOND MATRIX WIDTH'
> // ' (printmat)'
stop 1
else if (ncol_print.gt.ncol) then
write(6,'(A)') 'ERROR: CANNOT PRINT BEYOND MATRIX HEIGHT'
> // ' (printmat)'
stop 1
endif
do j=1,ncol_print
do k=1,nrow_print
write(unit=funit,fmt=matfmt,advance='NO') mat(k,j)
enddo
write(funit,'()')
enddo
end
!--------------------------------------------------------------------------
subroutine printmat_full(mat,matfmt,flen,nrow,ncol)
implicit none
! Print matrix mat using format matfmt on each
! individual value.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen
integer nrow,ncol
double precision mat(nrow,ncol)
character*(flen) matfmt
integer stdin
parameter (stdin=6)
call writemat(stdin,mat,matfmt,flen,nrow,ncol,nrow,ncol)
end
!--------------------------------------------------------------------------
subroutine writevec(funit,vec,vecfmt,flen,len,wraplen)
implicit none
! Write vector vec of length len in blocks of length wraplen.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen,funit
integer len,wraplen
double precision vec(len)
character*(flen) vecfmt
integer wordcount
integer j
wordcount=0
do while (wordcount.lt.len)
do j=1,min(wraplen,len-wordcount)
wordcount=wordcount+1
write(unit=funit,fmt=vecfmt,advance='NO') vec(wordcount)
enddo
write(funit,'()')
enddo
end
!--------------------------------------------------------------------------
subroutine printvec_full(vec,vecfmt,flen,len,wraplen)
implicit none
! Print vector vec of length len in blocks of length wraplen.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen
integer len,wraplen
double precision vec(len)
character*(flen) vecfmt
integer stdin
parameter (stdin=6)
call writevec(stdin,vec,vecfmt,flen,len,wraplen)
end

530
src/lib/dmatrix.f~ Normal file
View File

@ -0,0 +1,530 @@
************************************************************************
*** dmatrix
*** generic double precision matrix operations
***
************************************************************************
subroutine permutemat(oldmat,newmat,perm_row,perm_col,nrow,ncol)
implicit none
! Allows to perform arbitrary permutations of row- and column
! entries of the matrix (corresponding to permutations of the
! underlying basis sets).
!
! Permutations are symbolized as integer vectors. They should
! contain each number from 1 to nrow/ncol in the desired new order,
! 1 meaning the originally first entry etc.
!
! (1,2,3,..) -Permutation-> (P(1),P(2),...)
!
! oldmat: matrix to be modified
! newmat: generated matrix
! nrow: dimension of row-vectors
! ncol: dimension of column vectors
! perm_*: permutation applied to row or column
!
integer nrow,ncol
integer perm_row(nrow),perm_col(ncol)
double precision oldmat(nrow,ncol),newmat(nrow,ncol)
integer j,k
! check validity of permutations (pidgeonhole principle)
do j=1,nrow
if (.not.any(perm_row.eq.j)) then
write(6,'(A)') 'ERROR: INVALID PERMUTATION'
> // ' VECTOR (permutemat)'
stop 1
endif
enddo
do j=1,ncol
if (.not.any(perm_col.eq.j)) then
write(6,'(A)') 'ERROR: INVALID PERMUTATION'
> // ' VECTOR (permutemat)'
stop 1
endif
enddo
do j=1,ncol
do k=1,nrow
newmat(k,j)=oldmat(perm_row(k),perm_col(j))
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine rescalemat_out(mat,factors,nrow,ncol)
implicit none
! Rescale output of matrix mat in each dimension with the
! corresponding entry in factors. This is equivalent to multiplying
! an appropriate diagonal matrix from the lefthand side. The
! original matrix is destroyed in the process.
!
! mat: matrix to be scaled
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), factors(ncol)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)*factors(j)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine rescalemat_in(mat,factors,nrow,ncol)
implicit none
! Rescale input of matrix mat in each dimension with the
! corresponding entry in factors. This is equivalent to multiplying
! an appropriate diagonal matrix from the righthand side. The
! original matrix is destroyed in the process.
!
! mat: matrix to be scaled
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), factors(nrow)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)*factors(k)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine dmatvec(mat,vec_in,vec_out,nrow,ncol)
implicit none
! Multiply matrix vec with compatible vector vec_in, yielding
! vec_out.
!
! mat: matrix to be scaled
! vec_*: vectors as describe above
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), vec_in(nrow), vec_out(ncol)
integer j,k
vec_out=0.0d0
do j=1,ncol
do k=1,nrow
vec_out(j)=vec_out(j) + mat(k,j)*vec_in(k)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine shiftmat(mat,shift,nrow,ncol)
implicit none
! Add two identically dimensioned matrices mat and shift,
! overwriting mat.
!
! mat: matrix to which shift is added
! shift: addend
! nrow_*: dimension of row-vector in matrix *mat (matrix input)
! ncol_*: dimension of column-vector in matrix *mat (matrix output)
integer nrow,ncol
double precision mat(nrow,ncol), shift(nrow,ncol)
integer j,k
do j=1,ncol
do k=1,nrow
mat(k,j)=mat(k,j)+shift(k,j)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine phaselock_maxpos(vectors,vecdim,nvec,maxdim)
implicit none
! Normalizes phases of an array of vectors according to molpro standard,
! meaning that the value furthest from 0 is positive in each vector.
!
! vectors: matrix containing all vectors.
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec)
double precision maxelem,minelem
integer j
do j=1,nvec
maxelem=maxval(vectors(1:vecdim,j))
minelem=minval(vectors(1:vecdim,j))
if (dabs(minelem).gt.maxelem) then
vectors(1:vecdim,j)=-vectors(1:vecdim,j)
endif
enddo
end
!--------------------------------------------------------------------------
subroutine orderlock_maxolap(vectors,ref_vectors,vecdim,
> nvec,maxdim)
implicit none
! Normalizes the order of an array of vectors such that
! similar vectors appear in similar positions.
! The first reference vector takes priority over the second,
! the 2nd over the 3rd etc.
! vectors: matrix containing all vectors.
! ref_vectors: reference vector set
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec),ref_vectors(maxdim,nvec)
double precision olap, maxolap
double precision swap(maxdim)
integer best
integer j,k
do j=1,nvec
! find the vector most similar to reference, using scalar products
maxolap=0.0D0
best=j
do k=j,nvec
! calculate overlap
olap=dabs(dot_product(vectors(1:vecdim,k),
> ref_vectors(1:vecdim,j)))
if (olap.gt.maxolap) then
! update best overlap and mark vector
maxolap=olap
best=k
endif
enddo
! swap places of vectors accordingly
swap=vectors(:,j)
vectors(:,j)=vectors(:,best)
vectors(:,best)=swap
enddo
end
!--------------------------------------------------------------------------
subroutine phaselock_maxolap(vectors,ref_vectors,vecdim,
> nvec,maxdim)
implicit none
! Normalizes phases of an array of vectors such that scalar products
! of corresponding reference vectors are always non-negative.
! vectors: matrix containing all vectors.
! ref_vectors: reference vector set
! vecdim: dimension of vectors
! nvec: number of vectors
! maxdim: physical vector dimension
integer vecdim,nvec,maxdim
double precision vectors(maxdim,nvec),ref_vectors(maxdim,nvec)
double precision olap
integer j
do j=1,nvec
! calculate overlap
olap=dot_product(vectors(1:vecdim,j),
> ref_vectors(1:vecdim,j))
if (olap.lt.0.0D0) then
vectors(1:vecdim,j) = -1.0D0*vectors(1:vecdim,j)
endif
enddo
end
!--------------------------------------------------------------------------
subroutine safe_average(points,avrg,dim,maxdim,npoints)
implicit none
! Generates the average over a set of dim-dimensional vectors in a
! safe fashion using Kahan Summation.
!
! maxdim: physical dimension of vectors
! dim: actual dimension of vectors
! npoints: number of vectors
! points: array of vectors of length (max)dim.
! avrg: final mean vector
!
integer maxdim
integer dim,npoints
double precision points(maxdim,*), avrg(maxdim)
double precision tmp(maxdim)
double precision norm
integer j,k
norm=dble(npoints)
tmp=0.0d0
avrg=0.0d0
do j=1,npoints
do k=1,dim
call KahanAdd(points(k,j),avrg(k),tmp(k))
enddo
enddo
do k=1,dim
avrg(k)=avrg(k)/norm
enddo
end
!--------------------------------------------------------------------------
subroutine safe_variance(points,avrg,var,dim,maxdim,npoints)
implicit none
! Generates the variance over a set of dim-dimensional vectors in a
! safe fashion using Kahan Summation.
!
! maxdim: physical dimension of vectors
! dim: actual dimension of vectors
! npoints: number of vectors
! points: array of vectors of length (max)dim.
! avrg: mean vector
! var: final variance vector
!
integer maxdim
integer dim,npoints
double precision points(maxdim,*), avrg(maxdim), var(maxdim)
double precision tmp(maxdim)
double precision norm
integer j,k
norm=dble(npoints)
tmp=0.0d0
var=0.0d0
do j=1,npoints
do k=1,dim
call KahanAdd((points(k,j)-avrg(k))**2,var(k),tmp(k))
enddo
enddo
do k=1,dim
var(k)=var(k)/norm
enddo
end
!--------------------------------------------------------------------------
subroutine KahanSum(terms,nterms,sum)
implicit none
! Sums over all nterms entries in the vector terms using Kahan Summation.
! It utilizes an algorithm recovering low-order digits of added terms
! Taken from Wikipedia.
! Algebraically, the variable corr should always be zero. Beware
! overly-aggressive optimizing compilers.
integer nterms
double precision terms(nterms)
double precision sum
double precision corr,tmp,newsum
integer j
sum=0.0d0
corr=0.0d0 ! A running compensation for lost low-order bits.
do j=1,nterms
tmp = terms(j) - corr ! try to add collected lost lower digit summations to sum
newsum = sum + tmp ! low-order digits of tmp are lost to summation
! cancels high-order part of tmp
! subtracting tmp recovers low part of the term
corr = (newsum - sum) - tmp
sum = newsum
enddo
end
!--------------------------------------------------------------------------
subroutine KahanAdd(term,sum,corr)
implicit none
! Add term to sum using Kahan Summation.
! It utilizes an algorithm recovering low-order digits of added terms
! Taken from Wikipedia.
! Algebraically, the variable corr should always be zero. Beware
! overly-aggressive optimizing compilers.
double precision term,sum,corr
double precision tmp,newsum
tmp = term - corr ! try to add collected lost lower digit summations to sum
newsum = sum + tmp ! low-order digits of tmp are lost to summation
! cancels high-order part of tmp
! subtracting tmp recovers low part of the term
corr = (newsum - sum) - tmp
sum = newsum
end
!--------------------------------------------------------------------------
subroutine writemat(funit,mat,matfmt,flen,nrow,ncol,
> nrow_print,ncol_print)
implicit none
! Write (submatrix of) matrix mat using format matfmt on each
! individual value to file unit funit.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen,funit
integer nrow,ncol
integer nrow_print,ncol_print
double precision mat(nrow,ncol)
character*(flen) matfmt
integer j,k
if (nrow_print.gt.nrow) then
write(6,'(A)') 'ERROR: CANNOT PRINT BEYOND MATRIX WIDTH'
> // ' (printmat)'
stop 1
else if (ncol_print.gt.ncol) then
write(6,'(A)') 'ERROR: CANNOT PRINT BEYOND MATRIX HEIGHT'
> // ' (printmat)'
stop 1
endif
do j=1,ncol_print
do k=1,nrow_print
write(unit=funit,fmt=matfmt,advance='NO') mat(k,j)
enddo
write(funit,'()')
enddo
end
!--------------------------------------------------------------------------
subroutine printmat_full(mat,matfmt,flen,nrow,ncol)
implicit none
! Print matrix mat using format matfmt on each
! individual value.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen
integer nrow,ncol
double precision mat(nrow,ncol)
character*(flen) matfmt
integer stdin
parameter (stdin=6)
call writemat(stdin,mat,matfmt,flen,nrow,ncol,nrow,ncol)
end
!--------------------------------------------------------------------------
subroutine writevec(funit,vec,vecfmt,flen,len,wraplen)
implicit none
! Write vector vec of length len in blocks of length wraplen.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen,funit
integer len,wraplen
double precision vec(len)
character*(flen) vecfmt
integer wordcount
integer j
wordcount=0
do while (wordcount.lt.len)
do j=1,min(wraplen,len-wordcount)
wordcount=wordcount+1
write(unit=funit,fmt=vecfmt,advance='NO') vec(j)
enddo
write(funit,'()')
enddo
end
!--------------------------------------------------------------------------
subroutine printvec_full(vec,vecfmt,flen,len,wraplen)
implicit none
! Print vector vec of length len in blocks of length wraplen.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen
integer len,wraplen
double precision vec(len)
character*(flen) vecfmt
integer stdin
parameter (stdin=6)
call writevec(stdin,vec,vecfmt,flen,len,wraplen)
end

140
src/lib/fileread.f Normal file
View File

@ -0,0 +1,140 @@
!-------------------------------------------------------------------
subroutine get_datfile(datnam,dnlen)
implicit none
! Get name of input data file DATNAM either from the program's first
! command line argument or ask the user.
integer dnlen
character*(dnlen) datnam
integer argcount
argcount=iargc()
if (argcount.gt.0) then
call getarg(1,datnam)
else
write(6,'(A)') 'Specify input file:'
write(5,*) datnam
endif
if (len_trim(datnam).eq.dnlen) then
write(6,'(A)') 'ERROR: TRUNCATED FILENAME'
write(6,'(A)') '"' // datnam // '"'
endif
end
!-------------------------------------------------------------------
subroutine internalize_datfile(datnam,infile,linenum,llen,
> maxlines,dnlen)
implicit none
! Read input file located at DATNAM, skipping comments and blank lines.
integer dnlen,llen,maxlines
integer linenum
character*(dnlen) datnam
character*(llen) infile(maxlines)
character*(llen) line
character*32 datfmt
character*16 int2string
integer j
! datfmt=' '
! datfmt = '(' // trim(int2string(llen)) //'A)'
! write(6,"(100('*'))")
!? valgrind has a problem with this. find a fix!
datfmt='(750A)'
write(6,'(A)') 'Reading file ''' // trim(datnam) // ''' ...'
open(600,file=datnam)
linenum=0
do j=1,maxlines
read(600,fmt='(A750)',end=20) line
if (line(1:3).eq.'---') then
write(6,'(A)') 'EOF-mark "---" found at line'
> // trim(int2string(j))
exit
endif
call internalize_line(linenum,infile,line,llen,maxlines)
enddo
20 close(600)
if (j.ge.maxlines) then
write(6,'(A)') 'ERROR: FILE LENGTH EXCEEDING MAXLINES.'
stop 1
endif
write(6,'(A)') 'File read successfully ('
> // trim(int2string(linenum)) // ' lines).'
end
!-------------------------------------------------------------------
subroutine internalize_line(linenum,infile,line,llen,maxlines)
implicit none
! Parse a single line of input. Ignore comments ("!..") and blank
! lines, and turn all input to uppercase.
!
! infile: data file's internalized form
! line: single verbatim line read from physical file
! linenum: current number of non-commentlines read
! increased by 1 if read line is not a comment
! llen: maximum character length of a single line
! maxlines: maximum number of lines in infile
integer llen,maxlines
integer linenum
character*(llen) infile(maxlines)
character*(llen) line
character*(llen) strip
integer line_pos,text_end
integer j
line_pos=linenum+1
! ignore empty lines
if (len_trim(line).eq.0) then
return
endif
! strip needless whitespace
call strip_string(line,strip,llen)
! determine EOL
! ignore comments
text_end=0
do j=1,len_trim(strip)
if (strip(j:j).eq.'!') then
exit
endif
text_end=text_end+1
enddo
if (text_end.eq.llen) then
write(6,'(A,I6)') 'WARNING: POTENTIALLY TRUNCATED LINE:'
write(6,'(A)') '"' // strip(1:60) // '"...'
endif
! skip if line is a comment
if (text_end.eq.0) then
return
endif
infile(line_pos)=' '
! turn string to uppercase and write to infile, ignoring comments
call upcase(strip,infile(line_pos),text_end)
! increment line number
linenum=linenum+1
end

350
src/lib/imatrix.f Normal file
View File

@ -0,0 +1,350 @@
************************************************************************
*** imatrix
*** generic integer matrix operations
***
************************************************************************
subroutine expandimat(oldmat,newmat,nrow_old,ncol_old,
> nrow_new,ncol_new)
implicit none
! Expands a matrix oldmat to matrix newmat. Matrices are assumed to
! lie densely in memory, meaning physical and actual dimension
! coincides for the row-index. New matrix elements remain uninitialized.
!
! oldmat: matrix to be expanded
! newmat: expanded matrix
! nrow_*: dimension of row-vector in matrix *mat
! ncol_*: dimension of column-vector in matrix *mat
integer nrow_old,ncol_old,nrow_new,ncol_new
integer oldmat(nrow_old,ncol_old),newmat(nrow_new,ncol_new)
integer j,k
if (nrow_new.lt.nrow_old) then
write(6,'(A)') 'ERROR: CANNOT DECREASE MATRIX WIDTH'
> // ' (expandmat)'
stop
else if (ncol_new.lt.ncol_old) then
write(6,'(A)') 'ERROR: CANNOT DECREASE MATRIX HEIGHT'
> // ' (expandmat)'
stop
endif
do j=1,ncol_old
do k=1,nrow_old
newmat(k,j)=oldmat(k,j)
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine permuteimat(oldmat,newmat,perm_row,perm_col,nrow,ncol)
implicit none
! Allows to perform arbitrary permutations of row- and column
! entries of the matrix (corresponding to permutations of the
! underlying basis sets).
!
! Permutations are symbolized as integer vectors. They should
! contain each number from 1 to nrow/ncol in the desired new order,
! 1 meaning the originally first entry etc.
!
! (1,2,3,..) -Permutation-> (P(1),P(2),...)
!
! oldmat: matrix to be modified
! newmat: generated matrix
! nrow: dimension of row-vectors
! ncol: dimension of column vectors
! perm_*: permutation applied to row or column
!
integer nrow,ncol
integer perm_row(nrow),perm_col(ncol)
integer oldmat(nrow,ncol),newmat(nrow,ncol)
integer j,k
! check validity of permutations (pidgeonhole principle)
do j=1,nrow
if (.not.any(perm_row.eq.j)) then
write(6,'(A)') 'ERROR: INVALID PERMUTATION'
> // ' VECTOR (permutemat)'
stop 1
endif
enddo
do j=1,ncol
if (.not.any(perm_col.eq.j)) then
write(6,'(A)') 'ERROR: INVALID PERMUTATION'
> // ' VECTOR (permutemat)'
stop 1
endif
enddo
do j=1,ncol
do k=1,nrow
newmat(k,j)=oldmat(perm_row(k),perm_col(j))
enddo
enddo
end
!--------------------------------------------------------------------------
subroutine shuffled_ilist(list,len)
implicit none
! Generates an integer array of length len cotaining all integers
! form 1 to len in random order using a modification of the
! Fisher-Yates shuffle. Source: Wikipedia.
!
! WARNING: it is assumed that the RNG of random.f has been
! initialized.
!
! list: integer array to be written
! len: length of list meant to be written (not phys. dimension)
integer len
integer list(len)
double precision ran
integer ierr
integer j,n
parameter (ierr=6)
do j=1,len
! generate random real in [0,1)
call vranf(ran,1,0,ierr)
! translate to random int in [1,j]
n = 1 + floor(dble(j)*ran)
list(j)=list(n)
list(n)=j
enddo
end
!--------------------------------------------------------------------------
subroutine random_sample_ilist(list,len,maxval)
implicit none
! Generates a random sample of length len from a (virtual) list of
! integers from 1 to maxval using Algorithm R. Source: Wikipedia.
!
! WARNING: it is assumed that the RNG of random.f has been
! initialized.
!
! list: sample to be generated
! len: length of list meant to be written
! maxval: maximum value allowed in list. Assumed to be > len.
integer len,maxval
integer list(len)
double precision ran
integer ierr
parameter (ierr=6)
integer j,n
do j=1,len
list(j)=j
enddo
do j=len+1,maxval
! generate random real in [0,1)
call vranf(ran,1,0,ierr)
! translate to random int in [1,j]
n = 1 + floor(dble(j)*ran)
if (n.le.len) then
list(n)=j
endif
enddo
end
!--------------------------------------------------------------------------
integer function SIndex2(j,k,rowdim)
implicit none
! Map indices of a matrix lying densely in linear memory, with a
! logical row dimension rowdim. In other words, if M and V are
! besides the number of indices identical then
! M(j,k) == V(SIndex2(j,k,rowdim)) for all 1<=j<=rowdim.
!
integer rowdim
integer j,k
SIndex2 = (k-1)*rowdim + j
end
!--------------------------------------------------------------------------
integer function MIndex2(S,rowdim)
implicit none
! Map super index of a matrix lying densely in linear memory, with a
! logical row dimension rowdim to it's minor indices. In other
! words, if M and V are besides the number of indices identical then
! for all j = MIndex(S,rowdim)
! M(j(1),j(2)) == V(S) for all 1<=S.
!
dimension MIndex2(2)
integer rowdim
integer S
integer j(2)
j(1)=mod(S-1,rowdim)+1
j(2)=(S-1)/rowdim + 1
MIndex2=j(:)
end
!--------------------------------------------------------------------------
subroutine MIndexN(supidx,midx,dimnum,dimlen)
implicit none
! Map super index of some dimnum-dimensional array to linear memory
! according to FORTRAN convention, meaning that if V and M are the
! same array with different index convention then
!
! V(supidx) = M(midx(1),midx(2),midx(3),...,midx(dimnum))
! for all supidx >=1, IF dimlen(j) > 1 for all j
!
integer dimnum
integer midx(dimnum),dimlen(dimnum)
integer supidx
integer blocksize(dimnum)
integer sindex
integer j
! calculate block-size for unit indices (1,0,..),(0,1,0,..),...
! that is: 1,n1,n1*n2,...
blocksize=1
do j=2,dimnum
blocksize(j:dimnum)=blocksize(j:dimnum)*dimlen(j-1)
enddo
! superindex needs to start from 0 for fancy modulo arithmetic
sindex=supidx-1
do j=dimnum,1,-1
midx(j)=sindex/(blocksize(j))
sindex=mod(sindex,blocksize(j))
enddo
! set indices back to range [1..ni]
midx=midx+1
end
!--------------------------------------------------------------------------
subroutine MIndexN_range(maxidx,midx,dimnum,dimlen)
implicit none
! Map range of superindices from 1 to maxidx of some
! dimnum-dimensional array to linear memory according to FORTRAN
! convention, meaning that if V and M are the same array with
! different index convention then
!
! V(k) = M(midx(1,k),midx(2,k),...,midx(dimnum,k))
! for all 1<=k<=maxidx, IF dimlen(j) > 1 for all j
!
integer dimnum,maxidx
integer midx(dimnum,maxidx),dimlen(dimnum)
integer blocksize(dimnum)
integer sindex
integer j,k
! calculate block-size for unit indices (1,0,..),(0,1,0,..),...
! that is: 1,n1,n1*n2,...
blocksize=1
do j=2,dimnum
blocksize(j:dimnum)=blocksize(j:dimnum)*dimlen(j-1)
enddo
do k=1,maxidx
! superindex needs to start from 0 for fancy modulo arithmetic
sindex=k-1
do j=dimnum,1,-1
midx(j,k)=sindex/(blocksize(j)) + 1
sindex=mod(sindex,blocksize(j))
enddo
enddo
end
!--------------------------------------------------------------------------
integer function IdxShift(j,start)
implicit none
! Map linear index of a logical vector which is embedded in a memory
! vector and begins at START.
integer j,start
IdxShift=start-1+j
end
!--------------------------------------------------------------------------
subroutine writeivec(funit,vec,vecfmt,flen,len,wraplen)
implicit none
! Write integer vector vec of length len in blocks of length wraplen.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen,funit
integer len,wraplen
integer vec(len)
character*(flen) vecfmt
integer wordcount
integer j
wordcount=0
do while (wordcount.lt.len)
do j=1,min(wraplen,len-wordcount)
wordcount=wordcount+1
write(unit=funit,fmt=trim(vecfmt),advance='NO') vec(j)
enddo
write(funit,'()')
enddo
end
!--------------------------------------------------------------------------
subroutine printivec_full(vec,vecfmt,flen,len,wraplen)
implicit none
! Print integer vector vec of length len in blocks of length wraplen.
!
! flen: length of format string
! mat: matrix to be printed
! nrow: dimension of row-vector in matrix mat (matrix input)
! ncol: dimension of column-vector in matrix mat (matrix output)
! *_print: dimensions of submatrix to be printed
integer flen
integer len,wraplen
integer vec(len)
character*(flen) vecfmt
integer stdin
parameter (stdin=6)
call writeivec(stdin,vec,vecfmt,flen,len,wraplen)
end

275
src/lib/keyread.f Normal file
View File

@ -0,0 +1,275 @@
subroutine keyread(keylist,infile,keynum,idat,ddat,cdat,datpos,
> klen,llen,clen,linenum,maxdat)
implicit none
! Read all keys from KEYLIST from INFILE and write their associated
! data to the corresponding data block. Memory management is
! handled by DATPOS.
!
! keylist: Registry of keys containing the name of the key
! and it's type information.
! keylist(N,1): keyname. It should be in all-caps.
! keylist(N,2): type string of the form "X#"
!
! Note: Key 1 (keylist(1,1)) has the special property that all
! lines of the input file after it's first occurence will be
! ignored. This allows for long input files holding non-key
! information.
!
! typestring syntax:
! X should be I (Integer), +I (Int >= 0), D (double precision),
! C (character string), +D (real >= 0.0d0)
! or E (checks whether key exists).
! X! (e.g. +I!, D!,..) makes a key non-optional.
! E!, while absurd, is a valid option.
! # should be either N (meaning variable length) or an integer >0.
! it encodes the expected number of read values
!
! note: the E-type has no associated *dat-array, instead
! datpos(2,N) is either -1 or it's last occurence in infile,
! depending on whether the key was found. Furthermore,
! E-type keys accept no arguments.
!
! *dat: data arrays for respective items
! klen: length of key/typestring
! llen: line length of infile
! clen: length of read strings
! keynum: number of keys
! linenum: number of lines the file has
! maxdat: maximum number of total input values read
! infile: input file
! datpos: integer array assigning read values to the keys
! datpos(1,N): internalized type (0: I, 1: +I, 2: D, 3: +D,
! 4: C, 5: E)
! datpos(2,N): starting pos. in respective data array
! datpos(3,N): length of data block
!
!? WARNING: *dat() MAY BE WRITTEN BEYOND THEIR LENGTH FOR BAD DIMENSIONS.
!? CATCH THIS!
integer klen, llen, clen
integer keynum, linenum, maxdat
character*(klen) keylist(2,keynum)
character*(llen) infile(linenum)
integer datpos(3,maxdat)
integer idat(maxdat)
double precision ddat(maxdat)
character*(clen) cdat(maxdat)
character*(klen) key
character*64 errmsg
integer intype,inlen,readlen
integer cstart,istart,dstart
integer key_end
integer datnum,inpos,datlen
integer file_stop
logical optional
character*16 int2string, dble2string
integer j,k
cstart=1
istart=1
dstart=1
datnum=0
file_stop=linenum
key=keylist(1,1)
key_end=len_trim(key)
if (key_end.ne.0) then
do k=1,linenum
if (infile(k)(1:key_end).eq.trim(key)) then
file_stop=k
exit
endif
enddo
endif
do j=1,keynum
key=keylist(1,j)
! get information needed to read key
call get_key_kind(keylist(:,j),intype,optional,inlen,klen)
datpos(1,j)=intype
key_end=len_trim(key)
! find last invocation of key (if present)
inpos=0
do k=1,file_stop
if (infile(k)(1:key_end).eq.trim(key)) then
inpos=k
endif
enddo
if (inpos.eq.0) then
if (.not.optional) then
errmsg='MISSING, NON-OPTIONAL KEY'
call signal_key_error(key,errmsg,klen)
endif
datpos(2,j)=-1
datpos(3,j)=0
cycle
endif
! read from last occurence of key
readlen=0
if (intype.le.1) then
datlen=maxdat-istart+1
call long_intkey(infile,inpos,key_end,
> idat,istart,readlen,llen,maxdat,linenum)
else if (intype.le.3) then
datlen=maxdat-dstart+1
call long_realkey(infile,inpos,key_end,
> ddat,dstart,readlen,llen,maxdat,linenum)
else if (intype.eq.4) then
call long_strkey(infile,inpos,key_end,
> cdat,cstart,readlen,llen,maxdat,linenum,clen)
else if (intype.eq.5) then
! since datpos already encodes whether the key was found,
! there is no need to save anything
readlen=0
else
write(6,*) 'ERROR: ENCOUNTERED FAULTY TYPE SPEC.'
stop 1
endif
! check validity of input length
if (inlen.eq.-1) then
inlen=readlen
else if (inlen.ne.readlen) then
errmsg='WRONG NUMBER OF ARGUMENTS'
call signal_key_error(key,errmsg,klen)
endif
! check sign of +X types
if (intype.eq.1) then
do k=1,inlen
if (idat(istart-1+k).lt.0) then
errmsg='UNEXPECTED NEGATIVE INTEGER: '
> // trim(int2string(idat(istart-1+k)))
call signal_key_error(key,errmsg,klen)
endif
enddo
else if (intype.eq.3) then
do k=1,inlen
if (ddat(dstart-1+k).lt.0.0d0) then
errmsg='UNEXPECTED NEGATIVE REAL: '
> // trim(dble2string(ddat(dstart-1+k)))
call signal_key_error(key,errmsg,klen)
endif
enddo
endif
if (intype.le.1) then
datpos(2,j)=istart
istart=istart+inlen
else if (intype.le.3) then
datpos(2,j)=dstart
dstart=dstart+inlen
else if (intype.eq.4) then
datpos(2,j)=cstart
dstart=cstart+inlen
else if (intype.eq.5) then
! remember where you last found the key in infile
datpos(2,j)=inpos
endif
datpos(3,j)=inlen
enddo
end
subroutine get_key_kind(kentry,dattype,optional,datlen,klen)
implicit none
! Read typestring from a keylist entry KENTRY and extract the
! specific type and expected length of KEYs input.
!
! dattype: type of the data, encoded as int
! optional: true if key does not need to be present
! datlen: number of values expected
! klen: length of keys
integer klen
integer dattype,datlen
character*(klen) kentry(2)
logical optional
character*(klen) typestr,key,tmp,numstr
character*64 errmsg
integer strpos,typelen
integer typenum,maxtypelen
parameter (typenum=6,maxtypelen=2)
character*(maxtypelen) types(typenum)
parameter (types=['I ', '+I', 'D ', '+D', 'C ', 'E '])
integer j
key=kentry(1)
typestr=kentry(2)
dattype=-1
strpos=1
! check type declaration against defined types
! There has got to be a smarter way to do this.
do j=1,typenum
typelen=len_trim(types(j))
if (typestr(1:typelen).eq.trim(types(j))) then
dattype=j-1
strpos=typelen+1
exit
endif
enddo
if (dattype.eq.-1) then
errmsg='INVALID TYPE SPEC: '//'"'//typestr(1:maxtypelen)//'"'
call signal_key_error(key,errmsg,klen)
endif
! Any type followed by ! makes the card non-optional, crashing the
! program if it is missing.
optional=(typestr(strpos:strpos).ne.'!')
if (.not.optional) then
strpos=strpos+1
endif
if (dattype.eq.5) then
! since only the key's presence is checked, there is no need to
! read beyond the key
datlen=0
else if (typestr(strpos:strpos).eq.'N') then
datlen=-1
else
call trimnum(typestr,tmp,klen)
call nth_word(tmp,numstr,1,klen)
! crash gracefully if the expected number of values is neither
! int nor "N" (hackey version, but i can't think of a cleaner one)
do j=1,1
read(numstr,*,err=600,end=600) datlen
cycle
600 errmsg='CORRUPTED NUMBER OF VALUES: '
> //'"'//trim(typestr)//'"'
call signal_key_error(key,errmsg,klen)
enddo
if (datlen.le.0) then
errmsg='INVALID TYPE SPEC: '//'"'//trim(typestr)//'"'
call signal_key_error(key,errmsg,klen)
endif
endif
end
subroutine signal_key_error(key,msg,klen)
implicit none
integer klen
character*(klen) key
character*(*) msg
write(6,'(A)') 'ERROR: ' // trim(key) // ' ' // trim(msg)
stop 1
end

343
src/lib/long_keyread.f Normal file
View File

@ -0,0 +1,343 @@
! NOTE: all routines other than long_intkey and long_intline are
! copy-pasted versions of different types.
! replacements:
! idat -> *dat
! ipos -> *pos
! istart -> *start
! LONG_INT -> LONG_*
!---------------------------------------------------------------------------
subroutine long_intkey(infile,inpos,key_end,idat,istart,
> readlen,linelen,maxdat,maxlines)
implicit none
! Read an arbitrary number of integers for a single key from infile
! and write to idat.
!
! Data in infile is expected to have the general format
!
! KEY: ... ... ... ... &
! .... ... ... ... ... &
! .... ... ... ... ...
!
! Lines can be continued using the continuation marker arbitrarily
! often. A continuation marker at the last line causes the program
! to read undefined data following below. If that data is not a
! valid line of integers, the program breaks appropiately.
!
! idat: vector to write read data on
! istart: current position in vector idat (first empty entry)
! maxdat: length of idat
! readlen: the number of read integers for current key
!
! infile: string vector containing the read input file linewise
! key_end: length of key, expected at the first line read
! inpos: current position in infile
! linelen: max. character length of a single line
! maxlines: length of infile
!
! broken: if true, assume read data to be corrupt
! continued: if true, the next input line should continue
! the current data block.
integer maxlines,linelen,maxdat
integer key_end
integer istart,inpos,readlen
integer idat(maxdat)
character*(linelen) infile(maxlines)
logical continued, broken
integer line_start,ipos
character*(linelen) key
integer n
ipos=istart
readlen=0
key=' '
key=infile(inpos)(1:key_end)
! skip key on first line
line_start=key_end+1
call long_intline(infile(inpos),linelen,line_start,
> idat,ipos,maxdat,readlen,
> continued,broken)
line_start=1
do n=inpos+1,maxlines
if (broken) then
continued=.false.
exit
endif
if (.not.continued) then
exit
endif
call long_intline(infile(n),linelen,line_start,
> idat,ipos,maxdat,readlen,
> continued,broken)
enddo
if (continued) then
write(6,'(A)') 'ERROR: LONG_INTKEY: '
> // trim(key) //' CONTINUATION PAST EOF'
write(6,'(A,I5.5)') 'LINE #',n
endif
if (broken) then
write(6,'(A)') 'ERROR: LONG_INTKEY: '
> // trim(key) //' BROKEN INPUT.'
write(6,'(A,I5.5)') 'LINE #',n
write(6,'(A,I5.5,A)') 'AFTER ', n-inpos-1, ' CONTINUATIONS'
stop 1
endif
end
!---------------------------------------------------------------------------
subroutine long_intline(inline,linelen,line_start,
> idat,ipos,maxdat,readlen,
> continued,broken)
implicit none
! Read a single line of string input INLINE encoding integers.
!
! idat: vector to write read data on
! ipos: current position in vector idat (first empty entry)
! maxdat: length of idat
! inline: string containing line from read input file
! linelen: max. character length of a single line
! broken: if true, assume read data to be corrupt
! continued: if true, the next input line should continue
! the current data block.
! readlen: increment counting the number of read ints
! ASSUMED TO BE INITIALIZED.
integer linelen,maxdat
integer line_start,ipos
integer idat(maxdat)
integer readlen
character*(linelen) inline
logical continued, broken
integer line_end, wordcount
character*(linelen) workline, word
integer n
line_end=len_trim(inline)
broken=.false.
! check whether line will be continued
if (inline(line_end:line_end).eq.'&') then
continued=.true.
line_end=line_end-1
else
continued=.false.
endif
! create working copy of line
workline=' '
workline=inline(line_start:line_end)
! check the number of wordcount on line
call count_words(workline,wordcount,linelen)
! if the number of entries exceeds the length of idat, break
if ((wordcount+ipos).ge.maxdat) then
write(6,'(A)') 'ERROR: LONG_INTLINE: PARSER OUT OF MEMORY '
> // 'ON READ'
write(6,'(A)') 'CURRENT LINE:'
write(6,'(A)') trim(inline)
broken=.true.
return
endif
do n=1,wordcount
call nth_word(workline,word,n,linelen)
read(word,fmt=*,err=600,end=600) idat(ipos)
readlen=readlen+1
ipos=ipos+1
cycle
! avoid segfault in parser at all costs, throw error instead
600 write(6,'(A,I4.4)') 'ERROR: LONG_INTLINE: '
> // 'A FATAL ERROR OCCURED ON ENTRY #',
> n
write(6,'(A)') 'CURRENT LINE:'
write(6,'(A)') trim(inline)
broken=.true.
return
enddo
end
!---------------------------------------------------------------------------
subroutine long_realkey(infile,inpos,key_end,ddat,dstart,
> readlen,linelen,maxdat,maxlines)
implicit none
! Read an arbitrary number of double precision reals for a single
! key from infile and write to ddat.
!
! Data in infile is expected to have the general format
!
! KEY: ... ... ... ... &
! .... ... ... ... ... &
! .... ... ... ... ...
!
! Lines can be continued using the continuation marker arbitrarily
! often. A continuation marker at the last line causes the program
! to read undefined data following below. If that data is not a
! valid line of integers, the program breaks appropiately.
!
! ddat: vector to write read data on
! dstart: current position in vector ddat (first empty entry)
! maxdat: length of ddat
! readlen: the number of read integers for current key
!
! infile: string vector containing the read input file linewise
! key_end: length of key, expected at the first line read
! inpos: current position in infile
! linelen: max. character length of a single line
! maxlines: length of infile
!
! broken: if true, assume read data to be corrupt
! continued: if true, the next input line should continue
! the current data block.
integer maxlines,linelen,maxdat
integer key_end
integer dstart,inpos,readlen
double precision ddat(maxdat)
character*(linelen) infile(maxlines)
logical continued, broken
integer line_start,dpos
character*(linelen) key
integer n
dpos=dstart
readlen=0
key=' '
key=infile(inpos)(1:key_end)
! skip key on first line
line_start=key_end+1
call long_realline(infile(inpos),linelen,line_start,
> ddat,dpos,maxdat,readlen,
> continued,broken)
line_start=1
do n=inpos+1,maxlines
if (broken) then
continued=.false.
exit
endif
if (.not.continued) then
exit
endif
call long_realline(infile(n),linelen,line_start,
> ddat,dpos,maxdat,readlen,
> continued,broken)
enddo
if (continued) then
write(6,'(A)') 'ERROR: LONG_REALKEY: '
> // trim(key) //' CONTINUATION PAST EOF'
write(6,'(A,I5.5)') 'LINE #',n
endif
if (broken) then
write(6,'(A)') 'ERROR: LONG_REALKEY: '
> // trim(key) //' BROKEN INPUT.'
write(6,'(A,I5.5)') 'LINE #',n
write(6,'(A,I5.5,A)') 'AFTER ', n-inpos-1, ' CONTINUATIONS'
stop 1
endif
end
!---------------------------------------------------------------------------
subroutine long_realline(inline,linelen,line_start,
> ddat,dpos,maxdat,readlen,
> continued,broken)
implicit none
! Read a single line of string input INLINE encoding double
! precision reals.
!
! ddat: vector to write read data on
! dpos: current position in vector ddat (first empty entry)
! maxdat: length of ddat
! inline: string containing line from read input file
! linelen: max. character length of a single line
! broken: if true, assume read data to be corrupt
! continued: if true, the next input line should continue
! the current data block.
! readlen: increment counting the number of read ints
! ASSUMED TO BE INITIALIZED.
integer linelen,maxdat
integer line_start,dpos
integer readlen
double precision ddat(maxdat)
character*(linelen) inline
logical continued, broken
integer line_end, wordcount
character*(linelen) workline, word
integer n
line_end=len_trim(inline)
broken=.false.
! check whether line will be continued
if (inline(line_end:line_end).eq.'&') then
continued=.true.
line_end=line_end-1
else
continued=.false.
endif
! create working copy of line
workline=' '
workline=inline(line_start:line_end)
! check the number of wordcount on line
call count_words(workline,wordcount,linelen)
! if the number of entries exceeds the length of ddat, break
if ((wordcount+dpos).ge.maxdat) then
write(6,'(A)') 'ERROR: LONG_REALLINE: PARSER OUT OF MEMORY '
> // 'ON READ'
write(6,'(A)') 'CURRENT LINE:'
write(6,'(A)') trim(inline)
broken=.true.
return
endif
do n=1,wordcount
call nth_word(workline,word,n,linelen)
read(word,fmt=*,err=600,end=600) ddat(dpos)
readlen=readlen+1
dpos=dpos+1
cycle
! avoid segfault in parser at all costs, throw error instead
600 write(6,'(A,I4.4)') 'ERROR: LONG_REALLINE: '
> // 'A FATAL ERROR OCCURED ON ENTRY #',
> n
write(6,'(A)') 'CURRENT LINE:'
write(6,'(A)') trim(inline)
broken=.true.
return
enddo
end

132
src/lib/misc.f Normal file
View File

@ -0,0 +1,132 @@
**** Generic convenience subroutines and functions
subroutine ibaserep(x,base,rep_x,len)
implicit none
! Subroutine generating the first len digits of
! the standard representation of an integer x
! in the given base, ignoring the sign.
!
! x: Integer to be represented.
! base: Base of the representation.
! bases <= 1 yield an error.
! len: Length of the vector rep_x.
! rep_x: Vector containing the digits
! of the representation, starting
! with the 0th power.
integer len
integer base
integer x, rep_x(len)
integer z
integer k
if (base.le.1) then
stop 'ERROR: ibaserep: Invalid base.'
endif
! create working copy of x
z=iabs(x)
do k=1,len
rep_x(k) = mod(z,base)
z = z/base
enddo
end
!------------------------------------------------------------
subroutine repeatfmt32(fullfmt,unitfmt,rep,ulen)
implicit none
! Generate a 32 character format string repeating the same
! (up to) 16 character format the given number of times.
!
! Ex.: repeatfmt32(fmt,'ES23.15',50,7)
! is equivalent to
! fmt='( 50ES23.15) '
! which is a valid format string equivalent to '(50ES23.15)'.
!
!
! rep: number of repetitions
! ulen: actual length of unitfmt <=16
! fullfmt: output format string
! unitfmt: segment to be repeated rep times
integer ulen,rep
character*32 fullfmt
character unitfmt(16)
character*16 unit_tmp
if (ulen.gt.16) then
stop 'ERROR: repeatfmt32: string unit exceeding size limit'
else if (rep.ge.10**9) then
stop 'ERROR: repeatfmt32: repetition number too large'
endif
! copy desired unit string
unit_tmp=' '
write(unit_tmp,'(16(A1,:))') unitfmt(1:ulen)
write(fullfmt,'("(",I14,A16)') rep, unit_tmp
fullfmt = trim(fullfmt) // ')'
end
!------------------------------------------------------------
logical function ibetween(min,x,max)
implicit none
! Function checking whether the inequation
! min <= x <= max holds true.
integer min,max,x
ibetween=(min.le.x).and.(x.le.max)
end
!------------------------------------------------------------
logical function dbetween(min,x,max)
implicit none
! Function checking whether the inequation
! min <= x <= max holds true.
double precision min,max,x
dbetween=(min.le.x).and.(x.le.max)
end
!------------------------------------------------------------
logical function dveceq(vec1,vec2,len)
implicit none
! Function comparing two vectors of length len
! element by element, only true if all elements are
! equal
double precision vec1(*),vec2(*)
integer len
dveceq=all( vec1(1:len).eq.vec2(1:len) )
end
!------------------------------------------------------------
logical function dvecne(vec1,vec2,len)
implicit none
! Function comparing two vectors of length len
! element by element, only true if at least one
! is different.
double precision vec1(*),vec2(*)
integer len
dvecne=any( vec1(1:len).ne.vec2(1:len) )
end

429
src/lib/qsort.f Normal file
View File

@ -0,0 +1,429 @@
subroutine dqsort2(n,arr,key)
implicit none
! Sorts an array arr(1:n) into ascending order using Quicksort,
! while making the corresponding rearrangement of the array key(1:n)
! Taken from NUMERICAL RECIPES IN FORTRAN 77, 2nd Ed. (p. 324)
!
! arr: Array to be sorted, expects double precision.
! key: key array to be permuted in the same manner as arr.
! usually key is chosen such that key(j)=j for all j
! on input.
! n: actual length of arr.
!
! M: Size of subarrays sorted by straight insertion
! NSTACK: req. auxiliary storage.
! the maximal processable n is given by 2^(NSTACK/2)
integer n,M,NSTACK
double precision arr(n)
integer key(n),pos
parameter (M=7,NSTACK=50)
double precision a,temp
integer b,itemp
integer istack(NSTACK),jstack
integer i,ir,j,k,l
pos=n+1
jstack=0
l=1
ir=n
1 if (ir-l.lt.M) then
! Insertion sort when subarray is small enough
do j=l+1,ir
a=arr(j)
b=key(j)
do i=j-1,l,-1
if (arr(i).le.a) goto 2
arr(i+1)=arr(i)
key(i+1)=key(i)
enddo
i=l-1
2 arr(i+1)=a
key(i+1)=b
enddo
if (jstack.eq.0) return
! Pop stack and begin a new round of partitioning
ir=istack(jstack)
l=istack(jstack-1)
jstack=jstack-2
else
k=(l+ir)/2
temp=arr(k)
arr(k)=arr(l+1)
arr(l+1)=temp
itemp=key(k)
key(k)=key(l+1)
key(l+1)=itemp
if (arr(l).gt.arr(ir)) then
temp=arr(l)
arr(l)=arr(ir)
arr(ir)=temp
itemp=key(l)
key(l)=key(ir)
key(ir)=itemp
endif
if (arr(l+1).gt.arr(ir)) then
temp=arr(l+1)
arr(l+1)=arr(ir)
arr(ir)=temp
itemp=key(l+1)
key(l+1)=key(ir)
key(ir)=itemp
endif
if (arr(l).gt.arr(l+1)) then
temp=arr(l)
arr(l)=arr(l+1)
arr(l+1)=temp
itemp=key(l)
key(l)=key(l+1)
key(l+1)=itemp
endif
i=l+1
j=ir
a=arr(l+1)
b=key(l+1)
3 continue
i=i+1
if (arr(i).lt.a) goto 3
4 continue
j=j-1
if (arr(j).gt.a) goto 4
if (j.lt.i) goto 5
temp=arr(i)
arr(i)=arr(j)
arr(j)=temp
itemp=key(i)
key(i)=key(j)
key(j)=itemp
goto 3
5 arr(l+1)=arr(j)
arr(j)=a
key(l+1)=key(j)
key(j)=b
jstack=jstack+2
if (jstack.gt.NSTACK) then
stop 'ERROR: NSTACK too small in dqsort2'
endif
if (ir-i+1.ge.j-1) then
istack(jstack)=ir
istack(jstack-1)=i
ir=j-1
else
istack(jstack)=j-1
istack(jstack-1)=l
l=i
endif
endif
goto 1
end
subroutine dqsort(n,arr)
implicit none
! Sorts an array arr(1:n) into ascending order using Quicksort.
! Taken from NUMERICAL RECIPES IN FORTRAN 77, 2nd Ed. (p. 324)
!
! arr: Array to be sorted, expects double precision.
! n: actual length of arr.
!
! M: Size of subarrays sorted by straight insertion
! NSTACK: req. auxiliary storage.
! the maximal processable n is given by 2^(NSTACK/2)
integer n,M,NSTACK
double precision arr(n)
integer pos
parameter (M=7,NSTACK=50)
double precision a,temp
integer istack(NSTACK),jstack
integer i,ir,j,k,l
pos=n+1
jstack=0
l=1
ir=n
1 if (ir-l.lt.M) then
! Insertion sort when subarray is small enough
do j=l+1,ir
a=arr(j)
do i=j-1,l,-1
if (arr(i).le.a) goto 2
arr(i+1)=arr(i)
enddo
i=l-1
2 arr(i+1)=a
enddo
if (jstack.eq.0) return
! Pop stack and begin a new round of partitioning
ir=istack(jstack)
l=istack(jstack-1)
jstack=jstack-2
else
k=(l+ir)/2
temp=arr(k)
arr(k)=arr(l+1)
arr(l+1)=temp
if (arr(l).gt.arr(ir)) then
temp=arr(l)
arr(l)=arr(ir)
arr(ir)=temp
endif
if (arr(l+1).gt.arr(ir)) then
temp=arr(l+1)
arr(l+1)=arr(ir)
arr(ir)=temp
endif
if (arr(l).gt.arr(l+1)) then
temp=arr(l)
arr(l)=arr(l+1)
arr(l+1)=temp
endif
i=l+1
j=ir
a=arr(l+1)
3 continue
i=i+1
if (arr(i).lt.a) goto 3
4 continue
j=j-1
if (arr(j).gt.a) goto 4
if (j.lt.i) goto 5
temp=arr(i)
arr(i)=arr(j)
arr(j)=temp
goto 3
5 arr(l+1)=arr(j)
arr(j)=a
jstack=jstack+2
if (jstack.gt.NSTACK) then
stop 'ERROR: NSTACK too small in dqsort2'
endif
if (ir-i+1.ge.j-1) then
istack(jstack)=ir
istack(jstack-1)=i
ir=j-1
else
istack(jstack)=j-1
istack(jstack-1)=l
l=i
endif
endif
goto 1
end
subroutine iqsort(n,arr)
implicit none
! Sorts an array arr(1:n) into ascending order using Quicksort.
! Taken from NUMERICAL RECIPES IN FORTRAN 77, 2nd Ed. (p. 324)
!
! arr: Array to be sorted, expects integer.
! n: actual length of arr.
!
! M: Size of subarrays sorted by straight insertion
! NSTACK: req. auxiliary storage.
! the maximal processable n is given by 2^(NSTACK/2)
integer n,M,NSTACK
integer arr(n)
integer pos
parameter (M=7,NSTACK=50)
integer a,temp
integer istack(NSTACK),jstack
integer i,ir,j,k,l
pos=n+1
jstack=0
l=1
ir=n
1 if (ir-l.lt.M) then
! Insertion sort when subarray is small enough
do j=l+1,ir
a=arr(j)
do i=j-1,l,-1
if (arr(i).le.a) goto 2
arr(i+1)=arr(i)
enddo
i=l-1
2 arr(i+1)=a
enddo
if (jstack.eq.0) return
! Pop stack and begin a new round of partitioning
ir=istack(jstack)
l=istack(jstack-1)
jstack=jstack-2
else
k=(l+ir)/2
temp=arr(k)
arr(k)=arr(l+1)
arr(l+1)=temp
if (arr(l).gt.arr(ir)) then
temp=arr(l)
arr(l)=arr(ir)
arr(ir)=temp
endif
if (arr(l+1).gt.arr(ir)) then
temp=arr(l+1)
arr(l+1)=arr(ir)
arr(ir)=temp
endif
if (arr(l).gt.arr(l+1)) then
temp=arr(l)
arr(l)=arr(l+1)
arr(l+1)=temp
endif
i=l+1
j=ir
a=arr(l+1)
3 continue
i=i+1
if (arr(i).lt.a) goto 3
4 continue
j=j-1
if (arr(j).gt.a) goto 4
if (j.lt.i) goto 5
temp=arr(i)
arr(i)=arr(j)
arr(j)=temp
goto 3
5 arr(l+1)=arr(j)
arr(j)=a
jstack=jstack+2
if (jstack.gt.NSTACK) then
stop 'ERROR: NSTACK too small in dqsort2'
endif
if (ir-i+1.ge.j-1) then
istack(jstack)=ir
istack(jstack-1)=i
ir=j-1
else
istack(jstack)=j-1
istack(jstack-1)=l
l=i
endif
endif
goto 1
end
subroutine reverse_dqsort2(n,arr,key)
implicit none
! Sorts an array arr(1:n) into descending order using Quicksort,
! while making the corresponding rearrangement of the array key(1:n)
! Taken from NUMERICAL RECIPES IN FORTRAN 77, 2nd Ed. (p. 324)
!
! arr: Array to be sorted, expects double precision.
! key: key array to be permuted in the same manner as arr.
! usually key is chosen such that key(j)=j for all j
! on input.
! n: actual length of arr.
!
! M: Size of subarrays sorted by straight insertion
! NSTACK: req. auxiliary storage.
! the maximal processable n is given by 2^(NSTACK/2)
integer n,M,NSTACK
double precision arr(n)
integer key(n),pos
parameter (M=7,NSTACK=50)
double precision a,temp
integer b,itemp
integer istack(NSTACK),jstack
integer i,ir,j,k,l
pos=n+1
jstack=0
l=1
ir=n
1 if (ir-l.lt.M) then
! Insertion sort when subarray is small enough
do j=l+1,ir
a=arr(j)
b=key(j)
do i=j-1,l,-1
if (arr(i).ge.a) goto 2
arr(i+1)=arr(i)
key(i+1)=key(i)
enddo
i=l-1
2 arr(i+1)=a
key(i+1)=b
enddo
if (jstack.eq.0) return
! Pop stack and begin a new round of partitioning
ir=istack(jstack)
l=istack(jstack-1)
jstack=jstack-2
else
k=(l+ir)/2
temp=arr(k)
arr(k)=arr(l+1)
arr(l+1)=temp
itemp=key(k)
key(k)=key(l+1)
key(l+1)=itemp
if (arr(l).lt.arr(ir)) then
temp=arr(l)
arr(l)=arr(ir)
arr(ir)=temp
itemp=key(l)
key(l)=key(ir)
key(ir)=itemp
endif
if (arr(l+1).lt.arr(ir)) then
temp=arr(l+1)
arr(l+1)=arr(ir)
arr(ir)=temp
itemp=key(l+1)
key(l+1)=key(ir)
key(ir)=itemp
endif
if (arr(l).lt.arr(l+1)) then
temp=arr(l)
arr(l)=arr(l+1)
arr(l+1)=temp
itemp=key(l)
key(l)=key(l+1)
key(l+1)=itemp
endif
i=l+1
j=ir
a=arr(l+1)
b=key(l+1)
3 continue
i=i+1
if (arr(i).gt.a) goto 3
4 continue
j=j-1
if (arr(j).lt.a) goto 4
if (j.lt.i) goto 5
temp=arr(i)
arr(i)=arr(j)
arr(j)=temp
itemp=key(i)
key(i)=key(j)
key(j)=itemp
goto 3
5 arr(l+1)=arr(j)
arr(j)=a
key(l+1)=key(j)
key(j)=b
jstack=jstack+2
if (jstack.gt.NSTACK) then
stop 'ERROR: NSTACK too small in dqsort2'
endif
if (ir-i+1.ge.j-1) then
istack(jstack)=ir
istack(jstack-1)=i
ir=j-1
else
istack(jstack)=j-1
istack(jstack-1)=l
l=i
endif
endif
goto 1
end

50
src/lib/ran.f Normal file
View File

@ -0,0 +1,50 @@
double precision function ranget()
! Even shorter rn(), to remove visual clutter
implicit none
double precision rn
ranget=rn(1,1,0)
end
!--------------------------------------------------------------------------------------
double precision function ranget_gauss(sig)
implicit none
! Draw a single value from a gaussian distribution with a standard
! deviation of sig.
double precision sig
double precision gran(1)
integer iout ! standard output
parameter (iout=6)
call gautrg(gran,1,0,iout)
ranget_gauss=gran(1)*dabs(sig)
end
!--------------------------------------------------------------------------------------
integer function ranget_int(max)
implicit none
! Get a random int between 1 and max.
integer max
double precision ranget
ranget_int=floor(dble(max)*ranget())+1
end
!--------------------------------------------------------------------------------------
double precision function ranget_sym(spread)
implicit none
! Get a random real between -spread and spread.
double precision spread
double precision ranget
ranget_sym=(ranget()-0.5D0)*2.0D0*spread
end

133
src/lib/ran_gv.f Normal file
View File

@ -0,0 +1,133 @@
**** Custom extension to random.f
*** NOTE: IF THE RNG HAS BEEN INITIALIZED BY vranf ANYWHERE
*** IN THE CODE, IT IS NOT NECESSARY TO REINITIALIZE.
subroutine granvec(vecs,vdim,nvec,seed)
implicit none
! Generates vectors of dimension vdim. Resulting vectors are
! distributed uniformly for all angles.
! The vector norm is distributed normally (r>0) and centered at the
! origin but limited to an interval
! rmin <= r <= rmax for numerical reasons.
! rmin and rmax scale with sqrt(vdim) due to the progression of
! |(1)|, |(1 1)|, |(1 1 1)| ...
!
! vdim: dimension of a single vector.
! nvec: number of vectors to be stored in vecs
! vecs: random vectors
! seed: seed for RNG
integer vdim,nvec
double precision vecs(vdim,nvec)
integer seed
double precision rmin,rmax
double precision norm
integer iout
integer j,k
parameter (rmin=0.1d0,rmax=1.5,iout=6)
! force seed to be negative integer
seed=-iabs(seed)
! initalize RNG
call gautrg(vecs,0,seed,iout)
do j=1,nvec
norm=-1.0d0
! sort out too large/small vectors
do while ((norm.le.rmin).or.(norm.ge.rmax))
! generate vector
call gautrg(vecs(1,j),vdim,0,iout)
! calculate norm
norm=0.0d0
do k=1,vdim
norm=norm+vecs(k,j)**2
enddo
norm=dsqrt(norm/vdim)
enddo
enddo
end
subroutine nnorm_grv(vecs,vdim,nvec)
implicit none
! Generates vector(s) of dimension vdim. Resulting vectors are
! distributed uniformly for all angles. vranf is assumed
! to be already initialized.
!
! The norm is set to be sqrt(vdim), such that the in case
! of all vector elements being the same size they would be
! 'normalized' to 1.
!
! vdim: dimension of a single vector.
! nvec: number of vectors to be stored in vecs
! vecs: random vectors.
integer vdim,nvec
double precision vecs(vdim,nvec)
integer seed
double precision norm
integer j,k
! generate vectors
seed=0
call granvec(vecs,vdim,nvec,seed)
do j=1,nvec
! calculate norm
norm=0.0d0
do k=1,vdim
norm=norm+vecs(k,j)**2
enddo
! renorm vectors to vdim
norm=dsqrt(vdim/norm)
do k=1,vdim
vecs(k,j)=vecs(k,j)*norm
enddo
enddo
end
subroutine normal_grv(vecs,vdim,nvec)
implicit none
! Generates vector(s) of dimension vdim. Resulting vectors are
! distributed uniformly for all angles. vranf is assumed
! to be already initialized.
!
! The norm is set to be 1.
!
! vdim: dimension of a single vector.
! nvec: number of vectors to be stored in vecs
! vecs: random vectors.
integer vdim,nvec
double precision vecs(vdim,nvec)
integer seed
double precision norm
integer j,k
! generate vectors
seed=0
call granvec(vecs,vdim,nvec,seed)
do j=1,nvec
! calculate norm
norm=0.0d0
do k=1,vdim
norm=norm+vecs(k,j)**2
enddo
! renorm vectors to vdim
norm=dsqrt(1.0d0/norm)
do k=1,vdim
vecs(k,j)=vecs(k,j)*norm
enddo
enddo
end

1365
src/lib/random.f Normal file

File diff suppressed because it is too large Load Diff

BIN
src/lib/random.o Normal file

Binary file not shown.

46
src/lib/ranlfg.inc Normal file
View File

@ -0,0 +1,46 @@
c---------------------------- ranlfg.inc -------------------------------
c---+----|----+----|----+----|----+----|----+----|----+----|----+----|--
c
c parameters for lagged fibonacci generators and common block with
c generator state
c
c-----------------------------------------------------------------------
c
c possible (np,nq) values, (np,np-nq) is also valid:
c (17,5), (250,103), (521,158), (1279,418),
c (2281,715), (4423,1393), (1279,1063)
c ref.: Bhanot et al., phys. rev b 33, 7841 (1986);
c Zierler, inf. control 15, 67 (1961)
c
c mersenne prime primitive trinomials:
c (heringa et al. int.j.mod.phys.c 3, 561 (1992))
c
c (89,38)
c (127,1), (127,7), (127,15), (127,30), (127,63)
c (521,32), (521,48), (521,158), (521,168)
c (607,105), (607,147), (607, 273)
c (1279,216), (1279,418)
c (2281,715), (2281,915), (2281,1029)
c (3217,67), (3217,576)
c (4423,271), (4423,369), (4423,370), (4423,649), (4424,1393),
c (4423,1419), (4423,2098)
c (9689,84), (9689,471), (9689,1836), (9689,2444), (9689,4187)
c (19937,881), (19937,7083), (19937,9842)
c (23209,1530), (23209,6619), (23209,9739)
c (44497,8575), (44497,21034)
c (110503,25230), (110503,53719)
c (132049,7000), (132049,33912), (132049,41469), (132049,52549),
c (132049,54454)
c
c another pair from brent92 who recommends q=0.618p : (258,175)
c brent's ranu4 uses (132049,79500)
c
c-----------------------------------------------------------------------
c parameter (np=250,nq=103)
parameter (np=1279,nq=418)
c parameter (np=2281,nq=715)
c parameter (np=4423,nq=1393)
save /xrandf/
common /xrandf/ x(np),last,init
c---+----|----+----|----+----|----+----|----+----|----+----|----+----|--
c----------------------------- last line -------------------------------

526
src/lib/strings.f Normal file
View File

@ -0,0 +1,526 @@
!----------------------------------------------------------------------------
subroutine capital(in,str,lauf,mmax,sl)
implicit none
integer mmax,lauf,i,j,sl
character in(mmax)*(*), str*(*)
if (str.eq.'') return
j=0
do i=1,sl
if (str(i:i).ne.' ') then
j=i-1
goto 10
endif
enddo
10 do i=1,sl-j
str(i:i)=str(i+j:i+j)
enddo
do i=sl-j+1,sl
str(i:i)=' '
enddo
if (str(1:1).eq.'!') return
lauf=lauf+1
do i=1,sl
in(lauf)(i:i)=str(i:i)
if (str(i:i).eq.'a') in(lauf)(i:i)='A'
if (str(i:i).eq.'b') in(lauf)(i:i)='B'
if (str(i:i).eq.'c') in(lauf)(i:i)='C'
if (str(i:i).eq.'d') in(lauf)(i:i)='D'
if (str(i:i).eq.'e') in(lauf)(i:i)='E'
if (str(i:i).eq.'f') in(lauf)(i:i)='F'
if (str(i:i).eq.'g') in(lauf)(i:i)='G'
if (str(i:i).eq.'h') in(lauf)(i:i)='H'
if (str(i:i).eq.'i') in(lauf)(i:i)='I'
if (str(i:i).eq.'j') in(lauf)(i:i)='J'
if (str(i:i).eq.'k') in(lauf)(i:i)='K'
if (str(i:i).eq.'l') in(lauf)(i:i)='L'
if (str(i:i).eq.'m') in(lauf)(i:i)='M'
if (str(i:i).eq.'n') in(lauf)(i:i)='N'
if (str(i:i).eq.'o') in(lauf)(i:i)='O'
if (str(i:i).eq.'p') in(lauf)(i:i)='P'
if (str(i:i).eq.'q') in(lauf)(i:i)='Q'
if (str(i:i).eq.'r') in(lauf)(i:i)='R'
if (str(i:i).eq.'s') in(lauf)(i:i)='S'
if (str(i:i).eq.'t') in(lauf)(i:i)='T'
if (str(i:i).eq.'u') in(lauf)(i:i)='U'
if (str(i:i).eq.'v') in(lauf)(i:i)='V'
if (str(i:i).eq.'w') in(lauf)(i:i)='W'
if (str(i:i).eq.'x') in(lauf)(i:i)='X'
if (str(i:i).eq.'y') in(lauf)(i:i)='Y'
if (str(i:i).eq.'z') in(lauf)(i:i)='Z'
C..... Addition of the first if-loop
if (i-3.gt.0) then
if (in(lauf)(i-3:i).eq.'CHK:') then
in(lauf)(i+1:sl)=str(i+1:sl)
return
endif
endif
! if (i+3.le.sl) then
! if (in(lauf)(i:i+3).eq.'CHK:') then
! in(lauf)(i+1:sl)=str(i+1:sl)
! return
! endif
! endif
enddo
end
!-----------------------------------------------------------------------
subroutine lcap(str,n)
implicit none
integer i, n
character str*(*), dum*750
dum=''
do i=1,n
dum(i:i)=str(i:i)
if (str(i:i).eq.'a') dum(i:i)='A'
if (str(i:i).eq.'b') dum(i:i)='B'
if (str(i:i).eq.'c') dum(i:i)='C'
if (str(i:i).eq.'d') dum(i:i)='D'
if (str(i:i).eq.'e') dum(i:i)='E'
if (str(i:i).eq.'f') dum(i:i)='F'
if (str(i:i).eq.'g') dum(i:i)='G'
if (str(i:i).eq.'h') dum(i:i)='H'
if (str(i:i).eq.'i') dum(i:i)='I'
if (str(i:i).eq.'j') dum(i:i)='J'
if (str(i:i).eq.'k') dum(i:i)='K'
if (str(i:i).eq.'l') dum(i:i)='L'
if (str(i:i).eq.'m') dum(i:i)='M'
if (str(i:i).eq.'n') dum(i:i)='N'
if (str(i:i).eq.'o') dum(i:i)='O'
if (str(i:i).eq.'p') dum(i:i)='P'
if (str(i:i).eq.'q') dum(i:i)='Q'
if (str(i:i).eq.'r') dum(i:i)='R'
if (str(i:i).eq.'s') dum(i:i)='S'
if (str(i:i).eq.'t') dum(i:i)='T'
if (str(i:i).eq.'u') dum(i:i)='U'
if (str(i:i).eq.'v') dum(i:i)='V'
if (str(i:i).eq.'w') dum(i:i)='W'
if (str(i:i).eq.'x') dum(i:i)='X'
if (str(i:i).eq.'y') dum(i:i)='Y'
if (str(i:i).eq.'z') dum(i:i)='Z'
enddo
str(1:n)=dum(1:n)
end
!--------------------------------------------------------------------------
! function to test how many entries are on one line:
function clen(str,sl)
implicit none
integer clen, i, j, sl
character str*(sl)
clen=0
j=0
do i=sl,1,-1
if ((str(i:i).ne.' ').and.(j.eq.0)) then
clen=clen+1
j=1
endif
if (str(i:i).eq.' ') j=0
enddo
end
!--------------------------------------------------------------------------
logical function isnumeral(char)
implicit none
! Check whether character CHAR is a numeral.
character char
character numerals(10)
parameter (numerals = ['0','1','2','3','4','5','6','7','8','9'])
isnumeral=any(numerals.eq.char)
end
!--------------------------------------------------------------------------
logical function iswhitespace(char)
implicit none
! Check whether CHAR is tab or spc character
character char
character whitespace(2)
parameter (whitespace = [' ', ' '])
iswhitespace=any(whitespace.eq.char)
end
!--------------------------------------------------------------------------
subroutine trimnum(string,outstr,str_len)
implicit none
! Extract numbers in STRING as a space separated list in OUTSTR.
integer str_len
character*(str_len) string
character*(str_len) outstr
integer length
logical foundnum
integer k
logical isnumeral
length=len_trim(string)
foundnum=.false.
outstr=' '
do k=1,length
if (isnumeral(string(k:k))) then
if (foundnum) then
outstr = trim(outstr) // string(k:k)
else if (len_trim(outstr).ne.0) then
outstr = trim(outstr) // ' ' // string(k:k)
foundnum=.true.
else
outstr = trim(outstr) // string(k:k)
foundnum=.true.
endif
else
foundnum=.false.
endif
enddo
end
!--------------------------------------------------------------------------
subroutine strip_string(string,stripped,str_len)
implicit none
! Strip lefthand whitespace of STRING as well as excessive
! whitespace and save to STRIPPED.
! Example:
! " the quick brown fox" -> "the quick brown fox"
integer str_len
character*(str_len) string,stripped
character char
logical spaced
logical iswhitespace
integer k, trimpos
stripped=' '
trimpos=1
! spaced indicates whether if a space is found it is the first
! (separating the word from the next) or redundant
spaced=.true.
do k=1,len_trim(string)
char=string(k:k)
if (.not.iswhitespace(char)) then
spaced=.false.
else if (.not.spaced) then
! replace TAB characters if present
char=' '
spaced=.true.
else
! ignore redundant spaces
cycle
endif
stripped(trimpos:trimpos)=char
trimpos=trimpos+1
enddo
end
!--------------------------------------------------------------------------
subroutine nth_word(string,word,n,str_len)
implicit none
! If STRING is a space separated list of words, return the Nth word.
integer str_len
character*(str_len) string,word
integer n
character*(str_len) strip
integer wc
logical iswhitespace
integer k,j
call strip_string(string,strip,str_len)
word=' '
wc=1
! find the word
do k=1,len_trim(strip)
if (wc.eq.n) exit
if (iswhitespace(strip(k:k))) then
wc=wc+1
endif
enddo
do j=k,len_trim(strip)
if (iswhitespace(strip(j:j))) exit
word = trim(word) // strip(j:j)
enddo
end
!--------------------------------------------------------------------------
subroutine count_words(string,wordcount,str_len)
implicit none
! If STRING is a space separated list of words, return the Nth word.
integer str_len
character*(str_len) string
integer wordcount
character*(str_len) strip
integer wc
logical iswhitespace
integer k
call strip_string(string,strip,str_len)
if (len_trim(strip).gt.0) then
wc=1
else
wordcount=0
return
endif
! find the word
do k=1,len_trim(strip)
if (iswhitespace(strip(k:k))) then
wc=wc+1
endif
enddo
wordcount=wc
end
!--------------------------------------------------------------------------
subroutine upcase(string,upstring,str_len)
implicit none
! Transform arbitrary string to uppercase and save to upstring
integer str_len
character*(str_len) string,upstring
integer j
upstring=' '
do j=1,len_trim(string)
select case (string(j:j))
case ('a')
upstring(j:j)= 'A'
case ('b')
upstring(j:j)= 'B'
case ('c')
upstring(j:j)= 'C'
case ('d')
upstring(j:j)= 'D'
case ('e')
upstring(j:j)= 'E'
case ('f')
upstring(j:j)= 'F'
case ('g')
upstring(j:j)= 'G'
case ('h')
upstring(j:j)= 'H'
case ('i')
upstring(j:j)= 'I'
case ('j')
upstring(j:j)= 'J'
case ('k')
upstring(j:j)= 'K'
case ('l')
upstring(j:j)= 'L'
case ('m')
upstring(j:j)= 'M'
case ('n')
upstring(j:j)= 'N'
case ('o')
upstring(j:j)= 'O'
case ('p')
upstring(j:j)= 'P'
case ('q')
upstring(j:j)= 'Q'
case ('r')
upstring(j:j)= 'R'
case ('s')
upstring(j:j)= 'S'
case ('t')
upstring(j:j)= 'T'
case ('u')
upstring(j:j)= 'U'
case ('v')
upstring(j:j)= 'V'
case ('w')
upstring(j:j)= 'W'
case ('x')
upstring(j:j)= 'X'
case ('y')
upstring(j:j)= 'Y'
case ('z')
upstring(j:j)= 'Z'
case default
upstring(j:j)=string(j:j)
end select
enddo
end
!--------------------------------------------------------------------------
subroutine downcase(string,downstring,str_len)
implicit none
! Transform arbitrary string to downcase and save to downstring
integer str_len
character*(str_len) string,downstring
integer j
downstring=' '
do j=1,len_trim(string)
select case (string(j:j))
case ('A')
downstring(j:j)= 'a'
case ('B')
downstring(j:j)= 'b'
case ('C')
downstring(j:j)= 'c'
case ('D')
downstring(j:j)= 'd'
case ('E')
downstring(j:j)= 'e'
case ('F')
downstring(j:j)= 'f'
case ('G')
downstring(j:j)= 'g'
case ('H')
downstring(j:j)= 'h'
case ('I')
downstring(j:j)= 'i'
case ('J')
downstring(j:j)= 'j'
case ('K')
downstring(j:j)= 'k'
case ('L')
downstring(j:j)= 'l'
case ('M')
downstring(j:j)= 'm'
case ('N')
downstring(j:j)= 'n'
case ('O')
downstring(j:j)= 'o'
case ('P')
downstring(j:j)= 'p'
case ('Q')
downstring(j:j)= 'q'
case ('R')
downstring(j:j)= 'r'
case ('S')
downstring(j:j)= 's'
case ('T')
downstring(j:j)= 't'
case ('U')
downstring(j:j)= 'u'
case ('V')
downstring(j:j)= 'v'
case ('W')
downstring(j:j)= 'w'
case ('X')
downstring(j:j)= 'x'
case ('Y')
downstring(j:j)= 'y'
case ('Z')
downstring(j:j)= 'z'
case default
downstring(j:j)=string(j:j)
end select
enddo
end
!--------------------------------------------------------------------------
character*16 function int2string(int)
implicit none
! Convert integer to string of length 16.
integer int
character*16 istr
istr=' '
write(istr,*) int
do while (istr(1:1).eq.' ')
istr(1:16) = istr(2:16) // ' '
enddo
int2string=istr
end
!--------------------------------------------------------------------------
character*16 function dble2string(dble)
implicit none
! Convert double precision float to string of length 16.
double precision dble
character*16 dstr
dstr=' '
write(dstr,'(ES16.9)') dble
if (dstr(1:1).eq.' ') then
dstr(1:16) = dstr(2:16) // ' '
endif
dble2string=dstr
end
!--------------------------------------------------------------------------
character*16 function shortdble2string(dble)
implicit none
! Convert double precision float to string of length 16 using a
! shortened format
double precision dble
character*16 dstr
dstr=' '
write(dstr,'(ES11.2)') dble
if (dstr(1:1).eq.' ') then
dstr(1:16) = dstr(2:16) // ' '
endif
shortdble2string=dstr
end

5
src/lib/typedef.incl Normal file
View File

@ -0,0 +1,5 @@
integer typenum,maxtypelen
parameter (typenum=6,maxtypelen=2)
character*(maxtypelen) types(typenum)
parameter (types=['I ', '+I', 'D ', '+D', 'C ', 'E '])

343
src/long_io.f Normal file
View File

@ -0,0 +1,343 @@
************************************************************************
*** long_io
*** reading & writing genetic's long input format
***
************************************************************************
subroutine write_longint(f_unit,params,plen,intfmt,maxvals)
implicit none
! Routine writing long integer output of the form
! x1 x2 x3 .... xN &
! ... &
!
! f_unit: UNIT to be written on, directly passed to write
! params: integer vector to be written out
! plen: number of elements to be printed
! maxvals: (maximum) number of values per line
! intfmt: format of a single interger, e.g. '(I6)'
integer f_unit
integer params(*)
integer plen,maxvals
character*16 intfmt
integer pcount
integer j,k
pcount=0 ! count parameters written so far
! write all values that fill entire lines.
do k=1,(plen/maxvals)
do j=1,maxvals
write(unit=f_unit,fmt=intfmt,advance='NO') params(pcount+j)
enddo
pcount=pcount+maxvals
if (pcount.lt.plen) then
write(unit=f_unit,fmt='(A)') ' &'
endif
enddo
pcount=pcount+1
! write remaining few
do k=pcount,plen
write(unit=f_unit,fmt=intfmt,advance='NO') params(k)
enddo
write(f_unit,'(A)') ''
end
!----------------------------------------------------------------------------
subroutine write_longreal(f_unit,params,plen,dfmt,maxvals)
implicit none
! Routine writing long real(*8) output of the form
! x1 x2 x3 .... xN &
! ... &
!
! f_unit: UNIT to be written on, directly passed to write
! params: integer vector to be written out
! plen: number of elements to be printed
! maxvals: (maximum) number of values per line
! dfmt: format of a single real, e.g. '(ES23.15)'
double precision params(*)
integer f_unit
integer plen,maxvals
character*16 dfmt
integer pcount
integer j,k
pcount=0 ! count parameters written so far
! write all values that fill entire lines.
do k=1,(plen/maxvals)
do j=1,maxvals
write(unit=f_unit,fmt=dfmt,advance='NO') params(pcount+j)
enddo
pcount=pcount+maxvals
if (pcount.lt.plen) then
write(unit=f_unit,fmt='(A)') ' &'
endif
enddo
pcount=pcount+1
! write remaining few
do k=pcount,plen
write(unit=f_unit,fmt=dfmt,advance='NO') params(k)
enddo
write(f_unit,'(A)') ''
end
!---------------------------------------------------------------------------
subroutine long_strkey(infile,inpos,key_end,cdat,cstart,
> readlen,linelen,datlen,maxlines,clen)
implicit none
! Read an arbitrary number of strings for a single key from infile
! and write to idat.
!
! Data in infile is expected to have the general format
!
! KEY: ... ... ... ... &
! .... ... ... ... ... &
! .... ... ... ... ...
!
! Lines can be continued using the continuation marker arbitrarily
! often. A continuation marker at the last line causes the program
! to read undefined data following below. If that data is not a
! valid line of strings, the program breaks appropiately.
!
! cdat: vector to write read data on
! cstart: current position in vector idat (first empty entry)
! datlen: length of idat
! readlen: the number of read integers for current key
!
! infile: string vector containing the read input file linewise
! key_end: length of key, expected at the first line read
! inpos: current position in infile
! linelen: max. character length of a single line
! maxlines: length of infile
! clen: maximum length of a given string
!
! broken: if true, assume read data to be corrupt
! continued: if true, the next input line should continue
! the current data block.
! append: if true, continue appending to an existing string.
integer maxlines,linelen,datlen,clen
integer key_end
integer cstart,inpos,readlen
character*(linelen) infile(maxlines)
character*(clen) cdat(datlen)
integer line_start,cpos
integer strpos
character*(linelen) key
logical continued, broken
integer n
cpos=cstart
readlen=0
key=' '
key=infile(inpos)(1:key_end)
! skip key on first line
line_start=key_end+1
strpos=0
call long_strline(infile(inpos),linelen,line_start,
> cdat,cpos,datlen,readlen,clen,
> continued,broken,strpos)
line_start=1
do n=inpos+1,maxlines
if (broken) then
continued=.false.
exit
endif
if (.not.continued) then
exit
endif
call long_strline(infile(n),linelen,line_start,
> cdat,cpos,datlen,readlen,clen,
> continued,broken,strpos)
enddo
if (continued) then
write(6,'(A)') 'ERROR: LONG_STRKEY: '
> // trim(key) //' CONTINUATION PAST EOF'
write(6,'(A,I5.5)') 'LINE #',n
endif
if (broken) then
write(6,'(A)') 'ERROR: LONG_STRKEY: '
> // trim(key) //' BROKEN INPUT.'
write(6,'(A,I5.5)') 'LINE #',n
write(6,'(A,I5.5,A)') 'AFTER ', n-inpos-1, ' CONTINUATIONS'
stop 1
endif
end
!---------------------------------------------------------------------------
subroutine long_strline(inline,linelen,line_start,
> cdat,cpos,datlen,readlen,clen,
> continued,broken,strpos)
implicit none
! Read a single line of string input INLINE encoding integers.
!
! cdat: vector to write read data on
! cpos: current position in vector cdat (first empty/incomplete entry)
! datlen: length of idat
! inline: string containing line from read input file
! linelen: max. character length of a single line
! broken: if true, assume read data to be corrupt
! continued: if true, the next input line should continue
! the current data block.
! readlen: increment counting the number of read strings
! ASSUMED TO BE INITIALIZED.
! strpos: if 0, create new string. Otherwise, append to string of assumed
! length strpos.
integer linelen,datlen,clen
integer line_start,cpos,strpos
integer readlen
character*(linelen) inline
character*(clen) cdat(datlen)
logical continued, broken
character esc
parameter (esc='\\')
integer line_end
character*(linelen) workline
character*1 char, tmp_char
logical cont_string, escaped
integer j
logical iswhitespace
broken=.false.
continued=.false.
cont_string=.false.
escaped=.false.
! create working copy of line
workline=' '
workline=inline(line_start:len_trim(inline))
line_end=len_trim(workline)
! If needed, initialize working position in cdat
if (strpos.eq.0) then
cdat(cpos)=' '
endif
! iterate over characters in line
do j=1,line_end
char=workline(j:j)
if (escaped) then
! Insert escaped character and proceed.
escaped=.false.
! Special escape sequences
if (char.eq.'.') then
! \. = !
char='!'
endif
else if (char.eq.esc) then
! Consider next character escaped, skip char.
escaped=.true.
cycle
else if (char.eq.'&') then
continued=.true.
if (j.eq.line_end) then
exit
endif
! Deal with unusual continuations, look at char after "&"
char=workline(j+1:j+1)
if (char.eq.'&') then
! "&&" allows multi-line strings
cont_string=.true.
if (j+1.eq.line_end) then
exit
endif
endif
write(6,'(A)') 'WARNING: LONG_STRLINE: IGNORED'
> // ' JUNK CHARACTER(S) FOLLOWING'
> // ' CONTINUATION CHARACTER.'
exit
else if (iswhitespace(char)) then
! Whitespace separates strings; skip char.
if (strpos.gt.0) then
! Begin a new string unless the current one is empty.
strpos=0
cpos=cpos+1
cdat(cpos)=' '
endif
cycle
else
! assume char to be meant as a downcase char
call downcase(char,tmp_char,1)
char=tmp_char
endif
! Incorporate new char into string
strpos=strpos+1
! Break if a boundary exception occurs
if (cpos.gt.datlen) then
write(6,'(A)') 'ERROR: LONG_STRLINE: PARSER OUT OF MEMORY'
> // ' ON READ'
write(6,'(A)') 'CURRENT LINE:'
write(6,'(A)') trim(inline)
broken=.true.
return
else if (strpos.gt.clen) then
write(6,'(A)') 'ERROR: LONG_STRLINE: PARSER OUT OF MEMORY'
> // ' ON READ: STRING ARGUMENT EXCEEDS CLEN'
write(6,'(A)') 'CURRENT LINE:'
write(6,'(A)') trim(inline)
broken=.true.
return
endif
! insert character
cdat(cpos)(strpos:strpos)=char
if (strpos.eq.1) then
readlen=readlen+1
endif
enddo
! Fix incomplete escape sequences and deal with continuation
if (escaped) then
write(6,'(A)') 'WARNING: LONG_STRLINE: ENCOUNTERED ESCAPE'
> // ' CHARACTER AT EOL. IGNORED.'
endif
! Unless the line ended with "&&", consider the current, non-empty
! string complete.
if ((cont_string).or.(strpos.eq.0)) then
return
else
cpos=cpos+1
strpos=0
endif
end

432
src/mkNN.f Normal file
View File

@ -0,0 +1,432 @@
subroutine mknet(laystr,weistr,neupop,nlay)
implicit none
! Initialize layer structure matrix exclusively.
!
! nlay: number of given layers
! neupop: neuronal population vector: contains number of neurons for each layer
! laystr: layer structure matrix
! weistr: weight structure matrix
include 'nnparams.incl'
include 'nndbg.incl'
integer laystr(3,maxlay),weistr(2,maxlay,2), neupop(maxlay)
integer nlay
integer neu_tot,wei_tot
integer n
if (dbg) write(6,'(A)') '#INITIALIZING NN....'
neu_tot=0 !number of reserved neurons spaces in memory so far
wei_tot=0 !number of reserved weight matrix element spaces in mem. so far
do n=1,nlay-1
laystr(1,n)=neupop(n) !number of neurons in layer n
laystr(2,n)=neu_tot+1 !starting pos. for layer n
laystr(3,n)=wei_tot+1 !starting pos. for W-matrix
!from layer N to N+1
neu_tot=neu_tot+neupop(n)
wei_tot=wei_tot+neupop(n)*neupop(n+1)
enddo
laystr(1,nlay)=neupop(nlay)
laystr(2,nlay)=neu_tot+1
laystr(3,nlay)=wei_tot+1 !technically oversteps boundary
!of W-vector; practically points to first bias
if (dbg) write(6,'(A)') '#PERFORMING SANITY CHECKS..'
weistr=0
! since there are no input biases, the first entry just points at
! the last few weight matrix elements
weistr(1,1,2)=wei_tot-neupop(1)+1
weistr(2,1,2)=wei_tot
do n=1,nlay-1
weistr(1,n,1)=laystr(3,n)
weistr(2,n,1)=laystr(3,n+1)-1 !end pos. of corresponding W-matrix
weistr(1,n+1,2)=weistr(2,n,2)+1 !starting pos. of bias
weistr(2,n+1,2)=weistr(2,n,2)+neupop(n+1) !end pos. of bias
enddo
if (dbg.or.vbs) write(6,*) '#PERFORMING SANITY CHECKS..'
if (neupop(1).gt.maxnin) then
write(6,'("ERROR: NETWORK INPUT EXCEEDS MAXIMUM.")')
write(6,'(I3.3,"/",I3.3)') neupop(1),maxnin
stop 1
else if (neupop(nlay).gt.maxnout) then
write(6,'("ERROR: NETWORK OUTPUT EXCEEDS MAXIMUM.")')
write(6,'(I3.3,"/",I3.3)') neupop(nlay),maxnout
stop 1
else if (nlay.gt.maxlay) then
write(6,'("ERROR: LAYER COUNT EXCEED MAXIMUM.")')
write(6,'(I2.2,"/",I2.2)') nlay,maxlay
stop 1
endif
do n=2,nlay-1
if (neupop(1).gt.maxnin) then
write(6,'("ERROR: HIDDEN LAYER SIZE EXCEEDS MAXIMUM.")')
write(6,'(I3.3,"/",I3.3)') neupop(n),maxneu
write(6,'("PROBLEM OCCURED IN LAYER #",I2.2)') n
stop 1
endif
enddo
if (dbg) then
write(6,*) '#INIT SUCCESSFUL.'
write(6,'(A10,I6)') '#NEU_TOT =',neu_tot
write(6,'(A10,I6)') '#WEI_TOT =',wei_tot
write(6,'(A10,I6)') '#MAXWEI = ',maxwei
endif
end
!--------------------------------------------------------------------------------------
subroutine mkpars(par,spread,laystr,typop,weistr,nlay,rtype)
implicit none
! Initialize Weights and Biases exclusively.
!
!
! par: one parameter vector
! spread: factor by which each weight or bias spreads around 0
! nlay: number of given layers
! rtype: type of random distribution:
! 0 -- even distribution
! 1 -- angular uniform distribution,
! vectors normalized to sqrt(wb_end)
! 2 -- even normalized distribution:
! std. deviation of weighted sums is 1.
! Ignores act.
! 3 -- same as 2, but more exact for 2+ hidden layer
! networks
!
! Initialization of the random numbers must have been done before
! call vranf(par(1:1),0,seed,iout) is used for the initialization
include 'nnparams.incl'
include 'params.incl'
include 'common.incl'
include 'nndbg.incl'
double precision par(wbcap),spread(wbcap)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer rtype,nlay
integer wb_end
integer k
! evalute length of entire weight- and bias-vector together
wb_end=weistr(2,nlay,2)
if (rtype.eq.0) then
! generate random numbers within [0,1)
call vranf(par,wb_end,0,iout)
! shift range accordingly
do k=1,wb_end
par(k)=(par(k)-0.5D0)*2.0D0*spread(k)
enddo
else if (rtype.eq.1) then
! generate random numbers
call nnorm_grv(par,wb_end,1)
! shift range accordingly
do k=1,wb_end
par(k)=par(k)*2.0D0*spread(k)
enddo
else if (rtype.eq.2) then
! generate random numbers within [0,1)
call vranf(par,wb_end,0,iout)
! shift range to [-1,1)
do k=1,wb_end
par(k)=(par(k)-0.5D0)*2.0D0
enddo
call normalize_wbvec(par,laystr,weistr,nlay)
else if (rtype.eq.3) then
! generate random numbers within [0,1)
call vranf(par,wb_end,0,iout)
! shift range to [-1,1)
do k=1,wb_end
par(k)=(par(k)-0.5D0)*2.0D0
enddo
call normalize_wbvec_nonlin(par,laystr,weistr,typop,nlay)
par=par*spread
else
stop 'ERROR: INVALID TYPE OF RANDOM NUMBER GENERATION (RTYPE)'
endif
end
!--------------------------------------------------------------------------------------
subroutine normalize_wbvec_nonlin(par,laystr,weistr,typop,nlay)
implicit none
! Normalizes weights and biases in such a way that the standard
! deviation of a layer's weighted sums is 1, assuming par has been
! initialized with evenly distributed values from -1 to 1.
!
! For ANNs with 1 hidden layer, this routine is exact. For
! multilayered ANNs, this routine approximates distortions from ANN
! activation functions linearly. The "radius" of the even
! distribution is given for a layer k by:
!
! sqrt(3)/sqrt(1+N_eff(k-1)),
!
! where N_eff(k-1) is the effective number of neurons of the
! previous layer. It is given by the sum over all squared
! activation function derivatives at 0 of the previous layer.
! Hence, for f(x)=x for all neurons in a given layer N_eff is the
! actual number of neurons in that layer.
!
include 'nnparams.incl'
include 'params.incl'
include 'nncommon.incl'
include 'common.incl'
include 'nndbg.incl'
double precision par(wbcap)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
double precision L(maxneu),deriv(maxneu),wbfact(maxlay)
double precision effnum
integer neu_out
integer j,n
! input layer has a trivial activation by def.
wbfact(1)=dsqrt(3.0d0)/dsqrt(dble(laystr(1,1)+1))
do n=2,nlay
L=0
deriv=0
neu_out=laystr(1,n)
! sum over squared derivatives
call neurons(neu_out,L,deriv,typop(1,n))
effnum=0.0d0
do j=1,neu_out
effnum=effnum+deriv(j)**2
enddo
wbfact(n)=dsqrt(3.0d0)/dsqrt(effnum+1.0d0)
enddo
do n=1,nlay-1
do j=weistr(1,n,1),weistr(2,n,1)
par(j)=par(j)*wbfact(n)
enddo
enddo
do n=2,nlay
do j=weistr(1,n,2),weistr(2,n,2)
par(j)=par(j)*wbfact(n-1)
enddo
enddo
end
!--------------------------------------------------------------------------------------
subroutine normalize_wbvec(par,laystr,weistr,nlay)
implicit none
! Normalizes weights and biases in such a way that the standard
! deviation of a layer's weighted sums is 1, assuming par has been
! initialized with evenly distributed values from -1 to 1.
!
! For ANNs with 1 hidden layer, this routine is exact. For
! multilayered ANNs, this routine neglects distortion effects of the
! activation functions.
include 'nnparams.incl'
include 'params.incl'
include 'nncommon.incl'
include 'common.incl'
include 'nndbg.incl'
double precision par(wbcap)
integer laystr(3,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer j,n
do n=1,nlay-1
do j=weistr(1,n,1),weistr(2,n,1)
par(j)=par(j)*dsqrt(3.0d0)/dsqrt(dble(laystr(1,n)+1))
enddo
enddo
do n=2,nlay
do j=weistr(1,n,2),weistr(2,n,2)
par(j)=par(j)*dsqrt(3.0d0)
> /dsqrt(dble(laystr(1,n-1)+1))
enddo
enddo
end
!--------------------------------------------------------------------------------------
subroutine mkmodpars(par,act,spread,nlay,thresh)
implicit none
! Assume weights and biases to be mostly initialized and only change
! those that have values that which have an absolute value less than
! thresh. Inactive weights and biases remain untouched.
!
!
! par: one parameter vector
! spread: factor by which each weight or bias spreads around 0
! act: activities for the parameter vector par. Inactive
! parameters remain untouched
! nlay: number of given layers
! thresh: minimum absolute value for a parameter to be
! overwritten. If negative, default to 0.0d0.
! Initialization of the random numbers must have been done before
! call vranf(par(1:1),0,seed,iout) is used for the initialization
include 'nnparams.incl'
include 'params.incl'
include 'common.incl'
include 'nndbg.incl'
double precision par(wbcap),spread(wbcap),thresh
integer act(wbcap)
integer nlay
double precision ranval(2)
double precision minval
integer wb_end
integer k
if (thresh.le.0.0d0) then
minval=0.0d0
else
minval=thresh
endif
! evalute length of entire weight- and bias-vector together
wb_end=pst(1,2*(nlay-1))+pst(2,2*(nlay-1))-1
do k=1,wb_end
! check whether par(k) needs changing.
if ((act(k).ne.0).and.(dabs(par(k)).le.minval)) then
! generate random number within [0,1)
call vranf(ranval,1,0,iout)
! shift range accordingly
par(k)=(ranval(1)-0.5D0)*2.0D0*spread(k)
endif
enddo
end
!--------------------------------------------------------------------------------------
subroutine mkrefset_tail(pat_in,pat_out,ref_in,ref_out,npat,nref)
implicit none
! Split off the nref last pattern pairs and make them reference data.
!
! npat: number of given pattern pairs. Will be reduced by nref.
! nref: number of reference patterns
!
! pat_in: input patterns
! pat_out: desired output patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
!
! ref_*: in analogy to pat_in/out for reference data (convergence tests)
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision pat_in(maxnin,maxpats),pat_out(maxpout,maxpats)
double precision ref_in(maxnin,maxpats),ref_out(maxpout,maxpats)
integer npat,nref
integer j,k
if (nref.ge.npat) then
write(6,*) 'ERROR: MKREFSET: NREF TOO LARGE FOR GIVEN NPAT'
stop 1
else if (nref.lt.0) then
write(6,*) 'ERROR: MKREFSET: NEGATIVE NREF'
stop 1
endif
! update npat
npat=npat-nref
! Copy tail to ref-vectors
do j=1,nref
do k=1,maxnin
ref_in(k,j)=pat_in(k,npat+j)
enddo
do k=1,maxpout
ref_out(k,j)=pat_out(k,npat+j)
enddo
enddo
end
!--------------------------------------------------------------------------------------
subroutine mkweights(wterr,npat,pat_out)
implicit none
! Rescale weights depending on their kind (energy or state
! composition) based on a simplified form of the hybrid
! diabatisation weighting scheme. System specific rescaling is done
! by calling nnweights() for each pattern weight vector.
!
! npat: number of given pattern pairs
! wterr: weight factors for each element of the error vector e
!
! vecnum: number of state vectors in model
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
integer npat
double precision wterr(maxpout,npat),pat_out(maxpout,npat)
character*32 fname
integer j,k,n,total
fname = trim(nnfdir) // 'weights.out'
write(6,stdfmt) 'Applying weighting scheme..'
open(nnunit,file=trim(fname),status='replace')
write(nnunit,stdfmt) '# This is the established weighting scheme'
> // ' for the present fit.'
write(nnunit,stdfmt) '# Weights appear in the order given by the'
> // 'original input.'
write(nnunit,stdfmt) '# Weights given here are *not* normalized.'
write(nnunit,newline)
do k=1,npat
call nnweight(wterr(1,k),pat_out(1,k))
enddo
total=0
do k=1,sets
write(nnunit,'(A10,I6.5)') '# Scan Nr.',k
do j=1,ndata(k)
total=total+1
do n=1,inp_out
write(nnunit,'(ES25.15)',advance='NO')
> wterr(n,total)
enddo
write(nnunit,newline)
enddo
enddo
close(nnunit)
write(6,'(A)') 'Error weight generation successful.'
write(6,'(A)') 'Wrote (not normalized) weights to '''
> // trim(fname) // '''.'
end

View File

@ -0,0 +1 @@
../../../../Genetic/NO3/Dipole_NO3/Fit_stretch_Latest/fit_genric_bend_no3.f90

View File

@ -0,0 +1,82 @@
Module invariants_mod
implicit none
contains
!----------------------------------------------------
subroutine invariants(a,xs,ys,xb,yb,b,inv)
implicit none
!include "nnparams.incl"
double precision, intent(in) :: a, xs, ys, xb, yb, b
double precision, intent(out) :: inv(3)
double precision:: invar(24)
complex(8) :: q1, q2
LOGICAL,PARAMETER:: debg =.FALSE.
integer :: i
! express the coordinate in complex
q1 = dcmplx(xs, ys)
q2 = dcmplx(xb, yb)
! compute the invariants
invar(24) = a
invar(23) =b**2
! INVARIANTS OF KIND II
!------------------------
invar(1) = dreal( q1 * conjg(q1) ) ! r11
invar(2) = dreal( q1 * conjg(q2) ) ! r12
invar(3) = dreal( q2 * conjg(q2) ) ! r22
invar(4) = (dimag(q1 * conjg(q2)) )**2 ! rho 12**2
!INVATIANTS OF KIND III
!------------------------
invar(5) = dreal( q1 * q1 * q1 ) ! r111
invar(6) = dreal( q1 * q1 * q2 ) ! r112
invar(7) = dreal( q1 * q2 * q2 ) ! r122
invar(8) = dreal( q2 * q2 * q2 ) ! r222
invar(9) = (dimag( q1 * q1 * q1 ))**2 ! rho111**2
invar(10) = (dimag( q1 * q1 * q2 ))**2 ! rho112 **2
invar(11) = (dimag( q1 * q2 * q2 ))**2 ! rho122**2
invar(12) = (dimag( q2 * q2 * q2 ))**2 ! rho222
! INVARIANTS OF KIND IV
!-------------------------
invar(13) = (dimag( q1 * conjg(q2)) * dimag( q1 * q1 * q1 ))
invar(14) = (dimag( q1 * conjg(q2)) * dimag( q1 * q1 * q2 ))
invar(15) = (dimag( q1 * conjg(q2)) * dimag( q1 * q2 * q2 ))
invar(16) = (dimag( q1 * conjg(q2)) * dimag( q2 * q2 * q2 ))
! INVARIANTS OF KIND V
!----------------------
invar(17) = (dimag( q1 * q1 * q1 ) * dimag( q1 * q1 * q2 ))
invar(18) = (dimag( q1 * q1 * q1 ) * dimag( q1 * q2 * q2 ))
invar(19) = (dimag( q1 * q1 * q1 ) * dimag( q2 * q2 * q2 ))
invar(20) = (dimag( q1 * q1 * q2 ) * dimag( q1 * q2 * q2 ))
invar(21) = (dimag( q1 * q1 * q2 ) * dimag( q2 * q2 * q2 ))
invar(22) = (dimag( q1 * q2 * q2 ) * dimag( q2 * q2 * q2 ))
! the only non zero invariant for bend pure cuts
inv(1) = invar(3)
inv(2) = invar(8)
inv(3) = invar(12)
if (debg) then
write(*,"(A,*(f10.5))")"Invar II", (invar(i),i=1,4)
write(*,"(A,*(f10.5))") "Invar III", (invar(i),i=5,12)
write(*,"(A,*(f10.5))")"Invar IV", (invar(i),i=13,16)
write(*,"(A,*(f10.5))")"Invar V", (invar(i),i=17,22)
write(*,*)"THE INPUT COORDINATE IN COMPLEX REPRES"
write(*,*)"---------------------------------------"
write(*,*)"xs =",dreal(q1), "ys=",dimag(q1)
endif
! modify the invariants to only consider few of them
!
!invar(13:22)=0.0d0
end subroutine invariants
end module invariants_mod

469
src/model/model_no3.f90 Normal file
View File

@ -0,0 +1,469 @@
module diabmodel
!use dim_parameter,only:qn,ndiab,pst
use iso_fortran_env, only: idp => int32, dp => real64
!use accuracy_constants, only:dp,idp
use dip_param, only: init_dip_planar_data, p,pst,np
implicit none
include "nnparams.incl"
integer(idp),parameter:: ndiab=5
logical :: debug=.false.
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
subroutine diab_x(q,e,nn_out)
real(dp),intent(in)::q(maxnin)
real(dp),intent(out)::e(ndiab,ndiab)
real(dp),intent(inout):: nn_out(maxnout)
integer(idp) id,i,j, ii, non_zer_p
real(dp) xs,xb,ys,yb,a,b,ss,sb,v3(8),v2(6)
xs=q(5)
ys=q(6)
xb=q(7)
yb=q(8)
a=q(4)
b=q(9)
call init_dip_planar_data()
non_zer_p = count(p /= 0.0d0)
ii=1
do i=1,np-2
if (p(i) .ne. 0) then
p(i) =p(i)*(1.0_dp + 1.0d-2 + nn_out(ii))
ii=ii+1
else
p(i)=p(i)
endif
enddo
ss=xs**2+ys**2 ! totaly symmetric term
sb=xb**2+yb**2
v2(1)=xs**2-ys**2
v2(2)=xb**2-yb**2
v2(3)=xs*xb-ys*yb
v2(4)=2*xs*ys
v2(5)=2*xb*yb
v2(6)=xs*yb+xb*ys
v3( 1) = xs*(xs**2-3*ys**2)
v3( 2) = xb*(xb**2-3*yb**2)
v3( 3) = xb*(xs**2-ys**2) - 2*yb*xs*ys
v3( 4) = xs*(xb**2-yb**2) - 2*ys*xb*yb
v3( 5) = ys*(3*xs**2-ys**2)
v3( 6) = yb*(3*xb**2-yb**2)
v3( 7) = yb*(xs**2-ys**2)+2*xb*xs*ys
v3( 8) = ys*(xb**2-yb**2)+2*xs*xb*yb
e=0.0d0
id=1 ! 1
e(1,1)=e(1,1)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb ! 2 param
id=id+1 ! 2
e(2,2)=e(2,2)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb ! 2 p
e(3,3)=e(3,3)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb
id =id+1 ! 3
e(4,4)=e(4,4)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb ! 2 p
e(5,5)=e(5,5)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb
id=id+1 ! 4
! order 2
e(1,1)=e(1,1)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) & ! 5 p
+p(pst(1,id)+2)*(xs*xb-ys*yb)
id =id+1 ! 5
e(2,2)=e(2,2)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb)
e(3,3)=e(3,3)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb)
id =id+1 ! 6
e(4,4)=e(4,4)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb)
e(5,5)=e(5,5)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb)
! order 3
id=id+1 ! 7
e(1,1)=e(1,1)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb *sb ! 2 param
id=id+1 ! 8
e(2,2)=e(2,2)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb *sb ! 2 p
e(3,3)=e(3,3)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb*sb
id =id+1 ! 9
e(4,4)=e(4,4)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb*sb ! 2 p
e(5,5)=e(5,5)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb*sb
! W and Z term of E1
! order 0
id=id+1 ! 10
e(2,2)=e(2,2)+p(pst(1,id))
e(3,3)=e(3,3)-p(pst(1,id))
!e(2,3)=e(2,3)
! order 1
id=id+1 ! 11 ! 2 param
e(2,2)=e(2,2)+ p(pst(1,id))*xs+p(pst(1,id)+1)*xb
e(3,3)=e(3,3)- (p(pst(1,id))*xs+p(pst(1,id)+1)*xb)
e(2,3)=e(2,3)- p(pst(1,id))*ys -p(pst(1,id)+1)*yb
! order 2
id=id+1 ! 12 ! 3p
do i=1,3
e(2,2)=e(2,2)+p(pst(1,id)+(i-1))*v2(i)
e(3,3)=e(3,3)-p(pst(1,id)+(i-1))*v2(i)
e(2,3)=e(2,3)+ p(pst(1,id)+(i-1))*v2(i+3)
enddo
! order 3
id=id+1 ! 13 ! 8 param
do i=1,4
e(2,2)=e(2,2)+(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i)
e(3,3)=e(3,3)-(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i)
e(2,3)=e(2,3)+(-p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i+4)
enddo
! try the testing of higher order terms
!e(2,3)=e(2,3)- p(pst(1,id))*ys*ss +p(pst(1,id)+1)*ss*2*xs*ys
! W and Z for E2
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
id=id+1 ! 14
e(4,4)=e(4,4)+p(pst(1,id))
e(5,5)=e(5,5)-p(pst(1,id))
e(4,5)=e(4,5)
! order 1
id=id+1 ! 2 param 15
e(4,4)=e(4,4)+ p(pst(1,id))*xs+p(pst(1,id)+1)*xb
e(5,5)=e(5,5)- (p(pst(1,id))*xs+p(pst(1,id)+1)*xb)
e(4,5)=e(4,5)- p(pst(1,id))*ys-p(pst(1,id)+1)*yb
! order 2
id=id+1 ! 16 ! 3p
do i=1,3
e(4,4)=e(4,4)+p(pst(1,id)+(i-1))*v2(i)
e(5,5)=e(5,5)-p(pst(1,id)+(i-1))*v2(i)
e(4,5)=e(4,5)+ p(pst(1,id)+(i-1))*v2(i+3)
enddo
! order 3
id=id+1 ! 17 ! 8 param
do i=1,4
e(4,4)=e(4,4)+(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i)
e(5,5)=e(5,5)-(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i)
e(4,5)=e(4,5)+(-p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i+4)
enddo
!e(4,4) = e(4,4)+ p(pst(1,id))*xs*ss + p(pst(1,id)+1)*xb*sb
!e(5,5)=e(5,5)- (p(pst(1,id))*xs*ss + p(pst(1,id)+1)*xb*sb)
!e(4,5)=e(4,5)- p(pst(1,id))*ys*ss -p(pst(1,id)+1)*yb*sb
! E1 X E2
! WW and ZZ
id =id+1 ! 18
e(2,4)=e(2,4)+p(pst(1,id))*b
e(3,5)=e(3,5)-p(pst(1,id))*b
! ORDER 1
id=id+1 ! 19 ! 6 parama
e(2,4)=e(2,4)+b*((p(pst(1,id))+p(pst(1,id)+1)+p(pst(1,id)+2))*xs+(p(pst(1,id)+3)+p(pst(1,id)+4)+p(pst(1,id)+5))*xb)
e(3,5)=e(3,5)+b*((p(pst(1,id))+p(pst(1,id)+1)-p(pst(1,id)+2))*xs+(p(pst(1,id)+3)+p(pst(1,id)+4)-p(pst(1,id)+5))*xb)
e(2,5)=e(2,5)+b*((p(pst(1,id))-p(pst(1,id)+1)-p(pst(1,id)+2))*ys+(p(pst(1,id)+3)-p(pst(1,id)+4)-p(pst(1,id)+5))*yb)
e(3,4)=e(3,4)+b*((-p(pst(1,id))+p(pst(1,id)+1)-p(pst(1,id)+2))*ys+(-p(pst(1,id)+3)+p(pst(1,id)+4)-p(pst(1,id)+5))*yb)
! order 2
id=id+1 ! 20
do i=1,3 ! 9 param
e(2,4)=e(2,4)+b*(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+2))+p(pst(1,id)+(i+5)))*v2(i)
e(3,5)=e(3,5)+b*(-p(pst(1,id)+(i-1))+p(pst(1,id)+(i+2))+p(pst(1,id)+(i+5)))*v2(i)
e(2,5)=e(2,5)+b*(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+2))-p(pst(1,id)+(i+5)))*v2(i+3)
e(3,4)=e(3,4)+b*(p(pst(1,id)+(i-1))-p(pst(1,id)+(i+2))+p(pst(1,id)+(i+5)))*v2(i+3)
enddo
! pseudo A2 & E1
! ##################################################
!###################################################
! order 0
id=id+1 ! 1 param ! 21
e(1,3)=e(1,3)+b*(p(pst(1,id)))
! order 1
id = id +1 ! 22
e(1,2)=e(1,2)-b*(p(pst(1,id))*ys + p(pst(1,id)+1)*yb)
e(1,3)=e(1,3)+b*(p(pst(1,id))*xs + p(pst(1,id)+1)*xb)
! order 2
id=id+1 ! 23
e(1,2)=e(1,2)+b*(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+p(pst(1,id)+2)*(xs*yb+xb*ys))
e(1,3)=e(1,3)+b*(p(pst(1,id))*(xs**2-ys**2) + p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb))
! COUPLING OF A2 WITH E2
!##########################################################################################################
! order 0
id =id+1 !24
e(1,5)=e(1,5)+p(pst(1,id))
! order 1
id = id +1 ! 25
e(1,4)=e(1,4)-(p(pst(1,id))*ys + p(pst(1,id)+1)*yb)
e(1,5)=e(1,5)+(p(pst(1,id))*xs + p(pst(1,id)+1)*xb)
! order 2
id=id+1 ! 26
e(1,4)=e(1,4)+p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+p(pst(1,id)+2)*(xs*yb+xb*ys)
e(1,5)=e(1,5)+p(pst(1,id))*(xs**2-ys**2) + p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb)
! order 3
id=id+1 ! 27 ! 8 param
do i=1,4
e(1,4)=e(1,4)+(p(pst(1,id)+(i-1))-p(pst(1,id)+(i+3)))*v3(i+4)
e(1,5)=e(1,5)+(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i)
enddo
call copy_2_lower_triangle(e)
!temp = e(2,2)
!e(2,2)=e(3,3)
!e(3,3)=temp
if (debug) then
do i=1,ndiab
write(34,'(5f14.6)') (e(i,j),j=1,ndiab)
enddo
write(34,*)""
endif
end subroutine diab_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! THE Y COMPONENT OF DIPOLE
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
subroutine diab_y(q,e,nn_out)
real(dp),intent(in)::q(maxnin)
real(dp),intent(out)::e(ndiab,ndiab)
real(dp),intent(inout):: nn_out(maxnout)
integer(idp) id,i,j, ii, non_zer_p
real(dp) xs,xb,ys,yb,a,b,ss,sb,v3(8),v2(6)
xs=q(5)
ys=q(6)
xb=q(7)
yb=q(8)
a=q(4)
b=q(9)
call init_dip_planar_data()
non_zer_p = count(p /= 0.0d0)
ii=1
do i=1,np-2
if (p(i) .ne. 0) then
p(i) =p(i)*(1.0_dp + 1.0d-2 + nn_out(ii))
ii=ii+1
else
p(i)=p(i)
endif
enddo
ss=xs**2+ys**2 ! totaly symmetric term
sb=xb**2+yb**2
v2(1)=xs**2-ys**2
v2(2)=xb**2-yb**2
v2(3)=xs*xb-ys*yb
v2(4)=2*xs*ys
v2(5)=2*xb*yb
v2(6)=xs*yb+xb*ys
v3( 1) = xs*(xs**2-3*ys**2)
v3( 2) = xb*(xb**2-3*yb**2)
v3( 3) = xb*(xs**2-ys**2) - 2*yb*xs*ys
v3( 4) = xs*(xb**2-yb**2) - 2*ys*xb*yb
v3( 5) = ys*(3*xs**2-ys**2)
v3( 6) = yb*(3*xb**2-yb**2)
v3( 7) = yb*(xs**2-ys**2)+2*xb*xs*ys
v3( 8) = ys*(xb**2-yb**2)+2*xs*xb*yb
e=0.0d0
! V-term
id=1 ! 1
! order 1
e(1,1)=e(1,1)+p(pst(1,id))*ys + p(pst(1,id)+1)*yb
id=id+1 ! 2
e(2,2)=e(2,2)+p(pst(1,id))*ys + p(pst(1,id)+1)*yb
e(3,3)=e(3,3)+p(pst(1,id))*ys + p(pst(1,id)+1)*yb
id =id+1 ! 3
e(4,4)=e(4,4)+p(pst(1,id))*ys + p(pst(1,id)+1)*yb
e(5,5)=e(5,5)+p(pst(1,id))*ys + p(pst(1,id)+1)*yb
id=id+1 ! 4b*(
e(1,1)=e(1,1)-(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+p(pst(1,id)+2)*(xs*yb+xb*ys))
id =id+1 ! 5
e(2,2)=e(2,2)-(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+p(pst(1,id)+2)*(xs*yb+xb*ys))
e(3,3)=e(3,3)-(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+p(pst(1,id)+2)*(xs*yb+xb*ys))
id=id+1 ! 6
e(4,4)=e(4,4)-(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+p(pst(1,id)+2)*(xs*yb+xb*ys))
e(5,5)=e(5,5)-(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+p(pst(1,id)+2)*(xs*yb+xb*ys))
! order 3
id=id+1 ! 7
e(1,1)=e(1,1)+p(pst(1,id))*ys*ss + p(pst(1,id)+1)*yb*sb
id=id+1 ! 2
e(2,2)=e(2,2)+p(pst(1,id))*ys*ss + p(pst(1,id)+1)*yb*sb
e(3,3)=e(3,3)+p(pst(1,id))*ys*ss + p(pst(1,id)+1)*yb*sb
id =id+1 ! 3
e(4,4)=e(4,4)+p(pst(1,id))*ys*ss + p(pst(1,id)+1)*yb*sb
e(5,5)=e(5,5)+p(pst(1,id))*ys*ss + p(pst(1,id)+1)*yb*sb
! W and Z of E1
! order 0
id=id+1 ! 10
e(2,3)=e(2,3)+p(pst(1,id))
! order 1
id=id+1 !
e(2,2)=e(2,2)-p(pst(1,id))*ys -p(pst(1,id)+1)*yb
e(3,3)=e(3,3)+p(pst(1,id))*ys+ p(pst(1,id)+1)*yb
e(2,3)=e(2,3)-p(pst(1,id))*xs -p(pst(1,id)+1)*xb
! order 2
id=id+1 ! 12
do i=1,3
e(2,2)=e(2,2)+p(pst(1,id)+(i-1))*v2(i+3)
e(3,3)=e(3,3)-p(pst(1,id)+(i-1))*v2(i+3)
e(2,3)=e(2,3)-p(pst(1,id)+(i-1))*v2(i)
enddo
id=id+1 ! 8
do i=1,4
e(2,2)=e(2,2)+(p(pst(1,id)+(i-1))-p(pst(1,id)+(i+3)))*v3(i+4)
e(3,3)=e(3,3)-(p(pst(1,id)+(i-1))-p(pst(1,id)+(i+3)))*v3(i+4)
e(2,3)=e(2,3)+(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i)
enddo
!! W and Z of E2
!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! order 0
id=id+1 ! 14
e(4,5)=e(4,5)+p(pst(1,id))
! order 1
id=id+1 ! 15
e(4,4)=e(4,4)-p(pst(1,id))*ys -p(pst(1,id)+1)*yb
e(5,5)=e(5,5)+p(pst(1,id))*ys+ p(pst(1,id)+1)*yb
e(4,5)=e(4,5)-p(pst(1,id))*xs -p(pst(1,id)+1)*xb
! order 2
id=id+1 ! 16
do i=1,3
e(4,4)=e(4,4)+p(pst(1,id)+(i-1))*v2(i+3)
e(5,5)=e(5,5)-p(pst(1,id)+(i-1))*v2(i+3)
e(4,5)=e(4,5)-p(pst(1,id)+(i-1))*v2(i)
enddo
id=id+1 ! 17
do i=1,4
e(4,4)=e(4,4)+(p(pst(1,id)+(i-1))-p(pst(1,id)+(i+3)))*v3(i+4)
e(5,5)=e(5,5)-(p(pst(1,id)+(i-1))-p(pst(1,id)+(i+3)))*v3(i+4)
e(4,5)=e(4,5)+(p(pst(1,id)+(i-1))+p(pst(1,id)+(i+3)))*v3(i)
enddo
! PSEUDO JAHN-TELLER E1 AND E2
!ORDER 0
id=id+1 ! 18
e(2,5)=e(2,5)+p(pst(1,id))*b
e(3,4)=e(3,4)+p(pst(1,id))*b
! order 1
id=id+1
e(2,4)=e(2,4)+b*((p(pst(1,id))+p(pst(1,id)+1)-p(pst(1,id)+2))*ys+(p(pst(1,id)+3)+p(pst(1,id)+4)-p(pst(1,id)+5))*yb)
e(3,5)=e(3,5)+b*((p(pst(1,id))+p(pst(1,id)+1)+p(pst(1,id)+2))*ys+(p(pst(1,id)+3)+p(pst(1,id)+4)+p(pst(1,id)+5))*yb)
e(2,5)=e(2,5)+b*((-p(pst(1,id))+p(pst(1,id)+1)-p(pst(1,id)+2))*xs+(-p(pst(1,id)+3)+p(pst(1,id)+4)-p(pst(1,id)+5))*xb)
e(3,4)=e(3,4)+b*((p(pst(1,id))-p(pst(1,id)+1)-p(pst(1,id)+2))*xs+(+p(pst(1,id)+3)-p(pst(1,id)+4)-p(pst(1,id)+5))*xb)
! order 2
id=id+1
e(2,4)=e(2,4)+(p(pst(1,id)+(i-1))-p(pst(1,id)+(i+2))-p(pst(1,id)+(i+5)))*v2(i+3)*b
e(3,5)=e(3,5)+(-p(pst(1,id)+(i-1))-p(pst(1,id)+(i+2))-p(pst(1,id)+(i+5)))*v2(i+3)*b
e(2,5)=e(2,5)+(-p(pst(1,id)+(i-1))+p(pst(1,id)+(i+2))-p(pst(1,id)+(i+5)))*v2(i)*b
e(3,4)=e(3,4)+(-p(pst(1,id)+(i-1))-p(pst(1,id)+(i+2))+p(pst(1,id)+(i+5)))*v2(i)*b
! no order 3
!!!!!!!!!!!!!!!!
! the coupling A2 & E1
! #####################
! order 0
id=id+1
e(1,2)=e(1,2)+b*(p(pst(1,id)))
! order 1
id=id+1
e(1,2)=e(1,2)-b*(p(pst(1,id))*xs + p(pst(1,id)+1)*xb)
e(1,3)=e(1,3)-b*(p(pst(1,id))*ys + p(pst(1,id)+1)*yb)
! order 2
id=id+1
e(1,2)=e(1,2)-b*(p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb))
e(1,3)=e(1,3)+b*(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+ &
+p(pst(1,id)+2)*(xs*yb+xb*ys))
! COUPLING OF A2 WITH E2
!#######################################################################################
!###############################################################################
! order 0
id = id+1
e(1,4)=e(1,4)+p(pst(1,id))
! order 1
id=id+1
e(1,4)=e(1,4)-(p(pst(1,id))*xs + p(pst(1,id)+1)*xb)
e(1,5)=e(1,5)-(p(pst(1,id))*ys + p(pst(1,id)+1)*yb)
! order 2
id=id+1
e(1,4)=e(1,4)-(p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb))
e(1,5)=e(1,5)+(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)+ &
p(pst(1,id)+2)*(xs*yb+xb*ys))
!write(*,*)'idy=',id
call copy_2_lower_triangle(e)
if (debug) then
do i=1,ndiab
write(*,'(5f14.6)') (e(i,j),j=1,ndiab)
enddo
write(*,*)""
endif
end subroutine diab_y
subroutine copy_2_lower_triangle(mat)
real(dp), intent(inout) :: mat(:, :)
integer :: m, n
! write lower triangle of matrix symmetrical
do n=1,size(mat,1)
do m=n,size(mat,1)
mat(m,n)=mat(n,m)
enddo
enddo
end subroutine copy_2_lower_triangle
end module diabmodel

63
src/model/nnadia_no3.f Normal file
View File

@ -0,0 +1,63 @@
subroutine nninit_mod()
implicit none
include 'nnparams.incl'
end subroutine
subroutine nnadia(coords,coeffs,adiaoutp)
USE diabmodel, only: diab_x
implicit none
! returns THE DIABATIC MATRIX UPPER MATRIX OF BOTH X AND Y COMPONENT OF DIPOLE
!
! coords: vector containing symmetry-adapted coordinates.
! coeffs: vector containing coeffs of diab dipole matrix
! adiaoutp: upper diab matrix of dipole
! x component come first and then y component
!
! dmat_x & dmat_y: analytic model of dipole, x and y
!
! matdim: dimension of hamiltoniam matrix
! mkeigen: integer: no eigenvectors if =0
! eigenvs: dummy storage for eigenvectors
include 'nnparams.incl'
include 'JTmod.incl'
integer ndiab
parameter ndiab=5
DOUBLE PRECISION coords(maxnin),coeffs(maxnout)
DOUBLE PRECISION adiaoutp(maxpout),dmat_x(ndiab,ndiab)
!DOUBLE PRECISION dmat_y(ndiab,ndiab)
!integer i,j,ii
call diab_x(coords,dmat_x,coeffs)
!call diab_y(coords,dmat_y,coeffs)
! rewrite the diabatic matrix into 1D array of adiaoutp
!ii=1
!do i=1,ndiab
!do j=i,ndiab
! adiaoutp(ii)=dmat_x(i,j)
! adiaoutp(ii+10) = -1*dmat_y(i,j)
! ii=ii+1
!enddo
!enddo
adiaoutp(1) = dmat_x(1,1)
adiaoutp(2) = dmat_x(2,1)
adiaoutp(3) = dmat_x(2,2)
adiaoutp(4) = dmat_x(3,1)
adiaoutp(5) = dmat_x(3,2)
adiaoutp(6) = dmat_x(3,3)
adiaoutp(7) = dmat_x(4,1)
adiaoutp(8) = dmat_x(4,2)
adiaoutp(9) = dmat_x(4,3)
adiaoutp(10) = dmat_x(4,4)
adiaoutp(11) = dmat_x(5,1)
adiaoutp(12) = dmat_x(5,2)
adiaoutp(13) = dmat_x(5,3)
adiaoutp(14) = dmat_x(5,4)
adiaoutp(15) = dmat_x(5,5)
!write(*,*) dmat_x(1,1)
END SUBROUTINE

716
src/model/nncoords_no3.f90 Normal file
View File

@ -0,0 +1,716 @@
!--------------------------------------------------------------------------------------
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! % SUBROUTINE CTRANS(...)
! %
! % M. Vossel 21.03.2023
! %
! % Routine to transform symmetryinput coordinates to symmetrized
! % coordinates. Distances Are discribet by Morse coordinates or
! % TMC depending on Set Parameters in the Genetic Input.
! %
! % input variables
! % q:
! % q(1): H1x
! % q(2): y
! % q(3): z
! % q(4): H2x
! % q(5): y
! % q(6): z
! % q(7): H3x
! % q(8): y
! % q(9): z
!
!
!
! % Internal variables:
! % t: primitive coordinates (double[qn])
! % t(1):
! % t(2):
! % t(3):
! % t(4):
! % t(5):
! % t(6):
! % t(7):
! % t(8):
! % t(9):
! % t: dummy (double[qn])
! % p: parameter vector
! % npar: length of parameter vector
! %
! % Output variables
! % s: symmetrized coordinates (double[qn])
! % s(1): CH-symetric streatch
! % s(2): CH-asymetric streatch-ex
! % s(3): CH-asymetric streatch-ey
! % s(4): CH-bend-ex
! % s(5): CH-bend-ey
! % s(6): CH-umbrella
! % s(7): CH-umbrella**2
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
module ctrans_mod
implicit none
include 'only_model.incl'
include 'nnparams.incl'
! precalculate pi, 2*pi and angle to radian conversion
double precision, parameter :: pii = 4.00d0*datan(1.00d0)
double precision, parameter :: pi2 = 2.00d0*pii
double precision, parameter :: ang2rad = pii/180.00d0
! precalculate roots
double precision, parameter:: sq2 = 1.00d0/dsqrt(2.00d0)
double precision, parameter:: sq3 = 1.00d0/dsqrt(3.00d0)
double precision, parameter:: sq6 = 1.00d0/dsqrt(6.00d0)
! change distances for equilibrium
double precision, parameter :: dchequi = 2.344419d0
contains
subroutine ctrans(q)
!use dim_parameter, only: qn
use invariants_mod, only: invariants
integer k !running indices
double precision, intent(inout) :: q(maxnin) !given coordinates
double precision :: s(maxnin) !output coordinates symmetry adapted and scaled
double precision :: t(maxnin) !output coordinates symmetry adapted but not scaled
! ANN Variables
!double precision, optional, intent(out) :: invariants(:)
! kartesian coordianates copy from MeF+ so substitute c by n and removed f
double precision ch1(3), ch2(3), ch3(3), c_atom(3)
double precision nh1(3), nh2(3), nh3(3)
double precision zaxis(3), xaxis(3), yaxis(3)
double precision ph1(3), ph2(3), ph3(3)
! primitive coordinates
double precision dch1, dch2, dch3 !nh-distances
double precision umb !Umbrella Angle from xy-plane
! Symmetry coordinates
double precision aR !a1-modes H-Dist.,
double precision exR, exAng !ex components H-Dist., H-Ang.
double precision eyR, eyAng !ey components H-Dist., H-Ang.
double precision inv(3)
! debugging
logical, parameter :: dbg = .false.
! initialize coordinate vectors
s = 0.0d0
t = 0.0d0
! write kartesian coords for readability
c_atom(1:3) = q(1:3) ! N-atom at origin
do k = 1, 3
ch1(k) = q(k + 3)
ch2(k) = q(k + 6)
ch3(k) = q(k + 9)
end do
q=0.d0
! construct z-axis
nh1 = normalized(ch1)
nh2 = normalized(ch2)
nh3 = normalized(ch3)
zaxis = create_plane(nh1, nh2, nh3)
! calculate bonding distance
dch1 = norm(ch1)
dch2 = norm(ch2)
dch3 = norm(ch3)
! construct symmertic and antisymmetric strech
aR = symmetrize(dch1 - dchequi, dch2 - dchequi, dch3 - dchequi, 'a')
exR = symmetrize(dch1, dch2, dch3, 'x')
eyR = symmetrize(dch1, dch2, dch3, 'y')
! construc x-axis and y axis
ph1 = normalized(project_point_into_plane(nh1, zaxis, c_atom))
xaxis = normalized(ph1)
yaxis = xproduct(zaxis, xaxis) ! right hand side koordinates
! project H atoms into C plane
ph2 = normalized(project_point_into_plane(nh2, zaxis, c_atom))
ph3 = normalized(project_point_into_plane(nh3, zaxis, c_atom))
call construct_HBend(exAng, eyAng, ph1, ph2, ph3, xaxis, yaxis)
umb = construct_umbrella(nh1, nh2, nh3, zaxis)
! set symmetry coordinates and even powers of umbrella
!s(1) = dch1-dchequi!aR
!s(2) = dch2-dchequi!exR
!s(3) = dch3-dchequi!eyR
! call invariants and get them
! 24 invariants
call invariants(0.0d0,exR,eyR,exAng,eyAng,umb,inv)
q(1:3)=inv(1:3)
q(4) = aR
q(5) = exR
q(6) = eyR
q(7) = exAng
q(8) = -1.0d0*eyAng
q(9) = umb
! pairwise distances as second coordinate set
!call pair_distance(q, t(1:6))
!if (dbg) write (6, '("sym coords s=",9f16.8)') s(1:qn)
!if (dbg) write (6, '("sym coords t=",9f16.8)') t(1:qn)
!if (present(invariants)) then
! call get_invariants(s, invariants)
!end if
! RETURN Q AS INTERNAL COORD
end subroutine ctrans
! subroutine ctrans(q)
! use invariants_mod, only: invariants
! implicit none
! double precision, intent(inout):: q(maxnin)
! double precision:: invar(24)
! double precision:: a,b,esx,esy,ebx,eby
! a=q(1)
! esx=q(2)
! esy=q(3)
! ebx=q(4)
! eby=q(5)
! b=q(6)
! call invariants(a,esx,esy,ebx,eby,b,invar)
!
! q(1:24)=invar(1:24)
! q(25)=esx
! q(26)=esy
! q(27)=ebx
! q(28)=eby
! q(29)=b
! end subroutine ctrans
subroutine pair_distance(q, r)
double precision, intent(in) :: q(9)
double precision, intent(out) :: r(6)
double precision :: atom(3, 4)
integer :: n, k, count
!atom order: H1 H2 H3 N
atom(:, 1:3) = reshape(q, [3, 3])
atom(:, 4) = (/0.00d0, 0.00d0, 0.00d0/)
! disntace order 12 13 14 23 24 34
count = 0
do n = 1, size(atom, 2)
do k = n + 1, size(atom, 2)
count = count + 1
r(count) = sqrt(sum((atom(:, k) - atom(:, n))**2))
end do
end do
end subroutine pair_distance
function morse_and_symmetrize(x,p,pst) result(s)
double precision, intent(in),dimension(3) :: x
double precision, intent(in),dimension(11) :: p
integer, intent(in),dimension(2) :: pst
integer :: k
double precision, dimension(3) :: s
double precision, dimension(3) :: t
! Morse transform
do k=1,3
t(k) = morse_transform(x(k), p, pst)
end do
s(1) = symmetrize(t(1), t(2), t(3), 'a')
s(2) = symmetrize(t(1), t(2), t(3), 'x')
s(3) = symmetrize(t(1), t(2), t(3), 'y')
end function morse_and_symmetrize
! subroutine get_invariants(s, inv_out)
! use dim_parameter, only: qn
! use select_monom_mod, only: v_e_monom, v_ee_monom
! double precision, intent(in) :: s(qn)
! double precision, intent(out) :: inv_out(:)
! ! double precision, parameter :: ck = 1.00d0, dk = 1.00d0/ck ! scaling for higher order invariants
! double precision inv(24)
! integer, parameter :: inv_order(12) = & ! the order in which the invariants are selected
! & [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
! double precision Rch, umb, xR, yR, xAng, yAng
!! for readability
! Rch = s(1)
! xR = s(2)
! yR = s(3)
! xAng = s(4)
! yAng = s(5)
! umb = s(6)**2
!! invarianten
!! a moden
! inv(1) = Rch
! inv(2) = umb
!! invariante e pairs
! inv(3) = v_e_monom(xR, yR, 1)
! inv(4) = v_e_monom(xAng, yAng, 1)
!! third order e pairs
! inv(5) = v_e_monom(xR, yR, 2)
! inv(6) = v_e_monom(xAng, yAng, 2)
! ! invariant ee coupling
! inv(7) = v_ee_monom(xR, yR, xAng, yAng, 1)
! ! mode combinations
! inv(8) = Rch*umb
!
! inv(9) = Rch*v_e_monom(xR, yR, 1)
! inv(10) = umb*v_e_monom(xR, yR, 1)
!
! inv(11) = Rch*v_e_monom(xAng, yAng, 1)
! inv(12) = umb*v_e_monom(xAng, yAng, 1)
!
!! damp coordinates because of second order and higher invariants
! inv(3) = sign(sqrt(abs(inv(3))), inv(3))
! inv(4) = sign(sqrt(abs(inv(4))), inv(4))
! inv(5) = sign((abs(inv(5))**(1./3.)), inv(5))
! inv(6) = sign((abs(inv(6))**(1./3.)), inv(6))
! inv(7) = sign((abs(inv(7))**(1./3.)), inv(7))
! inv(8) = sign(sqrt(abs(inv(8))), inv(8))
! inv(9) = sign((abs(inv(9))**(1./3.)), inv(9))
! inv(10) = sign((abs(inv(10))**(1./3.)), inv(10))
! inv(11) = sign((abs(inv(11))**(1./3.)), inv(11))
! inv(12) = sign((abs(inv(12))**(1./3.)), inv(12))
!
! inv_out(:) = inv(inv_order(1:size(inv_out, 1)))
!
! end subroutine get_invariants
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! % real part of spherical harmonics
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! Ylm shifted to 0 for theta=0
! double precision function ylm(theta, phi, l, m)
! implicit none
! double precision theta, phi
! integer l, m
! ylm = plm2(dcos(theta), l, m)*cos(m*phi) - plm2(1.00d0, l, m)
! end function ylm
!!----------------------------------------------------------
! double precision function plm2(x, l, n)
! implicit none
! double precision x
! integer l, m, n
!
! double precision pmm, p_mp1m, pllm
! integer ll
!
!! negative m und bereich von x abfangen
! if ((l .lt. 0)&
! &.or. (abs(n) .gt. abs(l))&
! &.or. (abs(x) .gt. 1.)) then
! write (6, '(''bad arguments in legendre'')')
! stop
! end if
!
!! fix sign of m to compute the positiv m
! m = abs(n)
!
! pmm = (-1)**m*dsqrt(fac(2*m))*1./((2**m)*fac(m))& !compute P(m,m) not P(l,l)
! &*(dsqrt(1.-x**2))**m
!
! if (l .eq. m) then
! plm2 = pmm !P(l,m)=P(m,m)
! else
! p_mp1m = x*dsqrt(dble(2*m + 1))*pmm !compute P(m+1,m)
! if (l .eq. m + 1) then
! plm2 = p_mp1m !P(l,m)=P(m+1,m)
! else
! do ll = m + 2, l
! pllm = x*(2*ll - 1)/dsqrt(dble(ll**2 - m**2))*p_mp1m& ! compute P(m+2,m) up to P(l,m) recursively
! &- dsqrt(dble((ll - 1)**2 - m**2))&
! &/dsqrt(dble(l**2 - m**2))*pmm
!! schreibe m+2 und m+1 jeweils fuer die naechste iteration
! pmm = p_mp1m !P(m,m) = P(m+1,m)
! p_mp1m = pllm !P(m+1,m) = P(m+2,m)
! end do
! plm2 = pllm !P(l,m)=P(m+k,m), k element N
! end if
! end if
!
!! sets the phase of -m term right (ignored to gurantee Ylm=(Yl-m)* for JT terms
!! if(n.lt.0) then
!! plm2 = (-1)**m * plm2 !* fac(l-m)/fac(l+m)
!! endif
!
! end function
!----------------------------------------------------------------------------------------------------
double precision function fac(i)
integer i
select case (i)
case (0)
fac = 1.00d0
case (1)
fac = 1.00d0
case (2)
fac = 2.00d0
case (3)
fac = 6.00d0
case (4)
fac = 24.00d0
case (5)
fac = 120.00d0
case (6)
fac = 720.00d0
case (7)
fac = 5040.00d0
case (8)
fac = 40320.00d0
case (9)
fac = 362880.00d0
case (10)
fac = 3628800.00d0
case (11)
fac = 39916800.00d0
case (12)
fac = 479001600.00d0
case default
write (*, *) 'ERROR: no case for given faculty, Max is 12!'
stop
end select
end function fac
! Does the simplest morse transform possible
! one skaling factor + shift
function morse_transform(x, p, pst) result(t)
double precision, intent(in) :: x
double precision, intent(in) :: p(11)
integer, intent(in) :: pst(2)
double precision :: t
if (pst(2) == 11) then
t = 1.00d0 - exp(-abs(p(2))*(x - p(1)))
else
error stop 'in morse_transform key required or wrong number of parameters'
end if
end function morse_transform
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! % FUNCTION F(...) ! MAIK DEPRICATING OVER THE TOP MORSE FUNCTION FOR MYSELF
! %
! % Returns exponent of tunable Morse coordinate
! % exponent is polynomial * gaussian (skewed)
! % ilabel = 1 or 2 selects the parameters a and sfac to be used
! %
! % Background: better representation of the prefector in the
! % exponend of the morse function.
! % Formular: f(r) = lest no3 paper
! %
! % Variables:
! % x: distance of atoms (double)
! % p: parameter vector (double[20])
! % ii: 1 for CCl and 2 for CCH (int)
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pure function f(x, p, ii)
integer , intent(in) :: ii !1 for CCL and 2 for CCH
double precision, intent(in) :: x !coordinate
double precision, intent(in) :: p(11) !parameter-vector
integer i !running index
double precision r !equilibrium distance
double precision gaus !gaus part of f
double precision poly !polynom part of f
double precision skew !tanh part of f
double precision f !prefactor of exponent and returned value
integer npoly(2) !order of polynom
! Maximum polynom order
npoly(1) = 5
npoly(2) = 5
! p(1): position of equilibrium
! p(2): constant of exponent
! p(3): constant for skewing the gaussian
! p(4): tuning for skewing the gaussian
! p(5): Gaussian exponent
! p(6): Shift of Gaussian maximum
! p(7)...: polynomial coefficients
! p(8+n)...: coefficients of Morse Power series
! 1-exp{[p(2)+exp{-p(5)[x-p(6)]^2}[Taylor{p(7+n)}(x-p(6))]][x-p(1)]}
! Tunable Morse function
! Power series in Tunable Morse coordinates of order m
! exponent is polynomial of order npoly * gaussian + switching function
! set r r-r_e
r = x
r = r - p(1)
! set up skewing function:
skew = 0.50d0*p(3)*(dtanh(dabs(p(4))*(r - p(6))) + 1.00d0)
! set up gaussian function:
gaus = dexp(-dabs(p(5))*(r - p(6))**2)
! set up power series:
poly = 0.00d0
do i = 0, npoly(ii) - 1
poly = poly + p(7 + i)*(r - p(6))**i
end do
! set up full exponent function:
f = dabs(p(2)) + skew + gaus*poly
end function
!----------------------------------------------------------------------------------------------------
pure function xproduct(a, b) result(axb)
double precision, intent(in) :: a(3), b(3)
double precision :: axb(3) !crossproduct a x b
axb(1) = a(2)*b(3) - a(3)*b(2)
axb(2) = a(3)*b(1) - a(1)*b(3)
axb(3) = a(1)*b(2) - a(2)*b(1)
end function xproduct
pure function normalized(v) result(r)
double precision, intent(in) :: v(:)
double precision :: r(size(v))
r = v/norm(v)
end function normalized
pure function norm(v) result(n)
double precision, intent(in) :: v(:)
double precision n
n = dsqrt(sum(v(:)**2))
end function norm
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! % FUNCTION Project_Point_Into_Plane(x,n,r0) result(p)
! % return the to n orthogonal part of a vector x-r0
! % p: projected point in plane
! % x: point being projected
! % n: normalvector of plane
! % r0: Point in plane
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pure function project_point_into_plane(x, n, r0) result(p)
double precision, intent(in) :: x(:), n(:), r0(:)
double precision :: p(size(x)), xs(size(x))
xs = x - r0
p = xs - plane_to_point(x, n, r0)
end function project_point_into_plane
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! % Function Plane_To_Point(x,n,r0) result(p)
! % p: part of n in x
! % x: point being projected
! % n: normalvector of plane
! % r0: Point in plane
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pure function plane_to_point(x, n, r0) result(p)
double precision, intent(in) :: x(:), n(:), r0(:)
double precision p(size(x)), xs(size(x)), nn(size(n))
nn = normalized(n)
xs = x - r0
p = dot_product(nn, xs)*nn
end function plane_to_point
subroutine check_coordinates(q)
! check for faulty kartesain coordinates
double precision, intent(in) :: q(:)
integer :: i
if (all(abs(q) <= epsilon(0.00d0))) then
stop 'Error (ctrans): all kartesian coordinates are<=1d-8'
end if
do i = 1, 9, 3
if (all(abs(q(i:i + 2)) <= epsilon(0.00d0))) then
write (*, *) q
stop 'Error(ctrans):kartesian coordinates zero for one atom'
end if
end do
end subroutine
pure function rotor_a_to_z(a, z) result(r)
double precision, intent(in) :: a(3), z(3)
double precision :: r(3, 3)
double precision :: alpha
double precision :: s1(3), s(3, 3), rotor(3, 3)
s1 = xproduct(normalized(a), normalized(z))
alpha = asin(norm(s1))
s(:, 1) = normalized(s1)
s(:, 2) = normalized(z)
s(:, 3) = xproduct(s1, z)
rotor = init_rotor(alpha, 0.00d0, 0.00d0)
r = matmul(s, matmul(rotor, transpose(s)))
end function
! function returning Rz(gamma) * Ry(beta) * Rx(alpha) for basis order xyz
pure function init_rotor(alpha, beta, gamma) result(rotor)
double precision, intent(in) :: alpha, beta, gamma
double precision :: rotor(3, 3)
rotor = 0.00d0
rotor(1, 1) = dcos(beta)*dcos(gamma)
rotor(1, 2) = dsin(alpha)*dsin(beta)*dcos(gamma)&
&- dcos(alpha)*dsin(gamma)
rotor(1, 3) = dcos(alpha)*dsin(beta)*dcos(gamma)&
&+ dsin(alpha)*dsin(gamma)
rotor(2, 1) = dcos(beta)*dsin(gamma)
rotor(2, 2) = dsin(alpha)*dsin(beta)*dsin(gamma)&
&+ dcos(alpha)*dcos(gamma)
rotor(2, 3) = dcos(alpha)*dsin(beta)*dsin(gamma)&
&- dsin(alpha)*dcos(gamma)
rotor(3, 1) = -dsin(beta)
rotor(3, 2) = dsin(alpha)*dcos(beta)
rotor(3, 3) = dcos(alpha)*dcos(beta)
end function init_rotor
pure function create_plane(a, b, c) result(n)
double precision, intent(in) :: a(3), b(3), c(3)
double precision :: n(3)
double precision :: axb(3), bxc(3), cxa(3)
axb = xproduct(a, b)
bxc = xproduct(b, c)
cxa = xproduct(c, a)
n = normalized(axb + bxc + cxa)
end function create_plane
function symmetrize(q1, q2, q3, sym) result(s)
double precision, intent(in) :: q1, q2, q3
character, intent(in) :: sym
double precision :: s
select case (sym)
case ('a')
s = (q1 + q2 + q3)*sq3
case ('x')
s = sq6*(2.00d0*q1 - q2 - q3)
case ('y')
s = sq2*(q2 - q3)
case default
write (*, *) 'ERROR: no rule for symmetrize with sym=', sym
stop
end select
end function symmetrize
subroutine construct_HBend(ex, ey, ph1, ph2, ph3, x_axis, y_axis)
double precision, intent(in) :: ph1(3), ph2(3), ph3(3)
double precision, intent(in) :: x_axis(3), y_axis(3)
double precision, intent(out) :: ex, ey
double precision :: x1, y1, alpha1
double precision :: x2, y2, alpha2
double precision :: x3, y3, alpha3
! get x and y components of projected points
x1 = dot_product(ph1, x_axis)
y1 = dot_product(ph1, y_axis)
x2 = dot_product(ph2, x_axis)
y2 = dot_product(ph2, y_axis)
x3 = dot_product(ph3, x_axis)
y3 = dot_product(ph3, y_axis)
! -> calculate H deformation angles
alpha3 = datan2(y2, x2)
alpha2 = -datan2(y3, x3) !-120*ang2rad
! write(*,*)' atan2'
! write(*,*) 'alpha2:' , alpha2/ang2rad
! write(*,*) 'alpha3:' , alpha3/ang2rad
if (alpha2 .lt. 0) alpha2 = alpha2 + pi2
if (alpha3 .lt. 0) alpha3 = alpha3 + pi2
alpha1 = (pi2 - alpha2 - alpha3)
! write(*,*)' fixed break line'
! write(*,*) 'alpha1:' , alpha1/ang2rad
! write(*,*) 'alpha2:' , alpha2/ang2rad
! write(*,*) 'alpha3:' , alpha3/ang2rad
alpha1 = alpha1 !- 120.00d0*ang2rad
alpha2 = alpha2 !- 120.00d0*ang2rad
alpha3 = alpha3 !- 120.00d0*ang2rad
! write(*,*)' delta alpha'
! write(*,*) 'alpha1:' , alpha1/ang2rad
! write(*,*) 'alpha2:' , alpha2/ang2rad
! write(*,*) 'alpha3:' , alpha3/ang2rad
! write(*,*)
! construct symmetric and antisymmetric H angles
ex = symmetrize(alpha1, alpha2, alpha3, 'x')
ey = symmetrize(alpha1, alpha2, alpha3, 'y')
end subroutine construct_HBend
pure function construct_umbrella(nh1, nh2, nh3, n)&
&result(umb)
double precision, intent(in) :: nh1(3), nh2(3), nh3(3)
double precision, intent(in) :: n(3)
double precision :: umb
double precision :: theta(3)
! calculate projections for umberella angle
theta(1) = dacos(dot_product(n, nh1))
theta(2) = dacos(dot_product(n, nh2))
theta(3) = dacos(dot_product(n, nh3))
! construct umberella angle
umb = sum(theta(1:3))/3.00d0 - 90.00d0*ang2rad
end function construct_umbrella
pure subroutine construct_sphericals&
&(theta, phi, cf, xaxis, yaxis, zaxis)
double precision, intent(in) :: cf(3), xaxis(3), yaxis(3), zaxis(3)
double precision, intent(out) :: theta, phi
double precision :: x, y, z, v(3)
v = normalized(cf)
x = dot_product(v, normalized(xaxis))
y = dot_product(v, normalized(yaxis))
z = dot_product(v, normalized(zaxis))
theta = dacos(z)
phi = -datan2(y, x)
end subroutine construct_sphericals
! subroutine int2kart(internal, kart)
! double precision, intent(in) :: internal(6)
! double precision, intent(out) :: kart(9)
! double precision :: h1x, h1y, h1z
! double precision :: h2x, h2y, h2z
! double precision :: h3x, h3y, h3z
! double precision :: dch0, dch1, dch2, dch3
! double precision :: a1, a2, a3, wci
!
! kart = 0.00d0
! dch1 = dchequi + sq3*internal(1) + 2*sq6*internal(2)
! dch2 = dchequi + sq3*internal(1) - sq6*internal(2) + sq2*internal(3)
! dch3 = dchequi + sq3*internal(1) - sq6*internal(2) - sq2*internal(3)
! a1 = 2*sq6*internal(4)
! a2 = -sq6*internal(4) + sq2*internal(5)
! a3 = -sq6*internal(4) - sq2*internal(5)
! wci = internal(6)
!
! ! Berechnung kartesische Koordinaten
! ! -----------------------
! h1x = dch1*cos(wci*ang2rad)
! h1y = 0.0
! h1z = -dch1*sin(wci*ang2rad)
!
! h3x = dch2*cos((a2 + 120)*ang2rad)*cos(wci*ang2rad)
! h3y = dch2*sin((a2 + 120)*ang2rad)*cos(wci*ang2rad)
! h3z = -dch2*sin(wci*ang2rad)
!
! h2x = dch3*cos((-a3 - 120)*ang2rad)*cos(wci*ang2rad)
! h2y = dch3*sin((-a3 - 120)*ang2rad)*cos(wci*ang2rad)
! h2z = -dch3*sin(wci*ang2rad)
!
! kart(1) = h1x
! kart(2) = h1y
! kart(3) = h1z
! kart(4) = h2x
! kart(5) = h2y
! kart(6) = h2z
! kart(7) = h3x
! kart(8) = h3y
! kart(9) = h3z
! end subroutine int2kart
end module ctrans_mod
!**** Define coordinate transformation applied to the input before fit.
!***
!***
!****Conventions:
!***
!*** ctrans: subroutine transforming a single point in coordinate space
subroutine trans_in(pat_in,ntot)
use ctrans_mod, only: ctrans
implicit none
include 'nnparams.incl'
!include 'nndbg.incl'
!include 'nncommon.incl'
double precision pat_in(maxnin,maxpats)
integer ntot
integer j
do j=1,ntot
call ctrans(pat_in(:,j))
! FIRST ELEMENT OF PAT-IN ARE USED BY NEURON NETWORK
write(62,'(6f16.8)') pat_in(4:9,j)
enddo
end

View File

@ -0,0 +1,72 @@
Module invariants_mod
implicit none
contains
!----------------------------------------------------
subroutine invariants(a,xs,ys,xb,yb,b,invar)
implicit none
double precision, intent(in) :: a, xs, ys, xb, yb, b
double precision, intent(out) :: invar(24)
complex(8) :: q1, q2
LOGICAL,PARAMETER:: debg =.FALSE.
integer :: i
! express the coordinate in complex
q1 = dcmplx(xs, ys)
q2 = dcmplx(xb, yb)
! compute the invariants
invar(24) = a
invar(23) =b**2
! INVARIANTS OF KIND II
!------------------------
invar(1) = dreal( q1 * conjg(q1) ) ! r11
invar(2) = dreal( q1 * conjg(q2) ) ! r12
invar(3) = dreal( q2 * conjg(q2) ) ! r22
invar(4) = (dimag(q1 * conjg(q2)) )**2 ! rho 12**2
!INVATIANTS OF KIND III
!------------------------
invar(5) = dreal( q1 * q1 * q1 ) ! r111
invar(6) = dreal( q1 * q1 * q2 ) ! r112
invar(7) = dreal( q1 * q2 * q2 ) ! r122
invar(8) = dreal( q2 * q2 * q2 ) ! r222
invar(9) = (dimag( q1 * q1 * q1 ))**2 ! rho111**2
invar(10) = (dimag( q1 * q1 * q2 ))**2 ! rho112 **2
invar(11) = (dimag( q1 * q2 * q2 ))**2 ! rho122**2
invar(12) = (dimag( q2 * q2 * q2 ))**2 ! rho222
! INVARIANTS OF KIND IV
!-------------------------
invar(13) = (dimag( q1 * conjg(q2)) * dimag( q1 * q1 * q1 ))
invar(14) = (dimag( q1 * conjg(q2)) * dimag( q1 * q1 * q2 ))
invar(15) = (dimag( q1 * conjg(q2)) * dimag( q1 * q2 * q2 ))
invar(16) = (dimag( q1 * conjg(q2)) * dimag( q2 * q2 * q2 ))
! INVARIANTS OF KIND V
!----------------------
invar(17) = (dimag( q1 * q1 * q1 ) * dimag( q1 * q1 * q2 ))
invar(18) = (dimag( q1 * q1 * q1 ) * dimag( q1 * q2 * q2 ))
invar(19) = (dimag( q1 * q1 * q1 ) * dimag( q2 * q2 * q2 ))
invar(20) = (dimag( q1 * q1 * q2 ) * dimag( q1 * q2 * q2 ))
invar(21) = (dimag( q1 * q1 * q2 ) * dimag( q2 * q2 * q2 ))
invar(22) = (dimag( q1 * q2 * q2 ) * dimag( q2 * q2 * q2 ))
if (debg) then
write(*,"(A,*(f10.5))")"Invar II", (invar(i),i=1,4)
write(*,"(A,*(f10.5))") "Invar III", (invar(i),i=5,12)
write(*,"(A,*(f10.5))")"Invar IV", (invar(i),i=13,16)
write(*,"(A,*(f10.5))")"Invar V", (invar(i),i=17,22)
write(*,*)"THE INPUT COORDINATE IN COMPLEX REPRES"
write(*,*)"---------------------------------------"
write(*,*)"xs =",dreal(q1), "ys=",dimag(q1)
endif
end subroutine invariants
end module invariants_mod

115
src/neuron_types.f Normal file
View File

@ -0,0 +1,115 @@
**** Define activation functions for FF-NN propagation.
***
***Conventions:
***neuroni: subroutine for type-i neuron (ex. neuron1)
***derivi: derivative of type-i activation function
***ntype: number of neurons of type i
***L: Layer vector, assumed to begin at the first neuron of type i
***deriv: Derivative vector, assumed to begin at the first neuron of type i
***************************************************************************
****Pattern:
* subroutine neuron0(L,ntype)
* implicit none
* <Description>
*
* include 'nnparams.incl'
*
* double precision L(*)
* integer ntype
*
* integer i
*
* do i=1,ntype
* L(i)= f(L(i))
* enddo
*
* end
***************************************************************************
subroutine neuron1(L,ntype)
implicit none
! logistic sigmoid curve
! f = N*tanh(a*x)
! where a=atanh(1/sqrt(3)) and N=sqrt(3)
! This way, f(1)=1 and f'' maximal at 1.
include 'nnparams.incl'
double precision L(*)
integer ntype
double precision alpha, norm
parameter (norm=dsqrt(3.0d0))
parameter (alpha=(dlog(norm+1.0d0)-dlog(norm-1.0d0))/2.0d0)
integer i
do i=1,ntype
L(i)=norm*dtanh(alpha*L(i))
enddo
end
subroutine deriv1(L,deriv,ntype)
implicit none
! logistic sigmoid curve
! f'(x)=N*(1-tanh^2(a*x))*(a)
! where a=atanh(1/sqrt(3)) and N=sqrt(3)
! This way, f(1)=1 and f'' maximal at 1.
include 'nnparams.incl'
double precision L(*),deriv(*)
integer ntype
double precision alpha, norm
parameter (norm=dsqrt(3.0d0))
parameter (alpha=(dlog(norm+1.0d0)-dlog(norm-1.0d0))/2.0d0)
integer i
do i=1,ntype
deriv(i)=alpha*norm*(1.0D0 - dtanh(alpha*L(i))**2)
enddo
end
**********************
subroutine neuron2(L,ntype)
implicit none
! linear activation function
include 'nnparams.incl'
double precision L(*)
integer ntype
integer i
do i=1,ntype
L(i)=L(i)
enddo
end
subroutine deriv2(deriv,ntype)
implicit none
! linear activation function
include 'nnparams.incl'
integer ntype
double precision deriv(*)
integer i
do i=1,ntype
deriv(i)=1.0D0
enddo
end
**********************

336
src/new_model_dipole.f90 Normal file
View File

@ -0,0 +1,336 @@
module diabmodel
use dip_param, only: p,pst,init_dip_planar_data
implicit none
include "nnparams.incl"
integer, parameter:: ndiab=4
logical:: debug=.false.
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
subroutine diab_x(q,e,nn_out)
implicit none
!include "dip_planar_genetic.incl"
double precision,intent(in)::q(maxnin)
double precision,intent(out)::e(ndiab,ndiab)
double precision,intent(inout):: nn_out(maxnout)
!double precision:: mod_param(maxnout)
!double precision:: cj(maxnout)
integer id,i,j
double precision xs,xb,ys,yb,a,b,ss,sb,v3_vec(8)
call init_dip_planar_data()
xs=q(25)
ys=q(26)
xb=q(27)
yb=q(28)
a=q(24)
b=q(29)
ss=xs**2+ys**2 ! totaly symmetric term
sb=xb**2+yb**2
v3_vec( 1) = xs*(xs**2-3*ys**2)
v3_vec( 2) = xb*(xb**2-3*yb**2)
v3_vec( 3) = xb*(xs**2-ys**2) - 2*yb*xs*ys
v3_vec( 4) = xs*(xb**2-yb**2) - 2*ys*xb*yb
v3_vec( 5) = ys*(3*xs**2-ys**2)
v3_vec( 6) = yb*(3*xb**2-yb**2)
v3_vec( 7) = yb*(xs**2-ys**2)+2*xb*xs*ys
v3_vec( 8) = ys*(xb**2-yb**2)+2*xs*xb*yb
!do i=1,maxnout
! mod_param(i)=1+0.0001*nn_out(i)
!enddo
e=0.0d0
id=1 !1
! V-term
! order 1
e(1,1)=e(1,1)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb
id=id+1 !2
e(2,2)=e(2,2)+p(pst(1,id))*(1+0.0001*nn_out(1))*xs+p(pst(1,id)+1)*xb ! here
e(3,3)=e(3,3)+p(pst(1,id))*(1+0.0001*nn_out(1))*xs+p(pst(1,id)+1)*xb
id=id+1 !3
e(4,4)=e(4,4)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb
! order 2
id=id+1 !4
e(1,1)=e(1,1)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2)&
+p(pst(1,id)+2)*(xs*xb-ys*yb)
id=id+1 !5
e(2,2)=e(2,2)+p(pst(1,id))*(1+0.0001*nn_out(2))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) +&
p(pst(1,id)+2)*(xs*xb-ys*yb)
e(3,3)=e(3,3)+p(pst(1,id))*(1+0.0001*nn_out(2))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) +&
p(pst(1,id)+2)*(xs*xb-ys*yb)
id=id+1 !6
e(4,4)=e(4,4)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) + &
p(pst(1,id)+2)*(xs*xb-ys*yb)
! order 3
id=id+1 !7
e(1,1)=e(1,1)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb*sb
id=id+1 !8
e(2,2)=e(2,2)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb*sb
e(3,3)=e(3,3)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb*sb
id=id+1 !9
e(4,4)=e(4,4)+p(pst(1,id))*xs*ss+p(pst(1,id)+1)*xb*sb
! JAHN TELLER COUPLING W AND Z
! order 0
id=id+1 !10
e(2,2)=e(2,2)+p(pst(1,id))*(1+0.0001*nn_out(3))
e(3,3)=e(3,3)-p(pst(1,id))*(1+0.0001*nn_out(3))
! order 1
id=id+1 !11
e(2,2)=e(2,2)+p(pst(1,id))*(1+0.0001*nn_out(4))*xs+p(pst(1,id)+1)*xb
e(3,3)=e(3,3)-p(pst(1,id))*(1+0.0001*nn_out(4))*xs-p(pst(1,id)+1)*xb
e(2,3)=e(2,3)-p(pst(1,id))*(1+0.0001*nn_out(4))*ys-p(pst(1,id)+1)*yb
! order 2
id=id+1 !12
e(2,2)=e(2,2)+p(pst(1,id))*(1+0.0001*nn_out(5))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb)+p(pst(1,id)+3)*ss+p(pst(1,id)+4)*sb
e(3,3)=e(3,3)-(p(pst(1,id))*(1+0.0001*nn_out(5))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb)+p(pst(1,id)+3)*ss+p(pst(1,id)+4)*sb)
e(2,3)=e(2,3)+p(pst(1,id))*(1+0.0001*nn_out(5))*2*xs*ys+p(pst(1,id)+1)*2*xb*yb+ &
p(pst(1,id)+2)*(xs*yb+xb*ys)
! order 3
id=id+1 !13
do i=1,4
j=i-1
e(2,2)=e(2,2)+(p(pst(1,id)+j)+p(pst(1,id)+j+4))*v3_vec(i)
e(3,3)=e(3,3)-(p(pst(1,id)+j)+p(pst(1,id)+j+4))*v3_vec(i)
e(2,3)=e(2,3)+(-p(pst(1,id)+j)+p(pst(1,id)+j+4))*v3_vec(i+4)
enddo
e(2,2)=e(2,2)+p(pst(1,id)+8)*xs*ss+p(pst(1,id)+9)*xb*sb
e(3,3)=e(3,3)-(p(pst(1,id)+8)*xs*ss+p(pst(1,id)+9)*xb*sb)
e(2,3)=e(2,3)-p(pst(1,id)+8)*ys*ss-p(pst(1,id)+9)*yb*sb
! PSEUDO JAHN TELLER
! A2 ground state coupled with E
! ###################################################
! ###################################################
! order 0
id=id+1 !14
e(1,2)=e(1,2)+b*p(pst(1,id))
! order 1
id=id+1 !15
e(1,2)=e(1,2)+b*(p(pst(1,id))*xs+p(pst(1,id)+1)*xb)
e(1,3)=e(1,3)+b*(p(pst(1,id))*ys+p(pst(1,id)+1)*yb)
! order 2
id=id+1 !16
e(1,2)=e(1,2)+b*(p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2)&
+p(pst(1,id)+2)*(xs*xb-ys*yb) + p(pst(1,id)+3)*(xs**2+ys**2))
e(1,3)=e(1,3)-b*(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)&
+p(pst(1,id)+2)*(xs*yb+xb*ys))
!! THE COUPLING OF A2 WITH A1
!####################################################
!####################################################
! order 1
id=id+1 !17
e(1,4)=e(1,4)+b*(p(pst(1,id))*xs+p(pst(1,id)+1)*xb)
id=id+1 !18
e(1,4)=e(1,4)+b*(p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2)&
+p(pst(1,id)+2)*(xs*xb-ys*yb))
!!! THE COUPLING OF A1 WITH E
!!####################################################
!####################################################
! order 0
id=id+1 !19
e(2,4)=e(2,4)+p(pst(1,id))
! order 1
id=id+1 !20
e(2,4)=e(2,4)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb
e(3,4)=e(3,4)+p(pst(1,id))*ys+p(pst(1,id)+1)*yb
! order 2
id=id+1 !21
e(2,4)=e(2,4)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb) +p(pst(1,id)+3)*(xs**2+ys**2)
e(3,4)=e(3,4)-p(pst(1,id))*(2*xs*ys)-p(pst(1,id)+1)*(2*xb*yb) &
-p(pst(1,id)+2)*(xs*yb+xb*ys)
!! End of the model
e(2,1)=e(1,2)
e(3,1)=e(1,3)
e(3,2)=e(2,3)
e(4,1)=e(1,4)
e(4,2)=e(2,4)
e(4,3)=e(3,4)
end subroutine diab_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! THE Y COMPONENT OF DIPOLE
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
subroutine diab_y(q,e,nn_out)
implicit none
!integer , intent(in)::npar
!include "dip_planar_genetic.incl"
double precision,intent(in)::q(maxnin)
double precision,intent(out)::e(ndiab,ndiab)
double precision,intent(inout):: nn_out(maxnout)
!double precision:: mod_param(maxnout)
!double precision :: cj(maxnout)
integer id,i,j
double precision ys,xb,a,b,xs,yb,ss,sb,v3_vec(8)
call init_dip_planar_data()
xs=q(25)
ys=q(26)
xb=q(27)
yb=q(28)
a=q(24)
b=q(29)
ss=xs**2+ys**2 ! totaly symmetric term
sb=xb**2+yb**2
v3_vec( 1) = xs*(xs**2-3*ys**2)
v3_vec( 2) = xb*(xb**2-3*yb**2)
v3_vec( 3) = xb*(xs**2-ys**2) - 2*yb*xs*ys
v3_vec( 4) = xs*(xb**2-yb**2) - 2*ys*xb*yb
v3_vec( 5) = ys*(3*xs**2-ys**2)
v3_vec( 6) = yb*(3*xb**2-yb**2)
v3_vec( 7) = yb*(xs**2-ys**2)+2*xb*xs*ys
v3_vec( 8) = ys*(xb**2-yb**2)+2*xs*xb*yb
!do i=1,maxnout
! mod_param(i)=1+0.0001*nn_out(i)
!enddo
e=0.0d0
! V-term
id=1 !1
e(1,1)=e(1,1)+p(pst(1,id))*ys+p(pst(1,id)+1)*yb
id=id+1 !2
e(2,2)=e(2,2)+p(pst(1,id))*(1+0.0001*nn_out(1))*ys+p(pst(1,id)+1)*yb
e(3,3)=e(3,3)+p(pst(1,id))*(1+0.0001*nn_out(1))*ys+p(pst(1,id)+1)*yb
id=id+1 !3
e(4,4)=e(4,4)+p(pst(1,id))*ys+p(pst(1,id)+1)*yb
! order 2
id=id+1 !4
e(1,1)=e(1,1)-p(pst(1,id))*(2*xs*ys)-p(pst(1,id)+1)*(2*xb*yb) &
-p(pst(1,id)+2)*(xs*yb+xb*ys)
id=id+1 !5
e(2,2)=e(2,2)-p(pst(1,id))*(1+0.0001*nn_out(2))*(2*xs*ys)-p(pst(1,id)+1)*(2*xb*yb) &
-p(pst(1,id)+2)*(xs*yb+xb*ys)
e(3,3)=e(3,3)-p(pst(1,id))*(1+0.0001*nn_out(2))*(2*xs*ys)-p(pst(1,id)+1)*(2*xb*yb) &
-p(pst(1,id)+2)*(xs*yb+xb*ys)
id=id+1 !6
e(4,4)=e(4,4)-p(pst(1,id))*(2*xs*ys)-p(pst(1,id)+1)*(2*xb*yb) &
-p(pst(1,id)+2)*(xs*yb+xb*ys)
! order 3
id=id+1 !7
e(1,1)=e(1,1)+p(pst(1,id))*ys*ss+p(pst(1,id)+1)*yb*sb
id=id+1 !8
e(2,2)=e(2,2)+p(pst(1,id))*ys*ss+p(pst(1,id)+1)*yb*sb
e(3,3)=e(3,3)+p(pst(1,id))*ys*ss+p(pst(1,id)+1)*yb*sb
id=id+1 !9
e(4,4)=e(4,4)+p(pst(1,id))*ys*ss+p(pst(1,id)+1)*yb*sb
! V- term + totally symmetric coord a
! JAHN TELLER COUPLING TERM
! order 0
id=id+1 !10
e(2,3)=e(2,3)+p(pst(1,id))*(1+0.0001*nn_out(3))
! order 1
id=id+1 !11
e(2,2)=e(2,2)-p(pst(1,id))*(1+0.0001*nn_out(4))*ys-p(pst(1,id)+1)*yb
e(3,3)=e(3,3)+p(pst(1,id))*(1+0.0001*nn_out(4))*ys+p(pst(1,id)+1)*yb
e(2,3)=e(2,3)-p(pst(1,id))*(1+0.0001*nn_out(4))*xs-p(pst(1,id)+1)*xb
!id=id+1 !12
! order 2
id=id+1 !12
e(2,2)=e(2,2)+p(pst(1,id))*(1+0.0001*nn_out(5))*2*xs*ys+p(pst(1,id)+1)*2*xb*yb+p(pst(1,id)+2)*(xs*yb+xb*ys)
e(3,3)=e(3,3)-p(pst(1,id))*(1+0.0001*nn_out(5))*2*xs*ys-p(pst(1,id)+1)*2*xb*yb-p(pst(1,id)+2)*(xs*yb+xb*ys)
e(2,3)=e(2,3)-(p(pst(1,id))*(1+0.0001*nn_out(5))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2)) &
-p(pst(1,id)+2)*(xs*xb-ys*yb)+p(pst(1,id)+3)*ss+p(pst(1,id)+4)*sb
! order 3
id=id+1 !13
do i=1,4
j=i-1
e(2,2)=e(2,2)+(p(pst(1,id)+j)-p(pst(1,id)+j+4))*v3_vec(i+4)
e(3,3)=e(3,3)-(p(pst(1,id)+j)-p(pst(1,id)+j+4))*v3_vec(i+4)
e(2,3)=e(2,3)+(p(pst(1,id)+j)+p(pst(1,id)+j+4))*v3_vec(i)
enddo
e(2,2)=e(2,2)-p(pst(1,id)+8)*ys*ss-p(pst(1,id)+9)*yb*sb
e(3,3)=e(3,3)+p(pst(1,id)+8)*ys*ss+p(pst(1,id)+9)*yb*sb
e(2,3)=e(2,3)-p(pst(1,id)+8)*xs*ss-p(pst(1,id)+1)*xb*sb
! PSEUDO JAHN TELLER
! ORDER 0
! THE COUPLING OF A2 GROUND STATE WITH E
! ###################################################
! ###################################################
! order 0
id=id+1 !14
e(1,3)=e(1,3)-b*(p(pst(1,id)))
! order 1
id=id+1 !15
e(1,2)=e(1,2)-b*(p(pst(1,id))*ys+p(pst(1,id)+1)*yb)
e(1,3)=e(1,3)+b*(p(pst(1,id))*xs+p(pst(1,id)+1)*xb)
! order 2
id=id+1 !16
e(1,2)=e(1,2)+b*(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)&
+p(pst(1,id)+2)*(xs*yb+xb*ys))
e(1,3)=e(1,3)+b*(p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2)&
+p(pst(1,id)+2)*(xs*xb-ys*yb) - p(pst(1,id)+3)*(xs**2+ys**2))
! THE COUPLING OF A2 WITH A1
!####################################################
!####################################################
! order 1
id=id+1 !17
e(1,4)=e(1,4)+b*(p(pst(1,id))*ys+p(pst(1,id)+1)*yb)
! order 2
id=id+1 !18
e(1,4)=e(1,4)-b*(p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb)&
+p(pst(1,id)+2)*(xs*yb+xb*ys))
! THE COUPLING OF A1 WITH E
!####################################################
!####################################################
! order 0
id=id+1 !19
e(3,4)=e(3,4)-p(pst(1,id))
! order 1
id=id+1 !20
e(2,4)=e(2,4)-p(pst(1,id))*ys-p(pst(1,id)+1)*yb
e(3,4)=e(3,4)+p(pst(1,id))*xs+p(pst(1,id)+1)*xb
! order 2
id=id+1 !21
e(2,4)=e(2,4)+p(pst(1,id))*(2*xs*ys)+p(pst(1,id)+1)*(2*xb*yb) &
+p(pst(1,id)+2)*(xs*yb+xb*ys)
e(3,4)=e(3,4)+p(pst(1,id))*(xs**2-ys**2)+p(pst(1,id)+1)*(xb**2-yb**2) &
+p(pst(1,id)+2)*(xs*xb-ys*yb) - p(pst(1,id)+3)*(xs**2+ys**2)
! end of the model
e(2,1)=e(1,2)
e(3,1)=e(1,3)
e(3,2)=e(2,3)
e(4,1)=e(1,4)
e(4,2)=e(2,4)
e(4,3)=e(3,4)
end subroutine diab_y
end module diabmodel

98
src/nncommon.incl Normal file
View File

@ -0,0 +1,98 @@
!**** Basic data structures and special constants for ANN
!***
!***
!*** /nngene/: fundamental constants for gene manipulation
!***
!*** /nnprop/: basic fitting info (iternation numbers etc.)
!***
!*** /nnio/: constants for translating input variables/function values
!*** into NN input/output
!***
!*** /nnopt/: information for convergence acceleration
!***
!*** /nnunits/: unit transformations for output
!***
!*** /nnplot/: information relevant to plotting
!***
!*** /nnpartial/: information to organize partial runs (e.g. restarts)
!***
!*** maxbpit: max. number of iterations for ML-learning
!*** maxfails: maximum number of failed microiterations
!*** maxref_fails: maximum number of times the reference pattern
!*** set fails to improve
!*** lambda_initial: initial value for Marquardt-Levenberg parameter
!*** mqfact_default: factor by which lambda is changed during MQL-fit
!***
!*** inp_in: number of coordinates in input (not implemented)
!*** inp_out: number of values in output
!*** len_in: number of input neurons
!*** len_out: number of output neurons
!***
!*** unit_string: name of output unit
!*** unit_con: conversion factor from internal to output unit
!***
!*** continued/partial run parameters
!***
!*** from_fit: MQL-fit to start from
!*** to_fit: MQL-fit to end at (instead of nset)
!*** use_record: whether to interact with records at all.
!*** record_state: Whether to read/write from the record (see RECORD: key)
!***
!*** plotting parameters
!***
!*** sets: number of data sets for plotting
!*** ndata: contains the number of data points for each block for plot
!***
!*** genetic parameters
!***
!*** wspread: spread of new, random weights around 0
!*** bspread: spread of new, random biases around 0
!*** ipmut: chance of point mutation per gene on ichrom
!*** dpmut: chance of point mutation per gene on dchrom
!*** ipins: chance of a gene insertion/deletion on ichrom
!*** dpins: chance of a gene insertion/deletion on dchrom
!***
!*** convergence Acceleration parameters
!***
!*** wb_arad: trust radius (maximum allowed total stepsize)
!*** wei_alim: threshold for switching stepsize limit for weights
!*** bi_alim: threshold for switching stepsize limit for biases
!*** wei_amax: absolute maximum step size for |weights| <= wei_alim
!*** bi_amax: absolute maximum step size for |biases| <= bi_alim
!*** wei_ascale: relative maximum step size for |weights| > wei_alim
!*** bi_ascale: relative maximum step size for |biases| > bi_alim
!***
!*** shift_in: mean of the fitting input set
!*** fact_in: standard deviation of the input set
!*** norm_inp: if true, normalize input
!*** pres_inp: if true, preserve shift_in and fact_in from input,
!*** otherwise normalize destructively
double precision wei_alim,bi_alim,wei_amax,bi_amax
double precision wei_ascale,bi_ascale,wb_arad
double precision shift_in(maxnin),fact_in(maxnin)
double precision wspread,bspread
double precision ipmut, dpmut,ipins,dpins
double precision unit_con
double precision lambda_initial, mqfact_default
integer len_in,len_out,inp_out,inp_in
integer maxbpit,maxfails,maxref_fails
integer from_fit, to_fit
integer npoints(maxpats), ndata(maxpats)
integer sets
integer record_state
logical limstep,pres_inp,norm_inp
logical use_record
character*4 unit_string
common /nngene/ wspread,bspread,ipmut,dpmut,ipins,dpins
common /nnprop/ lambda_initial, mqfact_default,
> maxbpit, maxfails, maxref_fails
common /nnio/ inp_out,inp_in, len_in, len_out
common /nnopt/ wei_alim,bi_alim,wei_amax,bi_amax,
> wei_ascale,bi_ascale,wb_arad,shift_in,fact_in,
> pres_inp,norm_inp,limstep
common /nnunits/ unit_con,unit_string
common /nnplot/ npoints, sets, ndata
common /nnpartial/ from_fit, to_fit, record_state, use_record

29
src/nndbg.incl Normal file
View File

@ -0,0 +1,29 @@
!**** Parameters
!*** dbg: enables debugging features.
!*** vbs: enables verbose mode
!*** rats: enables mass calculation mode
!*** conlog: enables convergence logs
!***
logical dbg,vbs,rats
logical conlog
logical ldbg
! parameter (dbg=.false.,vbs=.false.,rats=.false.)
! parameter (dbg=.false.,vbs=.false.,rats=.true.)
! parameter (dbg=.false.,vbs=.true.,rats=.false.)
! parameter (dbg=.true.,vbs=.false.,rats=.false.)
! parameter (dbg=.true.,vbs=.true.,rats=.false.)
! parameter (dbg=.true.,vbs=.false.,rats=.true.)
parameter (dbg=.false.,vbs=.true.,rats=.true.)
parameter (conlog=.true.)
! parameter (conlog=.false.)
!**** Inferred Parameters
!*** ldbg: "long dbg": enables massive information
!*** dumps if rats is not present. Best for
!*** small data sets.
parameter (ldbg=(dbg.and.(.not.rats)))

982
src/nnmqo.f Normal file
View File

@ -0,0 +1,982 @@
!--------------------------------------------------------------------------------------
subroutine nnmarq(rms,ref_rms,mqpar,mqfact,W,B,act,wterr,
> pat_in,pat_out,ref_in,ref_out,
> typop,laystr,weistr,nlay,
> rmsopt,npat,nref,mingrad,minwbstep,fit_id,skip)
implicit none
! Optimizes weights and biases using least squares errors
! and Marquard Levenberg
!
! fit_id: unique identifying integer for a given fit
! log_unit: unique file unit for given fit
!
! nlay: number of given layers
! npat: number of given pattern pairs
! nref: number of reference patterns
! rms: (weighted) root mean square error
! ref_rms: rms of reference data
! gradnorm: norm of error gradient
! wbnorm: norm of steps
! last: rms of prev. iteration
! rmsopt: error threshold
! mingrad: error gradient threshold
! minwbstep: threshold for wbnorm
! update: Decides whether or not jsquare and grad need to be reevaluated.
! ref_conv: true if reference set seized improving despite fit
! grad_conv: true if gradient converged
! step_conv: true if stepsize converged
! fails: number of unsuccessful steps
! skip: indicates fatal error having occured
! act: decides which weights and biases are actually updated
! macroit: number of J-updates
!
! pat_in: input patterns
! pat_out: desired output patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
! ref_*: in analogy to pat_in/out for reference data
! (convergence tests)
!
! wterr: weight factors for each element of the error vector e
!
! J: Jacobian matrix. A single row consists of matrix elements
! corresponding to all Weights as they are kept in memory (W),
! followed by all Biases. It is never fully kept in memory.
! Instead, required matrix elements are generated when needed.
!
! e: Error vector. It consists of the differences between the NN's
! output-vector and the desired output patterns, for all patterns.
! Like J it is never really kept in memory.
!
! jsquare: J^T J
! wbsteps: Steps for weights and biases, same order as a single jacobian-row.
! mqpar: initial parameter (lambda) for Marquard-Levenberg
! mqfact: factor by which lambda is multiplied/divided after each iteration
! wsave: saves W with best outcome
! bsave: saves B with best outcome
! skip: indicates whether fit is broken and needs to be ignored.
!
! grad: total error vector transformed by transposed jacobian
! W: weight matrix vector
! B: bias vector
! typop: type population matrix
! laystr: layer structure matrix
include 'nnparams.incl'
include 'nndbg.incl'
include 'nncommon.incl'
integer npat,nref
integer fit_id
double precision W(maxwei),B(neucap)
double precision pat_in(maxnin,maxpats),pat_out(maxpout,maxpats)
double precision ref_in(maxnin,maxpats),ref_out(maxpout,maxpats)
double precision wterr(maxpout,maxpats)
double precision rms,ref_rms
double precision rmsopt,mqfact,mqpar,mingrad,minwbstep
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer act(wbcap)
logical skip
double precision wsave(maxwei),bsave(neucap),wbsteps(wbcap)
double precision wsave_ref(maxwei),bsave_ref(neucap)
double precision grad(wbcap)
double precision jsquare
allocatable jsquare(:,:)
double precision lambda,last,ref_last,gradnorm,wbnorm,wbnorm_old
integer pos_out,len_err
integer lay_end,wei_end,jac_end
integer fails,macroit
integer ref_fails
integer log_unit
character*32 nnlogfile
logical ref_conv,grad_conv,step_conv
logical update
integer j
! Initialize values
lambda=mqpar
allocate(jsquare(wbcap,wbcap))
pos_out=laystr(2,nlay)-1 !increment leading to output layer pos.
! position of last defined neuron/W-matrix element
lay_end=pos_out+len_out
wei_end=weistr(2,nlay-1,1)
len_err=npat*len_out !length of error vector
jac_end=wei_end+lay_end-len_in !width of jacobian matrix
! evaluate initial jsquare and gradient, initialize last
if (dbg) then
write(iout,'(A)') 'Building first Jacobian..'
endif
call mkjsq(W,B,wterr,jsquare,last,grad,gradnorm,
> jac_end,pat_in,pat_out,wei_end,
> typop,laystr,nlay,npat)
if (dbg) then
write(iout,'(A)') 'done.'
write(iout,asline)
write(iout,'(A)') 'INITIAL WEIGHTS:'
write(iout,mform) W(1:wei_end)
write(iout,'(A)') 'INITIAL BIASES:'
write(iout,mform) B(len_in+1:lay_end)
endif
call mkerr(W,B,wterr(1,npat+1),ref_rms,ref_in,ref_out,
> typop,laystr,nlay,nref)
rms=last
ref_last=ref_rms
wsave(1:wei_end)=W(1:wei_end)
bsave(1:lay_end)=B(1:lay_end)
fails=0
ref_fails=0
macroit=0
wbnorm=-1.0d0
update=.true.
ref_conv=.false.
grad_conv=.false.
step_conv=.false.
if (conlog) then
! generate file displaying convergence behavior.
log_unit=fitunit+fit_id
nnlogfile=trim(nnldir) // 'convergence_'
write(nnlogfile,'(A,I4.4,".log")') trim(nnlogfile),fit_id
if (dbg.or.vbs) then
write(iout,'(A)') 'logging convergence in '''
> // trim(nnlogfile) // '''...'
endif
open(log_unit,file=trim(nnlogfile),status='replace')
write(log_unit,'(A)') '# UNIT: ' // trim(unit_string)
write(log_unit,'(A1,A8,6A15,1A18)') '#','ITER','RMS',
> 'RMS(REF)','GRADNORM','STEP','LAMBDA','{ORIGSTEP}'
write(unit=log_unit,fmt='(I9,4ES15.3)') 0, rms*unit_con,
> ref_rms*unit_con, gradnorm*unit_con, lambda
else if (vbs) then
write(iout,'(A)') '#UNITS: '//trim(unit_string)
write(iout,'(A1,A8,5A15)') '#','ITER','RMS','RMS(REF)',
> 'GRADNORM','WBNORM','LAMBDA'
write(iout,'(I9,4ES15.3,ES15.2)') 0, rms*unit_con,
> ref_rms*unit_con, gradnorm*unit_con,
> wbnorm, lambda
endif
! Iterates up to a maximum number of allowed microiterations
! (backpropagations)
do j=1,maxbpit
! evaluate step
call marqstep(jsquare,wbsteps,lambda,jac_end,grad,wbnorm,skip)
if (skip) then
exit
endif
! copy old step norm
wbnorm_old=wbnorm
! apply changes
call mqupdate(W,B,wbsteps,act,lay_end,wei_end)
! TODO: consider pulling this into check_mqstep.
! check for improvement
call mkerr(W,B,wterr,rms,pat_in,pat_out,
> typop,laystr,nlay,npat)
if (conlog.and.rats) then
write(log_unit,'(I9,5ES15.3)',advance='no') j, rms*unit_con,
> ref_rms*unit_con, gradnorm*unit_con, wbnorm, lambda
if (limstep) then
write(log_unit,'(ES15.3,2I6)',advance='no') wbnorm_old
endif
else if (vbs) then
write(iout,'(I9,3ES15.3,2ES15.2)') j, rms*unit_con,
> ref_rms*unit_con, gradnorm*unit_con,
> wbnorm, lambda
endif
if (dbg) then
write(iout,sline)
write(iout,*) 'LAST:',last,'RMS:',rms
write(iout,*) 'LAMBDA:', lambda
write(iout,*) 'GRADNORM:', gradnorm
write(iout,*) 'WBNORM:', wbnorm
endif
call check_mqstep(W,B,wterr,rms,ref_rms,last,ref_last,
> wsave,bsave,wsave_ref,bsave_ref,
> fails,ref_fails,lambda,update,ref_conv,
> mqfact,ref_in,ref_out,wei_end,
> typop,laystr,weistr,
> nlay,npat,nref)
! check for convergence
step_conv=(wbnorm <= minwbstep)
grad_conv=(gradnorm <= mingrad)
if (step_conv.or.grad_conv) then
exit
endif
if (rmsopt.gt.0.0d0) then
! if considered relevant, check absolute error
if (rms <= rmsopt) exit
endif
if (fails > maxfails) then
if (dbg) write(iout,'(A)') 'MAXFAILS REACHED, GIVE UP'
exit
else if (ref_conv) then
if (dbg) write(iout,'(A)') 'MAXREFFAILS REACHED, GIVE UP'
exit
endif
if (conlog) then
if (update) then
write(log_unit,'(3X,A)') '#ACCEPTED'
else
write(log_unit,'(3X,A,ES12.3)') '#WORSE: ΔRMS=',
> (rms-last)*unit_con
endif
endif
if (update) then
! reevaluate jacobian
last=rms
macroit=macroit+1
call mkjsq(W,B,wterr,jsquare,rms,grad,gradnorm,
> jac_end,pat_in,pat_out,wei_end,
> typop,laystr,nlay,npat)
endif
if (dbg) then
write(iout,'(A)') 'WEIGHTS:'
write(iout,mform) W(1:wei_end)
write(iout,'(A)') 'BIASES:'
write(iout,mform) B(len_in+1:lay_end)
endif
enddo
! overwrite rms with best result
rms=last
ref_rms=ref_last
if (skip) then
if (dbg.or.vbs) then
write(iout,'(A)') '#CONVERGENCE ERROR: '
> // 'FATAL ERROR OCCURED.'
endif
if (rats) then
write(unit=perfunit,fmt=400) rms*unit_con, ref_rms*unit_con,
> wbnorm, gradnorm*unit_con, macroit, j-1, fit_id,
> '#CRASHED'
endif
else if (j >= maxbpit) then
if (dbg.or.vbs) then
write(iout,'(A)') '#CONVERGENCE ERROR: '
> // 'ITERATIONS EXCEEDED MAXBPIT'
endif
if (rats) then
write(unit=perfunit,fmt=401) rms*unit_con, ref_rms*unit_con,
> wbnorm, gradnorm*unit_con, macroit,j-1, fit_id
endif
else if (fails > maxfails) then
if (dbg) then
write(iout,'(A)') '#CONVERGENCE ERROR: MAXFAILS REACHED.'
endif
if (rats) then
write(unit=perfunit,fmt=400) rms*unit_con, ref_rms*unit_con,
> wbnorm, gradnorm*unit_con, macroit, j-1, fit_id,
> '#FAILED'
endif
else
if (vbs) then
if (ref_conv) then
write(iout,'(A)') '#CONVERGED VALIDATION SET.'
endif
if (wbnorm <= minwbstep) then
if (gradnorm <= mingrad) then
write(iout,'(A)') '#CONVERGENCE REACHED.'
> // ' (GRADIENT & STEP)'
endif
write(iout,'(A)') '#CONVERGED STEPSIZE ONLY.'
else if (gradnorm <= mingrad) then
write(iout,'(A)') '#CONVERGED GRADIENT ONLY.'
endif
endif
if (rats) then
write(unit=perfunit,fmt=400,advance='no')
> rms*unit_con,
> ref_rms*unit_con, wbnorm,
> gradnorm*unit_con, macroit, j-1, fit_id,
> '#CONVERGED'
if (ref_conv) then
write(perfunit,'(A)') ' [REF]'
else if (grad_conv.and.step_conv) then
write(perfunit,'(A)') ' [GRAD & STEP]'
else if (grad_conv) then
write(perfunit,'(A)') ' [GRAD]'
else if (step_conv) then
write(perfunit,'(A)') ' [STEP]'
else
write(unit=perfunit,fmt=newline)
endif
endif
endif
400 format(4ES10.2,4X,I6,"/",I6,I8,4X,A)
401 format(4ES10.2,4X,I6,"/",I6,I8)
if (conlog) then
close(log_unit)
endif
deallocate(jsquare)
if (dbg) then
j=j-1
write(iout,asline)
write(iout,'(A)') 'OPT END.'
write(iout,'(A12,I9)') 'ITERATIONS:',j
write(iout,'(A9,I12)') 'MACROIT:', macroit
write(iout,'(A26,3(I6,'' :''),F6.2,''%'')')
> 'SAVED:UNDONE:TOTAL:%SAVED',
> macroit, j-macroit, j,
> 1.0D2*dble(macroit)/dble(j)
write(iout,'(A)') 'NEUPOP:'
write(iout,miform) laystr(1,1:nlay)
write(iout,'(A)') 'INSHIFT:'
write(iout,mform) shift_in(1:laystr(1,1))
write(iout,'(A)') 'INSCALE:'
write(iout,mform) fact_in(1:laystr(1,1))
write(iout,'(A)') 'FINAL W:'
write(iout,mform) W(1:wei_end)
write(iout,'(A)') 'FINAL B:'
write(iout,mform) B(1:lay_end)
write(iout,*) 'FINAL RMS:', rms
write(iout,*) 'FINAL RMS(REF):', ref_rms
write(iout,*) 'FINAL LAMBDA',lambda*mqfact
write(iout,asline)
endif
end
!--------------------------------------------------------------------------------------
subroutine check_mqstep(W,B,wterr,rms,ref_rms,last,ref_last,
> wsave,bsave,wsave_ref,bsave_ref,
> fails,ref_fails,lambda,update,ref_conv,mqfact,
> ref_in,ref_out,wei_end,
> typop,laystr,weistr,
> nlay,npat,nref)
implicit none
! Compare current parameter set's performance with current best and
! revert if necessary.
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
integer npat,nref
double precision W(maxwei),B(neucap)
double precision wsave(maxwei),bsave(neucap)
double precision wsave_ref(maxwei),bsave_ref(neucap)
double precision ref_in(maxnin,maxpats),ref_out(maxpout,maxpats)
double precision wterr(maxpout,maxpats)
double precision rms,ref_rms,last,ref_last
double precision lambda,mqfact
integer fails,ref_fails
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
logical update,ref_conv
integer lay_end,wei_end
wei_end=weistr(2,nlay-1,1)
lay_end=laystr(2,nlay)-1+len_out
! First, check fitting data set
if (last.lt.rms) then
! Revert parameter changes
W(1:wei_end)=wsave(1:wei_end)
B(1:lay_end)=bsave(1:lay_end)
lambda=lambda*mqfact
update=.false.
fails=fails+1
return
else
if (lambda.gt.zero) then
lambda=lambda/mqfact
endif
update=.true.
fails=0
endif
! Evaluate error of reference data set
call mkerr(W,B,wterr(1,npat+1),ref_rms,ref_in,ref_out,
> typop,laystr,nlay,nref)
if (dbg) then
write(iout,*) 'LAST(REF):',ref_last,'RMS(REF):', ref_rms
endif
! Next, check reference data set
if (ref_last.lt.ref_rms) then
if (dbg) then
write(iout,'(A)') 'VALIDATION SET ERROR INCREASED.'
endif
! keep backup of old parameter set but continue fit
ref_fails=ref_fails+1
if (ref_fails.eq.1) then
wsave_ref(1:wei_end)=wsave(1:wei_end)
bsave_ref(1:lay_end)=bsave(1:lay_end)
endif
if (ref_fails.ge.maxref_fails) then
ref_conv=.true.
! if reference rms increased despite fit improving,
! discard changes and exit
W(1:wei_end)=wsave_ref(1:wei_end)
B(1:lay_end)=bsave_ref(1:lay_end)
if (dbg) then
write(iout,'(A)') 'VALIDATION SEIZED IMPROVING, GIVE UP'
endif
return
endif
else
ref_last=ref_rms
ref_fails=0
endif
! save changes disregarding reference set
wsave(1:wei_end)=W(1:wei_end)
bsave(1:lay_end)=B(1:lay_end)
end
!--------------------------------------------------------------------------------------
subroutine mkjsq(W,B,wterr,jsquare,rms,grad,gradnorm,jac_end,
> pat_in,pat_out,wei_end,
> typop,laystr,nlay,npat)
use axel, only: init_input
implicit none
! Directly evaluates J^T J and gradient.
! Since jsquare is symmetric, only the upper triangle is evaluated.
!
! nlay: number of given layers
! npat: number of given pattern pairs
! rms: (weighted) root mean square error
! wei_end: position of last defined W-matrix-element in W-vector!
! jac_end: number of all weights and biases together
!
! pat_in: input patterns
! pat_out: desired output patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
!
! wterr: weight factors for each element of the error vector e
!
! jacrow: One row of the jacobian matrix. It consists of matrix elements
! corresponding to all Weights as they are kept in memory (W),
! followed by all Biases.
!
! jsquare: J^T J
! outgrads: the derivatives of the arbitrary error function with respect to
! the neuronal outputs.
!
! grad: total error vector transformed by transposed jacobian
! gradnorm: norm of gradient grad
!
! del: neuron error vector
! pat_err: segment of the total error vector for one pattern.
! deriv: activation function derivatives
! W: weight matrix vector
! B: bias vector
! L: layer vector
! typop: type population matrix
! laystr: layer structure matrix
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for weight matrix from layer N to N+1
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
integer npat,nlay,wei_end,jac_end
double precision W(maxwei),B(neucap)
double precision jsquare(wbcap,wbcap),grad(wbcap)
double precision pat_in(maxnin,maxpats),pat_out(maxpout,maxpats)
double precision wterr(maxpout,maxpats)
double precision rms,gradnorm
integer laystr(3,maxlay),typop(maxtypes,maxlay)
double precision L(neucap),jacrow(wbcap)
double precision del(neucap),deriv(neucap),pat_err(maxpout)
double precision outgrads(maxnout,maxpout)
integer pos_out,pos_jac
integer j,k,n,m
pos_out=laystr(2,nlay)-1 !increment leading to output layer pos.
rms=0.0D0
del=0.0D0
do j=1,jac_end
do m=j,jac_end
jsquare(m,j)=0.0d0
enddo
grad(j)=0.0d0
enddo
do n=1,npat
call init_input(L,pat_in(1,n),shift_in,fact_in,len_in)
call propagate(W,B,L,deriv,typop,laystr,nlay)
pos_jac=(n-1)*inp_out !increment for err-vector pos.
! evaluate pat_err
call nnerror(pat_err,pat_in(1,n),pat_out(1,n),L(pos_out+1))
! evaluate output value derivatives
call nnoutgrad(outgrads,pat_in(1,n),L(pos_out+1))
do k=1,inp_out
rms=rms+wterr(k,n)*pat_err(k)**2
! prepare sensitivity vector
del=0.0D0
do j=1,len_out
del(pos_out+j)=-deriv(pos_out+j)*outgrads(j,k)
> * dsqrt(wterr(k,n))
enddo
! evaluate J-Matrix elements for a single row
call backprop(del,W,deriv,laystr,nlay)
call nnjacob(del,L,jacrow,wei_end,laystr,nlay)
! build up jsquare and gradient
do j=1,jac_end
do m=j,jac_end
jsquare(m,j)=jsquare(m,j)+jacrow(j)*jacrow(m)
enddo
grad(j)=grad(j)+jacrow(j)*pat_err(k)*dsqrt(wterr(k,n))
enddo
enddo
enddo
do j=1,jac_end
do m=j+1,jac_end
jsquare(j,m)=jsquare(m,j)
enddo
enddo
rms=dsqrt(rms)
gradnorm=dsqrt(dot_product(grad(1:jac_end),grad(1:jac_end)))
end
!--------------------------------------------------------------------------------------
subroutine nnjacob(del,L,jacrow,wei_end,laystr,nlay)
implicit none
! Evaluates one row of the Jacobian
!
! nlay: number of given layers
! nprop: number of single-layer propagations
! neu_io: number of neurons in giv./prev. layer
! neu_oi: number of neurons in prev./giv. layer
! poslay: starting position of layer in L- and B-vector
! poswei: starting position of weight-matrix in W-vector
! wei_end: position of last defined W-matrix-element in W-vector
!
! del: neuron error vector
! L: layer vector
! jacrow: A single row of the jacobian matrix. It consists of all weights as they
! are kept in memory (W), followed by all biases.
! laystr: layer structure matrix
!
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for Weight Matrix from layer N to N+1
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
integer wei_end
double precision del(neucap),L(neucap),jacrow(wbcap)
integer laystr(3,maxlay)
integer nlay
integer poslay,poswei,nprop,neu_io,neu_oi
integer k
nprop=nlay-1
neu_io=laystr(1,1) !number of input neurons ('layer N')
poslay=laystr(2,1)
poswei=laystr(3,1)
do k=2,2*(nprop/2),2
neu_oi=laystr(1,k) !number of output neurons ('layer N+1')
! input neurons have no bias (no J-elements), hence -len_in
call jalay(neu_io,neu_oi,del(poslay),L(poslay),jacrow(poswei),
> jacrow(wei_end+poslay-len_in))
poslay=laystr(2,k)
poswei=laystr(3,k)
neu_io=laystr(1,k+1) !new number of output neurons ('layer N')
! former output neurons are now input, _io and _oi switch places!
! (done for efficiency)
call jalay(neu_oi,neu_io,del(poslay),L(poslay),jacrow(poswei),
> jacrow(wei_end+poslay-len_in))
poslay=laystr(2,k+1)
poswei=laystr(3,k+1)
enddo
do k=1,mod(nprop,2) !for odd nprop one iteration is left
neu_oi=laystr(1,nlay)
call jalay(neu_io,neu_oi,del(poslay),L(poslay),jacrow(poswei),
> jacrow(wei_end+poslay-len_in))
enddo
end
!--------------------------------------------------------------------------------------
subroutine jalay(neu_in,neu_out,del,L,welems,belems)
implicit none
! Evaluates Matrix-elements corresponding to one NN-layer.
!
! neu_in: number of neurons in layer N
! neu_out: number of neurons in layer N+1
!
! del: neuron error vector
! L: layer vector (beginning at layer N)
! welems: elements corresponding to W-matrix
! belems: elements corresponding to B-vector
!
include 'nnparams.incl'
include 'nndbg.incl'
integer neu_in,neu_out
double precision L(neu_in),del(neu_in+neu_out)
double precision welems(neu_in,neu_out),belems(neu_in+neu_out)
integer neu_tot,pos_out
integer j,k
neu_tot=neu_in+neu_out !total number of neurons in both layers
pos_out=neu_in+1 !position of first element in layer N+1
do j=pos_out,neu_tot
belems(j)=del(j)
enddo
do j=1,neu_out
do k=1,neu_in
welems(k,j)=L(k)*del(neu_in+j)
enddo
enddo
end
!--------------------------------------------------------------------------------------
subroutine mkerr(W,B,wterr,rms,pat_in,pat_out,
> typop,laystr,nlay,npat)
implicit none
! Evaluates rms only.
! nlay: number of given layers
! npat: number of given pattern pairs
! rms: (weighted) root mean square error
!
! pat_in: input patterns
! pat_out: desired output patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
!
! wterr: weight factors for each element of the error vector e
! pat_err: segment of the total error vector for one pattern.
!
! deriv: activation function derivatives (discarded)
! W: weight matrix vector
! B: bias vector
! L: layer vector
! typop: type population matrix
! laystr: layer structure matrix
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for weight matrix from layer N to N+1
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
integer npat
double precision W(maxwei),B(neucap)
double precision pat_in(maxnin,maxpats),pat_out(maxpout,maxpats)
double precision wterr(maxpout,npat)
double precision rms
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer nlay
double precision pat_err(maxpout)
integer n,k
rms=0.0D0
do n=1,npat
call mkerrvec(W,B,pat_err,pat_in(1,n),pat_out(1,n),
> typop,laystr,nlay)
do k=1,inp_out
rms=rms+wterr(k,n)*pat_err(k)**2
enddo
enddo
rms=dsqrt(rms)
end
!--------------------------------------------------------------------------------------
subroutine mkerrvec(W,B,pat_err,pat_in,pat_out,
> typop,laystr,nlay)
use axel, only: init_input
implicit none
! Generates error vector pat_err out of given ANN parameters
! for a *single* pattern pair.
!
! pat_in: input pattern
! pat_out: desired output pattern
! pat_*(i): value of ith in-/output neuron
!
! pat_err: error vector for one pattern.
!
! deriv: activation function derivatives (discarded)
! W: weight matrix vector
! B: bias vector
! L: layer vector
! typop: type population matrix
! laystr: layer structure matrix
! laystr(1,N): number of neurons in layer N
! laystr(2,N): starting pos. for layer N
! laystr(3,N): starting pos. for weight matrix from layer N to N+1
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision W(maxwei),B(neucap)
double precision pat_in(maxnin),pat_out(maxpout)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer nlay
double precision L(neucap),deriv(neucap),pat_err(maxpout)
integer pos_out
pos_out=laystr(2,nlay)-1 !increment leading to output layer pos.
L=0.0d0
call init_input(L,pat_in,shift_in,fact_in,len_in)
call propagate(W,B,L,deriv,typop,laystr,nlay)
! evaluate pat_err
call nnerror(pat_err,pat_in,pat_out,L(pos_out+1))
end
!--------------------------------------------------------------------------------------
subroutine marqstep(jsquare,wbsteps,lambda,jac_end,grad,wbnorm,
> skip)
implicit none
! Evaluates steps for W and B using the equation
! (J^T J + lambda*1) wbsteps = -J^T e,
! where "J^T e" is already given as grad and "J^T J" as jsquare,
!
! wbsteps: Steps for weights and biases, same order as a single jacobian-row.
! lambda: parameter for Marquard-Levenberg
! jac_end: number of all weights and biases together
! grad: error vector transformed by transposed jacobian
! jsquare: J^T J. Only the upper triangle of it is required,
! that is jsquare(i,j) needs only to be defined for i>=j.
! jscop: working copy of jsquare
! skip: true if fatal error has occured
!
include 'nnparams.incl'
include 'nndbg.incl'
double precision jsquare(wbcap,wbcap),grad(wbcap),wbsteps(wbcap)
double precision lambda,wbnorm
integer jac_end
logical skip
double precision jscop
allocatable jscop(:,:)
integer k,j
allocate(jscop(wbcap,wbcap))
do k=1,jac_end
do j=1,jac_end
jscop(j,k)=jsquare(j,k) !brutally inefficient.
enddo
enddo
do k=1,jac_end
jscop(k,k)=jscop(k,k)+lambda
enddo
! solve for wbsteps using Cholesky decomposition
call choldcsol(jscop,grad,wbsteps,jac_end,wbcap,skip)
! call mqinvertsol(jscop,grad,wbsteps,jac_end)
deallocate(jscop)
if (skip) then
return
endif
wbnorm=sqrt(dot_product(wbsteps(1:jac_end),wbsteps(1:jac_end)))
end
!--------------------------------------------------------------------------------------
subroutine mqupdate(W,B,wbsteps,act,lay_end,wei_end)
implicit none
! Updates W and B according to wbsteps.
!
! wei_end: position of last defined weight in W-vector
! lay_end: position of last defined bias in B-vector
! len_in: number of input-neurons. Since they have no biases
! B(1:len_in) is meaningless.
!
! W: weight matrix vector
! B: bias vector
! wbsteps: steps for weights and biases, same order as a single jacobian-row.
! act: decides which weights and biases are actually updated (1=active)
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision W(maxwei),B(neucap),wbsteps(wbcap)
integer act(wbcap)
integer lay_end,wei_end
integer k
do k=1,wei_end
if (act(k).eq.1) then
W(k)=W(k)-wbsteps(k)
endif
enddo
do k=len_in+1,lay_end
if (act(wei_end+k-len_in).eq.1) then
B(k)=B(k)-wbsteps(wei_end+k-len_in)
endif
enddo
end
!--------------------------------------------------------------------------------------
subroutine mqinvertsol(jscop,grad,wbsteps,jac_end)
implicit none
! Generate step not from using cholesky decomposition, but by directly
! inverting the matrix jscop.
!
! wbsteps: Steps for weights and biases, same order as a single jacobian-row.
! jac_end: number of all weights and biases together
! grad: error vector transformed by transposed jacobian
! jscop: J^T J + lambda. Only the upper triangle of it is written,
! that is jsquare(i,j) needs only to be defined for i>=j.
! js_trans: eigenvectors (equivalent to transformation matrix)
! js_eigen: eigenvalues
include 'nnparams.incl'
include 'nndbg.incl'
double precision jscop(wbcap,wbcap),grad(wbcap),wbsteps(wbcap)
integer jac_end
double precision js_eigen
double precision js_trans,js_inv
allocatable js_eigen(:)
allocatable js_trans(:,:),js_inv(:,:)
integer k,j,n
allocate(js_eigen(wbcap))
allocate(js_trans(wbcap,wbcap))
allocate(js_inv(wbcap,wbcap))
! fill the lower triangle of the matrix
! DW: FIXME: probably useless now.
do k=1,jac_end
do j=k+1,jac_end
jscop(j,k)=jscop(k,j)
enddo
enddo
! solve wbsteps by diagonalizing
call ddiag(jscop,js_eigen,js_trans,wbcap,jac_end)
js_inv=0.0d0
! invert hessian
do n=1,jac_end
do k=1,jac_end
do j=1,jac_end
js_inv(j,k)=js_inv(j,k)
> + js_trans(j,n)*js_trans(k,n)/js_eigen(n)
enddo
enddo
enddo
! apply inverted hessian to grad
do j=1,jac_end
wbsteps(j)=0.0d0
do k=1,jac_end
wbsteps(j)=wbsteps(j)+js_inv(k,j)*grad(k)
enddo
enddo
deallocate(js_eigen)
deallocate(js_trans)
deallocate(js_inv)
end

204
src/nnparams.incl Normal file
View File

@ -0,0 +1,204 @@
!**** Declarations
double precision pi,infty,zero
double precision scan_res
double precision hart2eV, eV2hart
double precision hart2icm, icm2hart
double precision eV2icm, icm2eV
double precision deg2rad, rad2deg
integer maxneu,maxlay,maxtypes,maxtpar
integer maxpats
integer maxnin,maxnout,maxpout
integer maxwei,neucap,wbcap
integer maxset, maxnnkeys
integer maxxrmeta,xrcap
integer iinfty
integer iout,nnunit,perfunit,fitunit
integer ec_error,ec_read,ec_dim,ec_log
integer ec_dimrd
integer record_read,record_write,record_overwrite
integer record_update
character*2 newline
character*8 stdfmt
character*8 nnldir
character*8 nntag
character*16 prim_tag
character*16 nnfdir,nnsdir
character*16 sline,asline,hline
character*16 mform,smform,miform
character*16 lrfmt,lifmt
character*32 nndmpfile,nnexpfile
character*32 nndatfile,nnreffile
character*32 sampfile,perfile
character*32 nnparfile,nnp10file
character*32 nnrecfile
!**********************************************************
!**** Parameters
!*** maxneu: max. number of neurons per hidden layer
!*** maxnin: max. number of neurons in input layer
!*** maxnout: max. number of neurons in output layer
!*** maxset: max. number of neural networks to fit
!*** maxpout: max. number of values in output pattern
!*** maxlay: max. number of layers (always >2)
!*** maxtypes: max. number of neuron types
!*** maxtpar: max. number of parameters for each neuron type
!*** maxpats: max. number of learning patterns
!*** maxxrmeta: max. number of metadata-blocks in xranges
!*** WARNING: maxnout should not be > maxneu, deriv-like structures
!*** assume so.
parameter (maxneu=150,maxnin=15,maxnout=30)
parameter (maxpout=15,maxset=10000)
parameter (maxlay=3,maxtypes=2,maxtpar=1)
parameter (maxpats=50000)
parameter (maxxrmeta=3)
!**********************************************************
!**** Inferred Parameters
!*** maxwei: max. total number of weight matrix elements
!*** neucap: max. total number of neurons
!*** wbcap: max. total number of weights and biases
!*** xrcap: max. total number of used dimensions in xranges
parameter (maxwei=(maxlay-3)*maxneu**2+maxneu*(maxnin+maxnout))
parameter (neucap=(maxlay-2)*maxneu+maxnin+maxnout)
parameter (wbcap=maxwei+neucap)
parameter (xrcap=2+maxxrmeta)
parameter (maxnnkeys=4*maxlay)
!*** WARNING: maxwei may fail for 2-layered networks
!*** if maxnin*maxnout is sufficiently large!
!**********************************************************
!**** Numerical Parameters
!*** infty: largest possible double precision real value.
!*** iinfty: largest possible integer value.
!*** zero: sets what is considered an irrelevant difference
!*** in size. use for comarison of reals, to determine
!*** 'dangerously small' values, etc
!*** scan_res: maximum precision for geometric boundary algorithm
! 3.14159265358979323846264338327950...
parameter (pi=3.1415926536D0)
parameter (infty=huge(1.0D0),iinfty=huge(1))
parameter (zero=1.0D-8,scan_res=1.0D-8)
!**********************************************************
!**** Unit Conversion Parameters
!*** X2Y: convert from X to Y.
!***
!**** !? currently inexact. FIX THIS.
!*** hart: hartree
!*** eV: electron volt
!*** icm: inverse centimeters (h*c/cm)
!****
!*** deg: degree
!*** rad: radians
parameter (hart2icm=219474.69d0)
parameter (hart2eV=27.211385d0)
parameter (eV2icm=hart2icm/hart2eV)
parameter (icm2hart=1.0d0/hart2icm)
parameter (eV2hart=1.0d0/hart2eV)
parameter (icm2eV=1.0d0/eV2icm)
parameter (deg2rad=pi/180.0d0)
parameter (rad2deg=1.0d0/deg2rad)
!**********************************************************
!**** I/O Parameters
!*** iout: standard output for vranf error messages
!*** nnunit: temporary UNIT for misc. output files
!*** nnuit + [0..99] are reserved for futher
!*** unspecific misc. files.
!*** perfunit: UNIT for performance logfile
!*** fitunit: UNIT added to random positive integer
!*** identifying a single core fit UNIQUELY
!***
!*** lrfmt: format for long real output
!*** lifmt: format for long integer output
!***
!*** nndatfile: filename for DATA-files
!*** (without file extension)
!*** nnreffile: filename for reference DATA-blocks
!*** (without file extension)
!*** nnparfile: filename for best fitted parameters to be
!*** written on (without file extension)
!*** nnp10file: filename for the 10th percentile parameters to
!*** be written on (without file extension)
!*** nnexpfile: filename for modified neural network parameters
!*** (without file extension)
!*** sampfile: filename for displaying sampled points in
!*** configuration space
!*** nndmpfile: filename for dumping data point pairs
!*** nnrecfile: filename for writing parameter records.
!*** perfile: filename for logged fitting performances.
!*** nntag: infix for various filenames to mark their origin
!*** program should end with a trailing '_' if nonempty.
!*** prim_tag: tag added to the '***' line of primitive par-files
!*** nnfdir: directory for dumping fit files
!*** nnsdir: directory for dumping scans.
!*** nnldir: directory for dumping logfiles for each fit
parameter (nndatfile='DATA_ANN')
parameter (nnreffile='REF_ANN')
parameter (nnparfile='../nnfits/fit_pars')
parameter (nnp10file='../nnfits/fit_10p')
parameter (nnexpfile='../nnfits/exp_pars')
parameter (nndmpfile='../nnfits/fit_dump.dat')
parameter (sampfile='../scans/samples.dat')
parameter (perfile='../logs/performance.log')
parameter (nnrecfile='../nnfits/record')
parameter (nnfdir='../nnfits/',nnsdir='../scans/')
parameter (nnldir='../logs/')
parameter (nntag='',prim_tag=' Time-stamp: " "')
parameter (lrfmt='(ES20.12)',lifmt='(I12)')
parameter (iout=6,perfunit=700,nnunit=800,fitunit=8000)
!**********************************************************
!**** Debugging Parameters
!*** sline: separation line
!*** asline: alternative sep. line
!*** hline: simple horizontal line
!*** newline: a single blank line
!*** mform: standard form for matrix output
!*** miform: standard form for integer matrix output
!*** smform: shortened form for matrix output
!*** stdfmt: standard format for strings
parameter (sline='(75("*"))',asline='(75("#"))')
parameter (hline='(75("-"))')
parameter (newline='()')
parameter (mform='(5ES12.4)',smform='(5ES10.2)')
parameter (miform='(5I12)')
parameter (stdfmt='(A)')
!**********************************************************
!**** Continuation Parameters
!*** record_*: Various possible values for the common block variable
!*** record_state. See the parser for more.
parameter (record_read=0,record_write=1,record_overwrite=-1)
parameter (record_update=-2)
!**********************************************************
!**** Error Codes
!*** Codes should be powers of 2. Binary representation of return value
!*** should correspond to all exceptions invoked. ec_error should never
!*** be invoked with any other.
!***
!*** ec_error: generic error (catch-all, avoid!)
!*** ec_read: parsing error during les()
!*** ec_dim: dimensioning error
!*** ec_log: logic error
!***
!**** Inferred error codes
!*** ec_dimrd: ec_dim+ec_read
parameter (ec_error=1,ec_read=2,ec_dim=4,ec_log=8)
parameter (ec_dimrd=ec_dim+ec_read)

132
src/nnread.f Normal file
View File

@ -0,0 +1,132 @@
subroutine read_net_prim(fname,par,nlay,laystr,weistr,typop)
implicit none
! Subroutine reading ANN-parameters as generated by punch_net_prim
include 'nnparams.incl'
include 'nndbg.incl'
integer nlay
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
double precision par(*)
character*32 fname
character*2048 full_fname, net_id
integer neupop(maxlay)
integer par_end,len_out
integer file_maxtypes
integer j
full_fname = trim(fname) // '.par'
open(nnunit,file=trim(full_fname),status='old',action='read')
write(6,'(4096A)') '# READING ''' // trim(full_fname) // '''...'
! read structure parameters
read(nnunit,*,end=800) nlay
read(nnunit,*,end=801) file_maxtypes
! Nobody needs segfaults from corrupted input files.
if ((file_maxtypes.gt.maxtypes).or.(file_maxtypes.le.0)) then
write(6,'(A,I12)') 'ERROR: READ_NET_PRIM: '
> //'VARIABLE MAXTYPES OUT OF BOUNDS:',maxtypes
stop 1
else if ((nlay.gt.maxlay).or.(nlay.le.0)) then
write(6,'(A,I12)') 'ERROR: READ_NET_PRIM: '
> //'VARIABLE NLAY OUT OF BOUNDS:',nlay
stop 1
endif
read(nnunit,*,end=802) neupop(1:nlay)
read(nnunit,*,end=803) typop(1:file_maxtypes,1:nlay)
len_out=neupop(nlay)
net_id=' '
read(nnunit,'(2048A)',end=804) net_id
if (.not.(len_trim(net_id).eq.0)) then
write(6,'(4096A)') '# MODEL ID: ' // trim(net_id(4:))
endif
! initialize laystr
call mknet(laystr,weistr,neupop,nlay)
par_end=laystr(3,nlay)-1 !final W-position
! move to final bias
do j=2,nlay
par_end=par_end + neupop(j)
enddo
read(nnunit,*,end=805) par(1:par_end)
close(nnunit)
return
800 write(6,'(A)') 'ERROR: READ_NET_PRIM: BROKEN OR MISSING NLAY'
801 write(6,'(A)') 'ERROR: READ_NET_PRIM: BROKEN OR MISSING'
> // ' MAXTYPE'
802 write(6,'(A)') 'ERROR: READ_NET_PRIM: BROKEN OR MISSING NEUPOP'
803 write(6,'(A)') 'ERROR: READ_NET_PRIM: BROKEN OR MISSING TYPOP'
804 write(6,'(A)') 'ERROR: READ_NET_PRIM: BROKEN MODEL-ID'
805 write(6,'(A)') 'ERROR: READ_NET_PRIM: BROKEN OR MISSING PARAMS'
end
!--------------------------------------------------------------------------------
subroutine read_record(par,weistr,nlay,nset)
implicit none
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision par(wbcap,maxset)
integer weistr(2,maxlay,2)
integer nlay,nset
integer wb_end, wb_end_rec
integer nset_rec
character*64 fname
integer k,k_rec
fname=trim(nnrecfile) // '.rec'
wb_end=weistr(2,nlay,2)
write(6,'(A)') 'RECORD: Reading record from file '''
> // trim(fname) // '''...'
open(nnunit,file=trim(fname),action='READ')
read(nnunit,*) nset_rec
if (nset_rec.ne.nset) then
write(6,'(A)') 'ERROR: INCONSISTENT NUMBER OF PARAMETER SETS.'
write(6,'("(",I4," vs.",I4,")")')
stop 1
endif
read(nnunit,*) wb_end_rec
if (wb_end_rec.ne.wb_end) then
write(6,'(A)') 'ERROR: INCONSISTENT NUMBER OF PARAMETER SETS.'
write(6,'("(",I4," vs.",I4,")")')
stop 1
endif
do k=1,nset
read(nnunit,*) k_rec, par(1:wb_end,k)
if (k.ne.k_rec) then
write(6,'(A,I05,A)') 'ERROR: MISSING PARAMETER SET: ', k
write(6,'(A,I05,A)') 'FOUND ', k_rec, ' INSTEAD'
stop 1
endif
enddo
close(nnunit)
write(6,'(A,I5)') 'Done. Read ',nset, ' parameter sets in total.'
end

50
src/params.incl Normal file
View File

@ -0,0 +1,50 @@
*** nstat: number of electronic states [maxnout] ***
*** nmeta: max. number of metadata output values [maxnout] ***
*** such as CI coefficients etc ***
integer nstat, nmeta
integer maxoutp
integer dnlen
integer maxlines,llen
integer maxdat,clen
integer klen, maxkeys
integer maxerrors
logical mprun
parameter (nstat=4, nmeta=20)
******************************************************************************
**** Inferred Parameters
***
*** maxoutp: max. number of output values.
parameter (maxoutp=nstat+nmeta)
******************************************************************************
**** I/O-Parameters
***
*** dnlen: maximum char length of data file path
*** maxlines: maximum input file length
*** llen: character maximum per line
*** maxdat: maximum number of input data values of one kind
*** (e.g. integer values) excluding DATA:-block
*** clen: max. character length of string data
*** klen: maximum length of key or typestring
*** maxkeys: max. number of keys
*** maxerrors: max. number of pre-defined error messages.
parameter (dnlen=8192)
parameter (maxlines=300000,llen=750)
parameter (klen=32,maxkeys=200)
parameter (maxdat=10000,clen=1024)
parameter (maxerrors=100)
******************************************************************************
**** OpenMP-Parameters
***
*** mprun: true if openmp is used.
parameter (mprun=.true.)
! parameter (mprun=.false.)

32
src/parser/errcat.incl Normal file
View File

@ -0,0 +1,32 @@
**** ERROR CATALOGUE -- this defines what kind of errors parse.f throws
! 1 32 64
! v v v
! '................................................................'
errcat( 1)='ILLOGICALLY SMALL VALUE'
errcat( 2)='VALUE EXCEEDS SET MAXIMUM'
errcat( 3)='GIVEN DATA STRUCTURE SIZE INCONSISTENT WITH'
> // ' PREVIOUS DECLARATION'
errcat( 4)='IMPLIED NEURON NUMBER INCONSISTENT WITH NEUPOP'
errcat( 5)='VALUE LESS THAN SET MINIMUM'
errcat( 6)='IMPLIED DATA POINT NUMBER INCONSISTENT WITH NPAT'
errcat( 7)='PERCENTAGE NOT WITHIN MEANINGFUL RANGE (0.0-100.0)'
errcat( 8)='MISSING KEY CLASHES WITH PREVIOUS DECLARATION'
errcat( 9)='MAXIMUM IDENTICAL TO MINIMUM'
errcat(10)='DEPRECATED COMMAND: FEATURE HAS BEEN REMOVED, '
> // 'SEE PARSER.'
! errcat(11)=
! errcat(12)=
! errcat(13)=
! errcat(14)=
! errcat(15)=
! errcat(16)=
! errcat(17)=
! errcat(18)=
! errcat(19)=
! errcat(20)=
! errcat(21)=
! errcat(22)=
! errcat(23)=
! errcat(24)=

309
src/parser/keylist.incl Normal file
View File

@ -0,0 +1,309 @@
**** KEYLIST -- this defines what kind of keys genANN is able to process syntactially
keylist=' '
! The only "special" key in the sense that it terminates input
keylist(1, 1)='DATA:'
keylist(2, 1)='E!'
keylist(1, 2)='SEED:'
keylist(2, 2)='+I1'
keylist(1, 3)='NSET:'
keylist(2, 3)='+I1'
keylist(1, 4)='SETS:'
keylist(2, 4)='+IN'
keylist(1, 5)='NPAT:'
keylist(2, 5)='+I1'
keylist(1, 6)='NPOINTS:'
keylist(2, 6)='+IN'
keylist(1, 7)='VALIDATION:'
keylist(2, 7)='+I1'
keylist(1, 8)='RANDOM:'
keylist(2, 8)='E'
keylist(1, 9)='FREEZE:'
keylist(2, 9)='E'
keylist(1,10)='DRYRUN:'
keylist(2,10)='E'
keylist(1,11)='RECORD:'
keylist(2,11)='C1'
keylist(1,12)='NLAY:'
keylist(2,12)='+I!1'
keylist(1,13)='NEUPOP:'
keylist(2,13)='+I!N'
keylist(1,14)='TYPOP:'
keylist(2,14)='+I!N'
keylist(1,15)='DEPRECATED:'
keylist(2,15)='E'
keylist(1,16)='DEPRECATED:'
keylist(2,16)='E'
keylist(1,17)='INPUTS:'
keylist(2,17)='+I1'
keylist(1,18)='OUTPUTS:'
keylist(2,18)='+I1'
keylist(1,19)='MAXFAILS:'
keylist(2,19)='+I1'
keylist(1,20)='NOMAXFAILS:'
keylist(2,20)='E'
keylist(1,21)='REFFAILS:'
keylist(2,21)='+I1'
keylist(1,22)='NOREFFAILS:'
keylist(2,22)='E'
keylist(1,23)='DEPRECATED:'
keylist(2,23)='E'
keylist(1,24)='MICIT:'
keylist(2,24)='+I1'
keylist(1,25)='MAXBPIT:'
keylist(2,25)='+I1'
keylist(1,26)='GSPREAD:'
keylist(2,26)='+D1'
keylist(1,27)='WSPREAD:'
keylist(2,27)='+D1'
keylist(1,28)='BSPREAD:'
keylist(2,28)='+D1'
keylist(1,29)='HART2EV:'
keylist(2,29)='E'
keylist(1,30)='HART2ICM:'
keylist(2,30)='E'
keylist(1,31)='ARBUNITS:'
keylist(2,31)='+D1'
keylist(1,32)='UCUSTOM:'
keylist(2,32)='C2'
keylist(1,33)='RMSOPT:'
keylist(2,33)='+D1'
keylist(1,34)='MINGRAD:'
keylist(2,34)='+D1'
keylist(1,35)='MINWBSTEP:'
keylist(2,35)='+D1'
keylist(1,36)='DEPRECATED:'
keylist(2,36)='E'
keylist(1,37)='ECHO:'
keylist(2,37)='CN'
keylist(1,38)='ERRCUT:'
keylist(2,38)='DN'
keylist(1,39)='CUTWT:'
keylist(2,39)='+DN'
keylist(1,40)='INSHIFT:'
keylist(2,40)='DN'
keylist(1,41)='INSCALE:'
keylist(2,41)='DN'
keylist(1,42)='NORMINP:'
keylist(2,42)='E'
keylist(1,43)='ZERO:'
keylist(2,43)='E'
keylist(1,44)='VALPER:'
keylist(2,44)='+D1'
keylist(1,45)='DEPRECATED:'
keylist(2,45)='E'
keylist(1,46)='RUNCHUNK:'
keylist(2,46)='+I2'
keylist(1,47)='RUNFROM:'
keylist(2,47)='+I1'
keylist(1,48)='RUNTO:'
keylist(2,48)='+I1'
keylist(1,49)='LEGACY-WT:'
keylist(2,49)='E'
keylist(1,50)='INCLUDE-DATA:'
keylist(2,50)='C1'
keylist(1,51)='NOSCANWALK:'
keylist(2,51)='E'
keylist(1,52)='LAMBDA:'
keylist(2,52)='+D1'
keylist(1,53)='MQFACT:'
keylist(2,53)='+D1'
! keylist(1,54)=
! keylist(2,54)=
!
! keylist(1,55)=
! keylist(2,55)=
!
! keylist(1,56)=
! keylist(2,56)=
!
! keylist(1,57)=
! keylist(2,57)=
!
! keylist(1,58)=
! keylist(2,58)=
!
! keylist(1,59)=
! keylist(2,59)=
!
! keylist(1,60)=
! keylist(2,60)=
! keylist(1,61)=
! keylist(2,61)=
!
! keylist(1,62)=
! keylist(2,62)=
!
! keylist(1,63)=
! keylist(2,63)=
!
! keylist(1,64)=
! keylist(2,64)=
!
! keylist(1,65)=
! keylist(2,65)=
!
! keylist(1,66)=
! keylist(2,66)=
!
! keylist(1,67)=
! keylist(2,67)=
!
! keylist(1,68)=
! keylist(2,68)=
!
! keylist(1,69)=
! keylist(2,69)=
!
! keylist(1,70)=
! keylist(2,70)=
!
! keylist(1,71)=
! keylist(2,71)=
!
! keylist(1,72)=
! keylist(2,72)=
!
! keylist(1,73)=
! keylist(2,73)=
!
! keylist(1,74)=
! keylist(2,74)=
!
! keylist(1,75)=
! keylist(2,75)=
!
! keylist(1,76)=
! keylist(2,76)=
!
! keylist(1,77)=
! keylist(2,77)=
!
! keylist(1,78)=
! keylist(2,78)=
!
! keylist(1,79)=
! keylist(2,79)=
!
! keylist(1,80)=
! keylist(2,80)=
!
! keylist(1,81)=
! keylist(2,81)=
!
! keylist(1,82)=
! keylist(2,82)=
!
! keylist(1,83)=
! keylist(2,83)=
!
! keylist(1,84)=
! keylist(2,84)=
!
! keylist(1,85)=
! keylist(2,85)=
!
! keylist(1,86)=
! keylist(2,86)=
!
! keylist(1,87)=
! keylist(2,87)=
!
! keylist(1,88)=
! keylist(2,88)=
!
! keylist(1,89)=
! keylist(2,89)=
!
! keylist(1,90)=
! keylist(2,90)=
!
! keylist(1,91)=
! keylist(2,91)=
!
! keylist(1,92)=
! keylist(2,92)=
!
! keylist(1,93)=
! keylist(2,93)=
!
! keylist(1,94)=
! keylist(2,94)=
!
! keylist(1,95)=
! keylist(2,95)=
!
! keylist(1,96)=
! keylist(2,96)=
!
! keylist(1,97)=
! keylist(2,97)=
!
! keylist(1,98)=
! keylist(2,98)=
!
! keylist(1,99)=
! keylist(2,99)=
do j=1,maxkeys
if (keylist(1,j)(1:1).eq.' ') then
keynum=j-1
write(6,'("Number of accepted input keys: ",I3)') keynum
exit
endif
enddo

265
src/parser/nndata_new.f Normal file
View File

@ -0,0 +1,265 @@
! This is a rewrite of the original nndata. Consider debugging it.
!---------------------------------------------------------------------------
subroutine nndata(infile,pat_in,pat_out,ref_in,ref_out,wterr,
> dat_start,linenum,npat,nref,llen)
implicit none
! Routine reading DATA-block.
! If npat is nonzero, only the first npat pattern pairs are read.
!
! infile: input file as string vector
! infile(n) nth line of input file
! linenum: number of lines in input file
! dat_start: starting position of DATA-block
! llen: maximum length of a single input line
!
!.....ANN-specific variables
! nlay: number of given layers
! npat: number of given pattern pairs
! nref: number of reference patterns
! wterr: weight factors for each element of the error vector e
!
! pat_in: input patterns
! pat_out: desired output patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
!
! ref_*: in analogy to pat_in/out for reference data (convergence tests)
!
! expected format (for one pattern pair):
!.. y1 x1 x2 x3 ... xM
!.. y2 x1 x2 x3 ... xM
!.. .. .. .. .. ... ..
!.. yN x1 x2 x3 ... xM
!..
!.. WT: w1 w2 ... wN
!
!... wt-legacy mode format:
!.. y1 x1 x2 x3 ... xM
!.. WT: w1
!.. y2 x1 x2 x3 ... xM
!.. WT: w2
!.. .. .. .. .. ... ..
!.. yN x1 x2 x3 ... xM
!.. WT: wN
!
! where N=inp_out and M=inp_in
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision pat_in(maxnin,maxpats),pat_out(maxpout,maxpats)
double precision ref_in(maxnin,maxpats),ref_out(maxpout,maxpats)
double precision wterr(maxpout,maxpats)
integer npat,nref,dat_start,linenum,llen
character infile(*)*(llen)
double precision norm
double precision xtest(maxnin)
integer pat_count,line
integer yval_count
integer k,j
pat_count=1
! count the lines of y-values. inp_out y-values = 1 pattern
yval_count=0
! We will initialize wterr for each new pattern.
wterr(1:inp_out,1)=1.0D0
do line=dat_start,linenum
! Treat WT: lines differently
if (infile(line)(1:3).eq.'WT:') then
if (yval_count.eq.0) then
write(6,'(A)') 'ERROR: WT: KEY PRECEDES ACTUAL DATA.'
write(6,'("(Line #",I06,")")') line
stop ec_read
else if (legacy_wt) then
read(in(line)(4:llen),*,err=515,end=514)
> wterr(yval_count,pat_count)
cycle
514 write(6,419) pat_count
write(6,'(A)') '(broken WT: input)'
stop ec_read
515 write(6,418) pat_count
write(6,'(A)') 'LINE DUMP:'
write(6,'(A)') trim(in(line)(4:llen))
stop ec_read
else if (yval_count.eq.inp_out) then
read(infile(line)(4:llen),*,err=511,end=508)
> wterr(1:inp_out,pat_count)
cycle
508 write(6,419) pat_count
write(6,'(A)') '(broken WT: input)'
stop ec_read
511 write(6,418) pat_count
write(6,'(A)') 'LINE DUMP:'
write(6,'(A)') trim(in(line)(4:llen))
stop ec_read
else
write(6,'(A)') 'ERROR: UNEXPECTED WT: KEY'
write(6,'(A)') 'Consider using LEGACY-WT:.'
stop ec_read
endif
cycle
endif
! Check whether a new pattern begins
if (yval_count.lt.inp_out) then
yval_count=yval_count+1
else
! If npat patterns are completed, finish
if (pat_count.eq.npat) then
exit
endif
if (pat_count.ge.maxpats) then
write(6,418) pat_count,maxpats
stop ec_dimrd
endif
pat_count=pat_count+1
yval_count=1
wterr(1:inp_out,pat_count)=1.0D0
endif
! Read line
read(infile(line)(1:llen),*,err=513,end=510)
> pat_out(yval_count,pat_count),xtest(1:inp_in)
! I CAN DO DATA TRANSFORM HERE
! BY TRANSFORMING PAT_OUT INTO THE DESIRED SHAPE
! TRANSFORM DATA TO ADIABATIC REPRESANTATION.
! Copy x vector from first entry.
! Compare all others to first.
if (yval_count.eq.1) then
pat_in(1:inp_in,pat_count)=xtest(1:inp_in)
else if (
> any(xtest(1:inp_in).ne.pat_in(1:inp_in,pat_count))
> ) then
write(6,421) pat_count, line
write(6,'(A)') '(x values inconsistent with '
> //'previous line)'
stop ec_read
endif
cycle
510 write(6,419) pat_count
stop ec_read
513 write(6,421) pat_count, line
write(6,'(A)') 'LINE DUMP:'
write(6,'(A)') trim(in(line)(1:llen))
stop ec_read
enddo
! Did the data file end abruptly?
if (yval_count.ne.inp_out) then
write(6,419) pat_count
write(6,'(A)') '(Unexpected EOF)'
stop ec_read
endif
! pat_count is now actual number of patterns
if (pat_count.le.0) then
write(6,419) 1
stop ec_read
else if (npat.le.0) then
! set npat dynamically
npat=pat_count
else if (npat.ne.pat_count) then
write(6,420) npat,pat_count
stop ec_read
endif
! Rescale weights based on a predefined scheme
call mkweights(wterr,npat,pat_out)
! Split current dataset into actual fitting sets and reference
call mkrefset_tail(pat_in,pat_out,ref_in,ref_out,npat,nref)
norm=0.0D0
! normalize weights of fitting data
do k=1,npat
do j=1,inp_out
wterr(j,k)=dabs(wterr(j,k))
norm=norm+wterr(j,k)
enddo
enddo
do k=1,npat
wterr(1:inp_out,k)=wterr(1:inp_out,k)/norm
enddo
norm=0.0D0
! normalize weights of reference data
do k=npat+1,npat+nref
do j=1,inp_out
wterr(j,k)=dabs(wterr(j,k))
norm=norm+wterr(j,k)
enddo
enddo
do k=npat+1,npat+nref
wterr(1:inp_out,k)=wterr(1:inp_out,k)/norm
enddo
417 format('ERROR: CORRUPTED WEIGHT INPUT (SET #',I9,')')
418 format('ERROR: NPAT EXCEEDING MAXPATS (',I9,' vs.',I9,')')
419 format('ERROR: INCOMPLETE OR MISSING DATA SET. SET #',I9)
420 format('ERROR: NUMBER OF DATA POINTS INCONSISTENT WITH NPAT CARD',
> '(',I9,' vs.',I9,')')
421 format('ERROR: CORRUPTED DATA POINT INPUT (SET #',I9,', LINE,',
> I9,')')
end
!---------------------------------------------------------------------------
subroutine infer_npat(infile,dat_start,linenum,npat,llen)
implicit none
! Count the number of input patterns the DATA block has if it is
! free of errors. No safety checks are done here as they are done
! later.
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision pat_in(maxnin,maxpats),pat_out(maxpout,maxpats)
double precision ref_in(maxnin,maxpats),ref_out(maxpout,maxpats)
double precision wterr(maxpout,maxpats)
integer npat,nref,dat_start,linenum,llen
character infile(*)*(llen)
double precision norm
double precision xtest(maxnin)
integer pat_count,line,line_count
logical dvecne
integer k,j
pat_count=0
line=dat_start !count lines
line_count=0
do line=dat_start,linenum
if (in(line)(1:3).eq.'WT:') then
cycle
else
line_count=line_count+1
endif
enddo
pat_count=line_count/inp_out
! set npat dynamically
npat=pat_count
if (npat.gt.maxpats) then
write(6,500) npat,maxpats
stop ec_dimrd
endif
500 format('ERROR: NPAT EXCEEDING MAXPATS (',I9,' vs.',I9,')')
end

160
src/parser/parse_errors.f Normal file
View File

@ -0,0 +1,160 @@
module parse_errors
implicit none
contains
!--------------------------------------------------------------------------------
subroutine signal_p_error(key_id,msg)
! Signal generic error with user-defined message MSG.
implicit none
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
integer key_id
character*(*) msg
write(6,'(A)') 'ERROR: ' // trim(keylist(1,key_id))
> // ' ' // trim(msg)
stop 1
end subroutine
!--------------------------------------------------------------------------------
subroutine signal_dim_error(key_id,msg_code,value,expval)
! Signals errors where one specific dimensioning value is ill-set.
! If the optional parameter EXPVAL is given, return it as expected
! dimensioning value.
implicit none
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
integer key_id, msg_code, value
integer, optional :: expval
! optional expval
character*16 int2string
write(6,'(A)') 'ERROR: ' // trim(keylist(1,key_id))
> // ' ' // trim(errcat(msg_code))
write(6,'(A)') 'OFFENDING VALUE: ' // trim(int2string(value))
if (present(expval)) then
write(6,'(A)') 'EXPECTED: ' // trim(int2string(expval))
endif
stop ec_dim
end subroutine
!--------------------------------------------------------------------------------
subroutine signal_log_error(key_id,msg_code,alt_key)
! Signals errors where contradictory settings are provided which
! the program cannot resolve. If the optional parameter ALT_KEY
! is given, name the explicit key current settings clash with.
implicit none
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
integer key_id
integer, optional :: alt_key
integer msg_code
! optional expval
write(6,'(A)') 'ERROR: ' // trim(keylist(1,key_id))
> // ' ' // trim(errcat(msg_code))
if (present(alt_key)) then
write(6,'(A)') 'OFFENDING KEY: ' // trim(keylist(1,alt_key))
endif
stop ec_log
end subroutine
!--------------------------------------------------------------------------------
subroutine signal_val_error(key_id,msg_code,value,expval)
! Signals errors where a given value makes no sense in it's given context.
! If the optional parameter EXPVAL is given, return it as expected
! dimensioning value.
implicit none
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
integer key_id, msg_code, value,expval
optional expval
character*16 int2string
write(6,'(A)') 'ERROR: ' // trim(keylist(1,key_id))
> // ' ' // trim(errcat(msg_code))
write(6,'(A)') 'OFFENDING VALUE: ' // trim(int2string(value))
if (present(expval)) then
write(6,'(A)') 'EXPECTED: ' // trim(int2string(expval))
endif
stop ec_read
end subroutine
!--------------------------------------------------------------------------------
subroutine signal_dval_error(key_id,msg_code,value,expval)
! Signals errors where a given value makes no sense in it's given context.
! If the optional parameter EXPVAL is given, return it as expected
! dimensioning value.
implicit none
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
integer key_id
double precision value,expval
integer msg_code
optional expval
character*16 shortdble2string
write(6,'(A)') 'ERROR: ' // trim(keylist(1,key_id))
> // ' ' // trim(errcat(msg_code))
write(6,'(A)') 'OFFENDING VALUE: '
> // trim(shortdble2string(value))
if (present(expval)) then
write(6,'(A)') 'EXPECTED: ' // trim(shortdble2string(expval))
endif
stop ec_read
end subroutine
end module
!--------------------------------------------------------------------------------
subroutine signal_meta_error(key_id,msg_code)
! Signals errors where a key (or key combinations) is/are not
! supported or maintained for reasons outside of the program's
! scope (e.g.: deprecation).
implicit none
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
integer key_id,msg_code
write(6,'(A)') 'ERROR: ' // trim(keylist(1,key_id))
> // ' ' // trim(errcat(msg_code))
stop ec_read
end subroutine

1628
src/parser/parser.f Normal file

File diff suppressed because it is too large Load Diff

822
src/puNNch.f Normal file
View File

@ -0,0 +1,822 @@
************************************************************************
*** puNNch
*** printing (punching) ANN data structures
***
************************************************************************
subroutine punch_data(pat_in,pat_out,npat,append)
implicit none
! Subroutine generating geNNetic DATA: block for ANN fitting.
!
! nlay: number of given layers
! npat: number of pattern-pairs desired
! pat_in: input patterns
! pat_out: desired output patterns
! inp_in: number of coordinates written into input.
! inp_out: number of values written to output
!
! inp_format: format used for datapoints
! scans_fmt: format used for sample-visualisation-file
! nndatfile: filename for analytically generated DATA-blocks
! (see nnparams)
! append: if true, append to given file if it exists
include 'nnparams.incl'
include 'nndbg.incl'
include 'nncommon.incl'
double precision pat_in(maxnin,*),pat_out(maxpout,*)
integer npat
logical append
character*16 inp_format,scans_fmt
character*35 full_fname
logical alive
integer k,j
if (inp_in.ge.10**6) then
stop 'ERROR: NUMBER OF COORDINATES TOO LARGE TO HANDLE'
endif
! generate format string
write(inp_format,'(I6,A7)') inp_in+1,'ES23.14'
inp_format = '(' // trim(inp_format) // ')'
full_fname = trim(nndatfile) // '.in'
write(6,'(A)') "generating DATA-file '" // trim(full_fname)
> // "'..."
! write file
if (.not.append) then
open(nnunit,file=trim(full_fname),status='REPLACE')
else
inquire(file=trim(full_fname),exist=alive)
if (alive) then
! open existing file and append
open(nnunit,file=trim(full_fname),status='old',
> position='append')
else
! file does not exist; make it
open(nnunit,file=trim(full_fname),status='new')
endif
endif
write(nnunit,'(A5)') 'DATA:'
write(nnunit,*) ''
write(unit=nnunit,advance='no',fmt='("!")')
write(nnunit,sline)
write(nnunit,*) ''
do k=1,npat
do j=1,inp_out
write(nnunit,inp_format) pat_out(j,k), pat_in(1:inp_in,k)
enddo
write(nnunit,'(A4)') '!WT:'
write(nnunit,*) ''
enddo
close(nnunit)
! generate sample format string
write(scans_fmt,'(I6,A7)') inp_in,'ES23.14'
scans_fmt = '(' // trim(scans_fmt) // ')'
! write file
open(nnunit,file=trim(sampfile),status='REPLACE')
write(6,'(A)') "dumping sampled points in '" // trim(sampfile)
> // "'..."
write(nnunit,'(A)') '# This file shows all sampled points in '
> // 'the given configuration space.'
do k=1,npat
write(nnunit,scans_fmt) pat_in(1:inp_in,k)
enddo
close(nnunit)
end subroutine
!--------------------------------------------------------------------------------------
subroutine punch_net(funit,fname,par,
> typop,laystr,weistr,nlay,append,noprim)
implicit none
! Subroutine writing all relevant structural NN information
! to file.
!
! funit: file unit to be used. If negative or 0, use nnunit.
! fname: name of the file
! append: if true, append to given file if it exists
! noprim: if true, do not generate primitive representation
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
character*32 fname
double precision par(wbcap)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
integer funit
logical append, noprim
integer file_unit
integer wbnum,plen
integer nnkeynum
character*35 full_fname
character*(klen) nnkeylist(2,maxnnkeys)
logical alive
integer j
if (funit.le.0) then
file_unit=nnunit
else
file_unit=funit
endif
full_fname = trim(fname) // '.in'
if (.not.append) then
open(file_unit,file=trim(full_fname),status='replace')
else
inquire(file=trim(full_fname),exist=alive)
if (alive) then
! open existing file and append
open(file_unit,file=trim(full_fname),status='old',
> position='append')
else
! file does not exist; make it
open(file_unit,file=trim(full_fname),status='new')
endif
endif
! recover information to construct ANN
write(file_unit,'("NLAY:",I4)') nlay
write(file_unit,'(/,"NEUPOP:",100(I6,:))') laystr(1,1:nlay)
write(file_unit,'("TYPOP:",100(I6,:),//)') typop(:,2:nlay)
write(file_unit,'(A)') 'INSHIFT: &'
call write_longreal(file_unit,shift_in,len_in,lrfmt,5)
write(file_unit,'(A)') 'INSCALE: &'
call write_longreal(file_unit,fact_in,len_in,lrfmt,5)
! write out parameter set
write(file_unit,'(A)') '!.....NEURAL NETWORK PARAMETERS:'
! number of weights (and biases)
wbnum=nlay-1
! construct keys
call NNkeygen(nnkeylist,nnkeynum,nlay,.false.)
! write weight matrices
do j=1,wbnum
write(file_unit,newline)
write(file_unit,'(A," &")') trim(nnkeylist(1,1+j))
plen=1+weistr(2,j,1)-weistr(1,j,1)
call write_longreal(file_unit,par(weistr(1,j,1)),plen,lrfmt,5)
enddo
! write bias vectors
do j=1,wbnum
write(file_unit,newline)
write(file_unit,'(A," &")') trim(nnkeylist(1,1+wbnum+j))
plen=1+weistr(2,j+1,2)-weistr(1,j+1,2)
call write_longreal(file_unit,par(weistr(1,j+1,2)),plen,
> lrfmt,5)
enddo
close(file_unit)
if (.not.noprim) then
call punch_net_prim(funit,fname,par,
> typop,laystr,weistr,nlay)
endif
end subroutine
!--------------------------------------------------------------------------------------
subroutine punch_net_prim(funit,fname,par,
> typop,laystr,weistr,nlay)
use axel, only: unnorm_input
implicit none
! Subroutine writing all relevant structural NN information
! to a primitively readable file. The resulting parameters no longer
! assume a pre-normalized input
!
! funit: file unit to be used. If negative or 0, use nnunit.
! fname: name of the file
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
character*32 fname
double precision par(*)
integer funit
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
character*36 full_fname
double precision par_copy(wbcap)
integer par_pos,par_end,par_len
integer file_unit
integer j
if (funit.le.0) then
file_unit=nnunit
else
file_unit=funit
endif
full_fname = trim(fname) // '.par'
open(file_unit,file=trim(full_fname),status='replace')
par_pos=weistr(1,1,1)
par_end=weistr(2,nlay,2)
par_len=1+par_end-par_pos
write(file_unit,*) nlay
write(file_unit,*) maxtypes
write(file_unit,'(100(I6,:))') laystr(1,1:nlay)
write(file_unit,'(100(I6,:),//)') typop(:,1:nlay)
write(file_unit,'(A)') '***'//trim(prim_tag)
! copy parameter set and unddo norm
do j=par_pos,par_end
par_copy(1+j-par_pos)=par(j)
enddo
call unnorm_input(par_copy,laystr,shift_in,fact_in,weistr,.true.)
! write par-vector
do j=1,par_len
write(unit=file_unit,fmt=lrfmt,advance='NO') par_copy(j)
enddo
close(file_unit)
end subroutine
!--------------------------------------------------------------------------------------
subroutine punch_scans(pat_in,pat_out)
implicit none
! Subroutine writing plot files for random scans from input.
! pat_in: input patterns
! pat_out: desired output patterns
! inp_in: number of coordinates written into input.
! inp_out: number of values written to output
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision pat_in(maxnin,*),pat_out(maxpout,*)
integer total
character*64 fname
integer k,j
if (sets.ge.10**4) then
write(6,'(A)') 'WARNING: punch_scans: Too many scan files'
> // ' to generate.'
write(6,'(A)') 'Garbage file ' // trim(nnsdir)
> // '''scan_****.dat'' will be created.'
endif
! count number of data points written to file
total=0
do k=1,sets
! generate filename
write(fname,'(A32)') ''
write(fname,'(I4.4)') k
fname = trim(nnsdir) // 'scan_' // trim(fname) // '.dat'
if (dbg) write(*,*) 'writing ''' // trim(fname) // '''...'
open(unit=nnunit,status='replace',file=trim(fname))
! dump scan into file
do j=1,ndata(k)
total = total+1
write(nnunit,'(1000(ES23.15,:))') pat_in(1:inp_in,total),
> pat_out(1:inp_out,total)
enddo
close(nnunit)
enddo
end subroutine
!--------------------------------------------------------------------------------------
subroutine punch_fitscans(par,pat_in,pat_out,wterr,
> typop,laystr,weistr,
> nlay,walk)
implicit none
! Subroutine writing plot files for fitted random scans.
! For now only output in terms of diabatic energies is supported.
!
! walk: determines how coordinate-dependency is
! written to files
! true -- write scans as functions of t in [0,1] (walk along the scan)
! false -- dump full coordinate vector to file
!
! pat_in: input patterns
! pat_out: desired output patterns
! inp_in: number of coordinates written into input.
! inp_out: number of values written to output
!
! laystr: layer structure matrix
! typop: type population matrix
! nlay: number of given layers
!
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision par(*)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
double precision wterr(maxpout,maxpats)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
logical walk
double precision nnoutp(maxnout),adiaoutp(maxpout)
double precision max_err,err_vec(maxpout)
double precision x_diff(maxnin)
double precision walktime,walknorm
integer total
character*64 fname
integer k,j
integer end_int, bgn_int
! the coordianate in pat_in is order in the following way
! pat_In(INPUTS,INTERNAL COORDIANATE)
bgn_int = typop(1,1)+1 ! the begin of theinternal coordiante
end_int = typop(1,1)+6
if (sets.ge.10**4) then
write(6,'(A)') 'WARNING: punch_fitscans: Too many scan files'
> // ' to generate.'
write(6,'(A)') 'Garbage file ''' // trim(nnsdir)
> // 'fit_scan_****.dat'' will be created.'
endif
! count number of data points written to file
total=0
do k=1,sets
! generate filename
write(fname,'(A32)') ''
write(fname,'(I4.4)') k
fname = trim(nnsdir) // 'fit_scan_' // trim(fname) // '.dat'
if (dbg) write(*,*) 'writing ''' // trim(fname) // '''...'
open(unit=nnunit,status='replace',file=trim(fname))
if (walk) then
write(nnunit,'("# SCAN",I4.4,
>"[t,F(NN(x(t))),f(x(t)),NN(x(t)),We(x(t))]")') k
write(nnunit,'("# XDIM:",I6)') 1
else
write(nnunit,
> '("# SCAN",I4.4,"[x,F(NN(x)),f(x),NN(x),We(x)]")') k
write(nnunit,'("# XDIM:",I6)') inp_in
endif
write(nnunit,'("# OUTPUT VALUES:",I6)') inp_out
write(nnunit,'("# DATA POINTS:",I6,/)') ndata(k)
write(nnunit,'(A)') '# UNIT: ' // trim(unit_string)
walknorm=0.0d0
walktime=0.0d0
if (walk) then
do j=2,ndata(k)
x_diff(bgn_int:end_int)= pat_in(bgn_int:end_int,
> total+j) - pat_in(bgn_int:
> end_int,total+j-1)
walknorm=walknorm +dsqrt(sum(x_diff(bgn_int:end_int)**2))
enddo
endif
! dump scan into file
max_err=0
do j=1,ndata(k)
total = total+1
max_err=0.0d0
! generate model energies
nnoutp=0.0d0
call neunet(pat_in(1,total),nnoutp,par,
> typop,laystr,weistr,nlay)
call nnadia(pat_in(1,total),nnoutp,adiaoutp)
if (walk) then
if (j.eq.1) then
x_diff=0.0d0
else
x_diff(bgn_int:end_int)=
> pat_in(bgn_int:end_int,total)
> - pat_in(bgn_int:end_int,total-1)
endif
walktime = walktime
> + dsqrt(sum(x_diff(bgn_int:end_int)**2))/walknorm
write(nnunit,'(1000(ES23.15,:))') walktime,
> adiaoutp(1:inp_out)*unit_con,
> pat_out(1:inp_out,total)*unit_con,
> nnoutp(1:len_out),
> wterr(1:inp_out,total)
else
write(nnunit,'(1000(ES23.15,:))') pat_in(bgn_int:
> end_int,total),
> adiaoutp(1:inp_out)*unit_con,
> pat_out(1:inp_out,total)*unit_con,
> nnoutp(1:len_out),
> wterr(1:inp_out,total)
endif
err_vec=dabs(adiaoutp-pat_out(:,total))
max_err=max(max_err,sum(err_vec(1:inp_out)**2))
enddo
write(nnunit,'(/,"## SUP NORM:",E23.15,A)')
> dsqrt(max_err)*unit_con, trim(unit_string)
close(nnunit)
enddo
end subroutine
!--------------------------------------------------------------------------------------
subroutine punch_fitpoints(par,pat_in,pat_out,
> typop,laystr,weistr,nlay,npat,fname)
implicit none
! Subroutine dumping all reference data points into a single file.
! Also produces unweighted (!!) errors for each point
!
! nlay: number of given layers
! npat: number of given pattern pairs
! fname: name of output-file
!
! pat_in: input patterns
! pat_out: desired output patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
!
! del: neuron error vector
! pat_err: error of the network output for a single pattern
! deriv: activation function derivatives
! deriv: activation function derivatives
! typop: type population matrix
! laystr: layer structure matrix
!
include 'nnparams.incl'
include 'nndbg.incl'
include 'nncommon.incl'
integer npat
double precision par(*)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
character*32 fname
double precision nn_out(maxnout)
double precision pat_err(maxpout),abs_err
integer len_form
integer n,k
character*32 form
len_form=1+len_in+2*len_out !number of value blocks to be written
if (dbg.or.vbs) then
write(6,'(A)') 'dumping pointwise errors into '''
> // trim(fname) // '''...'
endif
open(unit=nnunit,status='replace',file=trim(fname))
write(nnunit,'(A)') '#DATA POINT DUMP '
> //'[x,NN(x),f(x),sqrt((F(NN)-f)^2)]'
write(form,'("(",I6,A,")")') len_form,'ES25.8'
do n=1,npat
! propagate nth input pattern
call neunet(pat_in(1,n),nn_out,par,typop,laystr,weistr,nlay)
! evaluate error
call nnerror(pat_err,pat_in(1,n),pat_out(1,n),nn_out)
abs_err=0.0D0
do k=1,inp_out
abs_err=abs_err+pat_err(k)**2
enddo
abs_err=dsqrt(abs_err)
!? valgrind does not like variable format strings
write(nnunit,'(10000(ES25.8,:))') pat_in(1:len_in,n),
> nn_out(1:len_out),
> pat_out(1:inp_out,n), abs_err
enddo
close(nnunit)
end subroutine
!--------------------------------------------------------------------------------------
subroutine punch_fitstat(fname,par,pat_in,pat_out,err_vec,npat,
> typop,laystr,weistr,
> nlay,append)
implicit none
! Subroutine providing a complete vector over all root mean square
! errors over all points from 1 to npat in a single file.
!
! This routine is used to construct errors_*.out files.
!
! fname: name of the file to be written
! pat_in: input patterns
! pat_out: desired output patterns
! npat: number of given pattern pairs
! inp_in: number of coordinates written into input.
! inp_out: number of values written to output
! err_vec: vector containing all abs. pattern errors (sorted)
! append: if true, append to given file if it exists
!
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
character*32 fname
integer npat
double precision par(wbcap)
double precision pat_in(maxnin,*),pat_out(maxpout,*)
double precision err_vec(npat)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
logical append
double precision pat_err(maxpout)
integer, dimension(:), allocatable :: err_pos
logical alive
integer n
if (.not.append) then
open(nnunit,file=trim(fname),status='replace')
else
inquire(file=trim(fname),exist=alive)
if (alive) then
! open existing file and append
open(nnunit,file=trim(fname),status='old',
> position='append')
write(nnunit,asline)
else
! file does not exist; make it
open(nnunit,file=trim(fname),status='new')
endif
endif
! accumulate errors to long vector
allocate(err_pos(maxpats))
do n=1,npat
call NNerrvec(par,pat_err,pat_in(1,n),pat_out(1,n),
> typop,laystr,weistr,nlay)
err_vec(n)=dsqrt(sum(pat_err(1:inp_out)**2))
err_pos(n)=n
enddo
! sort vector
call reverse_dqsort2(npat,err_vec,err_pos)
write(nnunit,'("#",A12,2A13)') 'RANK','ERROR [' //
> trim(unit_string) // ']','PAT#'
do n=1,npat
write(nnunit,'(I13,ES13.4,I13)') n, err_vec(n)*unit_con,
> err_pos(n)
enddo
close(nnunit)
deallocate(err_pos)
end subroutine
!--------------------------------------------------------------------------------------
subroutine punch_netdistrib(fdir,par,pat_in,typop,laystr,
> weistr,nlay,npat,ftag)
implicit none
! Subroutine evaluating the activity of all neurons for each data
! point. Also returns information about the network to construct it.
!
! fdir: directory for files to be written in
! pat_in: input patterns
! npat: number of given pattern pairs
! inp_in: number of coordinates written into input.
! inp_out: number of values written to output
! err_vec: vector containing all abs. pattern errors (sorted)
! ftag: prefix for generated filenames
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
character*16 fdir
integer npat
double precision par(wbcap)
double precision pat_in(maxnin,npat)
integer laystr(3,maxlay),typop(maxtypes,maxlay)
integer weistr(2,maxlay,2)
integer nlay
character*8 ftag
character*128 fname
double precision deriv(neucap),L(neucap)
double precision, dimension(:,:), allocatable :: neurons, derivs
double precision median(len_out), rec_scale(len_out)
integer med_pos(2)
integer lay_end,poslay
integer n,j
poslay=laystr(2,nlay)
lay_end=poslay-1+len_out
allocate(neurons(npat,len_out),derivs(npat,len_out))
! evaluate ANN for each pattern
do n=1,npat
L=0.0d0
deriv=0.0d0
call neunet_full(pat_in(1,n),L,deriv,par,
> typop,laystr,weistr,nlay)
neurons(n,1:len_out)=L(poslay:lay_end)
enddo
! compute location of median
if (1.eq.modulo(npat,2)) then
med_pos = (npat+1)/2
else
med_pos(1) = npat/2
med_pos(2) = med_pos(1) + 1
endif
do n=1,len_out
call dqsort(npat,neurons(1,n))
median(n)=(neurons(med_pos(1),n)+neurons(med_pos(2),n))/2.0d0
neurons(:,n)=neurons(:,n)
rec_scale(n)=(neurons(npat,n)-neurons(1,n))/2.0d0
enddo
! file containing the real ANN outputs
fname=trim(fdir)// trim(ftag) //'netdist-med.dat'
write(6,'(A)') 'Writing distribution of (shifted) '
> // 'ANN output values to ''' // trim(fname) // '''..'
open(nnunit,file=trim(fname),status='replace')
write(nnunit,'(A)') '# ANN OUTPUT VALUES'
write(nnunit,'(A)') '# SORT INDEX, OUTPUT NEURON(S) 1,2,.. ,'
> // ' (MINUS MEDIAN)'
write(nnunit,'(A,1000(F10.5,:))') '# Recommended rescaling: ',
> rec_scale(:)
write(nnunit,'(A,1000(F10.5,:))') '# Computed median: ',
> median(:)
do n=1,npat
write(nnunit,'(I11, 10000(ES11.2,:))') n,
> (neurons(n,j)-median(j), j=1,len_out)
enddo
close(nnunit)
! file containing outputs shifted by median
fname=trim(fdir)// trim(ftag) //'netdist.dat'
write(6,'(A)') 'Writing distribution of ANN output values '
> // 'to ''' // trim(fname) // '''..'
open(nnunit,file=trim(fname),status='replace')
write(nnunit,'(A)') '# ANN OUTPUT VALUES'
write(nnunit,'(A)') '# SORT INDEX, OUTPUT NEURON(S) 1,2,..'
write(nnunit,'(A,1000(F10.5,:))') '# Recommended rescaling: ',
> rec_scale(:)
write(nnunit,'(A,1000(F10.5,:))') '# Computed median: ',
> median(:)
do n=1,npat
write(nnunit,'(I11, 10000(ES11.2,:))') n, neurons(n,:)
enddo
close(nnunit)
deallocate(neurons,derivs)
end subroutine
!--------------------------------------------------------------------------------------
subroutine punch_record(par,weistr,nlay,nset,preserve)
implicit none
include 'params.incl'
include 'common.incl'
include 'nnparams.incl'
include 'nncommon.incl'
include 'nndbg.incl'
double precision par(wbcap,maxset)
integer weistr(2,maxlay,2)
integer nlay,nset
logical preserve
integer wb_end
logical file_exists
character*64 fname
integer k,j
fname=trim(nnrecfile) // '.rec'
wb_end=weistr(2,nlay,2)
if (preserve) then
inquire(file=trim(fname),exist=file_exists)
if (file_exists) then
! File exists already, try an alternative file name
write(6,'(A)') 'WARNING: File ''' //
> trim(fname) // ''' already exists.'
write(6,'(A)') 'Attempting to create an alternative file..'
k=1
do while ((k.le.99).and.file_exists)
write(fname,'("_",I2.2)') k
fname=trim(nnrecfile) // trim(fname) // '.rec'
inquire(file=trim(fname),exist=file_exists)
k=k+1
enddo
! File STILL exists?
if (file_exists) then
write(6,'(A)') 'WARNING: No safe backup could be made.'
fname=trim(nnrecfile) // '_XX.rec'
endif
endif
endif
write(6,'(A)') 'RECORD: Writing record to file '''
> // trim(fname) // '''...'
open(nnunit,file=trim(fname),action='WRITE')
write(nnunit,*) nset
write(nnunit,*) wb_end
do k=1,nset
write(nnunit,'(I0)',advance='no') k
do j=1,wb_end
write(nnunit,'(ES23.15)',advance='no') par(j,k)
enddo
write(nnunit,newline)
enddo
close(nnunit)
write(6,'(A)') 'Done.'
end subroutine

385
src/scans.f Normal file
View File

@ -0,0 +1,385 @@
!--------------------------------------------------------------------------------------
subroutine lscan_bounds(bounds,refp,dvec,xmin,xmax,dim,backwd)
implicit none
! Determine how far a scan can progress within a box-shaped boundary
! in terms of the length of the scan starting from the reference
! point.
!
! dim: dimension of coordinate space to be scanned
! xmin/max: minimum/maximum allowed value in each coordinate
! refp: reference point at which linear scan begins
! dvec: (normalized) vector pointing into the direction of the scan
! backwd: if true, evaluate boundary also in -dvec-direction
! bounds: maximum distance(s) from reference point
! bounds(1): in dvec-direction
! bounds(2): in -dvec-direction (default 0.0D0)
! res: resolution -- maximum error in bound estimates
include 'nnparams.incl'
integer dim
double precision refp(dim),dvec(dim)
double precision xmin(dim),xmax(dim)
double precision bounds(2)
logical backwd
double precision min_len,step_len,box_diag
integer j
! begin at a resolution of 10% the box diagonal
box_diag=0.0D0
do j=1,dim
box_diag=box_diag+(xmax(j)-xmin(j))**2
enddo
box_diag=sqrt(box_diag)
step_len=0.1D0*box_diag
min_len=0.0D0
do while (step_len.ge.scan_res)
! find lower boundary given current resolution
call lscan_estim_bound(min_len,step_len,refp,dvec,
> xmin,xmax,dim)
! refine resolution
step_len=0.5D0*step_len
enddo
bounds(1)=min_len
bounds(2)=0.0D0
if (backwd) then
! follow vector in a negative direction
step_len=-0.1D0*box_diag
min_len=0.0D0
do while (dabs(step_len).ge.scan_res)
! find lower boundary given current resolution
! this could be further numerically refined; since the step distance
! is halved, we know that no more than 1 step can be successful.
call lscan_estim_bound(min_len,step_len,refp,dvec,
> xmin,xmax,dim)
! refine resolution
step_len=0.5D0*step_len
enddo
bounds(2)=abs(min_len)
endif
end
!--------------------------------------------------------------------------------------
subroutine lscan_estim_bound(min_len,step_len,refp,dvec,xmin,xmax,
> dim)
implicit none
! Estimate a lower bound min_len for the length a linear scan can progress
! within a box-shaped boundary, given an inital guess which
! is also a lower bound and a step resolution step_len.
!
! dim: dimension of coordinate space to be scanned
! xmin/max: minimum/maximum allowed value in each coordinate
! refp: reference point at which linear scan begins
! dvec: (normalized) vector pointing into the direction of the scan
! min_len: estimate for minimal length of scan (will be overwritten
! with refined result)
! step_len: interval at which the algorithm checks for boundary violation
integer dim
double precision refp(dim),dvec(dim)
double precision xmin(dim),xmax(dim)
double precision step_len,min_len
double precision test_vec(dim)
logical in_bound
logical dbetween
integer j
in_bound=.true.
do while (.true.)
do j=1,dim
test_vec(j)=refp(j)+(min_len+step_len)*dvec(j)
in_bound=in_bound.and.dbetween(xmin(j),test_vec(j),xmax(j))
enddo
if (in_bound) then
min_len=min_len+step_len
else
exit
endif
enddo
end
!--------------------------------------------------------------------------------------
subroutine mkescans(pat_in,neu_in,npat,scans,xranges)
implicit none
! Generate input patterns for elliptic random scans. Datapoints
! on scans are arranged in concentric ellipsoids around the
! origin. The outermost ellipsoid is bounded by xranges(i,2) as it's
! principal axes. The innermost ellipsoid is the smallest one where
! no possible point violates the smallest allowed value in any
! dimension.
!
! For the sake of simplicity, the coordinate system is effectively
! rescaled such that the outer ellipsoid becomes a unit sphere
! and then transfomed back.
!
! npat: number points on the scan
! scans: number of scans
! pat_in: input patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
! rmin: radius of the smallest sphere enclosing all forbidden areas
! in the rescaled coordinate system
! len_step: radius step size for rescaled coordinate system
!
! xranges: range for (random) input distribution:
! |xranges(:,1)| < |pat_in(:,k)| < |xranges(i,2)| forall k
! xranges(i,3) : if it's absolute value is >=1,
! dimension i will always have the same sign as xranges(i,3).
include 'nnparams.incl'
include 'nndbg.incl'
integer npat,scans
integer neu_in
double precision xranges(maxnin,xrcap)
double precision pat_in(maxnin,npat,scans)
double precision rvec(maxnin)
double precision rmin,len_step
double precision dum
integer n,k,j
! rescale minimum distances such that corresponding
! outer ellipsoid transforms to a unit sphere and
! pick the largest of these minimal radii to actually use.
rmin=0.0d0
do k=1,neu_in
dum=dabs(xranges(k,1)/xranges(k,2))
if (dum.gt.rmin) rmin=dum
enddo
if (dbg.or.vbs) then
write(*,*) 'MINIMAL EFFECTIVE RADIUS:', rmin
endif
! evaluate step size
len_step=(1.0d0-rmin)/dble(npat-1)
do n=1,scans
! generate normalized isotropic random vector
call normal_grv(rvec,neu_in,1)
! adjust signs
do j=1,neu_in
if (dabs(xranges(j,3)).ge.1.0d0) then
rvec(j)=sign(rvec(j),xranges(j,3))
endif
enddo
do k=1,npat
do j=1,neu_in
! make equidistant steps along that direction
pat_in(j,k,n) = (rmin + (k-1)*len_step)*rvec(j)
! rescale
pat_in(j,k,n) = pat_in(j,k,n)*xranges(j,2)
enddo
enddo
enddo
! update npat to actual number of patterns
npat=npat*scans
end
!--------------------------------------------------------------------------------------
subroutine mklscan(pat_in,neu_in,npat,xranges)
implicit none
! Generate a single set of input patterns forming a single linear
! scan going through both specified points
!
! npat: number points on the scan
! pat_in: input patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
! xranges: starting point and end point of linear scan
! xranges(i,1) : starting point in coordinate space (r0)
! xranges(i,2) : end point in coordinate space (r1)
!
! dvec: direction vector pointing from r0 to r1.
include 'nnparams.incl'
include 'nndbg.incl'
double precision xranges(maxnin,xrcap)
double precision pat_in(maxnin,maxpats)
integer npat
integer neu_in
double precision dvec(maxnin)
integer n,j
! determine direction vector pointing from r0 to r1
do j=1,neu_in
dvec(j)=xranges(j,2)-xranges(j,1)
enddo
do n=1,npat
do j=1,neu_in
pat_in(j,n)=dble(n-1)/dble(npat-1)*dvec(j) + xranges(j,1)
enddo
enddo
end
!--------------------------------------------------------------------------------------
subroutine mklscans(pat_in,neu_in,npat,scans,xranges)
implicit none
! Generate input patterns for linear random scans inside a
! box-shaped coordinate subspace. Reference point is NOT included
! in the scan.
!
! npat: number points on the scan
! scans: number of scans
! pat_in: input patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
!
! xranges: ranges specifying scan properties (bounds etc)
! xranges(i,1) < pat_in(i,k) < xranges(i,2) forall i,k
! xranges(i,3) : reference point from which all scans originate
!
! res: convergence parameter for bound finding algorithm
include 'nnparams.incl'
include 'nndbg.incl'
integer npat,scans
integer neu_in
double precision xranges(maxnin,xrcap)
double precision pat_in(maxnin,npat,scans)
double precision bounds(2)
double precision rvec(neu_in)
double precision len_step
logical backwd
parameter (backwd=.false.)
integer n,k,j
do n=1,scans
! generate normalized isotropic random vector
call normal_grv(rvec,neu_in,1)
! numerically determine distance from box boundary
call lscan_bounds(bounds,xranges(1,3),rvec,
> xranges(1,1),xranges(1,2),neu_in,backwd)
! determine length of a single step
len_step=bounds(1)/dble(npat)
! generate scan
do k=1,npat
do j=1,neu_in
pat_in(j,k,n) = xranges(j,3) + len_step*dble(k)*rvec(j)
enddo
enddo
enddo
! update npat to actual number of patterns
npat=npat*scans
end
!--------------------------------------------------------------------------------------
subroutine mktscans(pat_in,neu_in,npat,scans,xranges)
implicit none
! Generate scans touching a sphere of fixed width and origin
! with random orientation. They are bounded within a box
! defined by xranges.
!
! npat: number points on the scan
! scans: number of scans
! pat_in: input patterns
! pat_*(i,N): value of ith in-/output neuron for pattern N
!
! xranges: ranges specifying scan properties (bounds etc)
! xranges(i,1) < pat_in(i,k) < xranges(i,2) forall i,k
! xranges(i,3) : center of the sphere
! xranges(1,4) : radius of the sphere
include 'params.incl'
include 'nnparams.incl'
include 'nndbg.incl'
integer npat,scans
integer neu_in
double precision pat_in(maxnin,npat,scans)
double precision xranges(maxnin,xrcap)
double precision rvec(maxnin),rtang(maxnin)
double precision rtnorm,overlap,radius
double precision bounds(2),len_step
logical backwd
parameter (backwd=.true.)
integer n,k,j
! determine radius of the sphere
radius=xranges(1,4)
do n=1,scans
! generate normalized isotropic random vector
call normal_grv(rvec,neu_in,1)
! generate another one orthogonal to the first using
! Grahm-Schmidt
rtnorm=0.0D0
do while (rtnorm.le.zero)
call normal_grv(rtang,neu_in,1)
rtnorm=0.0D0
overlap=dot_product(rvec(1:neu_in),rtang(1:neu_in))
do j=1,neu_in
rtang(j)=rtang(j)-overlap*rvec(j)
rtnorm = rtnorm + rtang(j)**2
enddo
rtnorm=dsqrt(rtnorm)
enddo
! reposition and scale rvec to rest on the desired sphere
! normalize rtang
do j=1,neu_in
rvec(j)=radius*rvec(j) + xranges(j,3)
rtang(j)=rtang(j)/rtnorm
enddo
! numerically determine distance from box boundary in both
! directions
call lscan_bounds(bounds,rvec,rtang,
> xranges(1,1),xranges(1,2),neu_in,backwd)
! determine step length
len_step=(bounds(1)+bounds(2))/dble(npat-1)
! set the scan to begin at an end point instead of in the middle
! of the tangent
do j=1,neu_in
rvec(j)=rvec(j)-rtang(j)*bounds(2)
enddo
! generate random scan
do k=1,npat
do j=1,neu_in
pat_in(j,k,n) = rvec(j) + len_step*dble(k-1)*rtang(j)
enddo
enddo
enddo
! evaluate true number of patterns
npat=npat*scans
end