Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added make0-related stuff and wrappers #29

Merged
merged 1 commit into from
May 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions devel_tools/adjoints/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
In order to translate a subroutine modify the three subroutin below in /src:
makefun_bumb.f90
makefun.f90
makefun_pbc.f90

Execute in the present directory:
command_bump.sh for makefun_bumb.f90
command.sh for makefun.f90
command_pbc.sh for makefun_pbc.f90

the three scripts will copy the corresponding
makefun*_b.f90
files into the directory:
trunk/AD/reverse_cell/

After that execute

./make0branch

This will create makefun*0 and correspondin makefun*0_b for length 1 loop

and TurboRVB is ready to work for computing forces.

THE PART BELOW IS NECESSARY ONLY IF SOMETHING WENT WRONG.
You should check by hand if the actions below were correctly handled by the
scripts.

#######################################
The following part is automatically executed by the scripts.
Be careful using command_pbc:
the input variables
cellscale,sinphase,cosphase,rphase
are added, in the subroutine arguments, after:
,c,rmucos,rmusin)
If these variables will be changed, the script command_pbc
will not work correctly.
#######################################



NB for makefun_pbc.f90

There is a little more work before execution in this case:

Remove the lines 5-6, namely:
use Cell, only:cellscale
use mod_twisted, only:sinphase,cosphase,rphase

add as input variables:

cellscale,sinphase,cosphase,rphase)

and define them with the two lines:

double precision, intent(in) :: cellscale(3),rphase(3)
double precision :: sinphase(3,nion,0:indtm),cosphase(nion,0:indtm)

END NB for makefun_pbc.f90



After execution in the directory /output:

Edit the corresponding make*_b.f90 file and:

Replace : USE NAMEMODULE_B ---> USE NAMEMODULE
e.g. (USE CONSTANTS_B --> USE CONSTANTS).

Then edit the *_b.f90 file and add the following two lines:

integer :: adi4ibuf,adr8ibuf,adi4buf(1024)
real*8 :: adr8buf(1024)


Also before the line:

SELECT CASE (iopt)

add two lines:

adi4ibuf=1
adr8ibuf=1


Finally copy the modified *_b.f90 file from the
AD/compmake/output directory to the AD/reverse_cell directory.


At the en

Then it should work.




40 changes: 40 additions & 0 deletions devel_tools/adjoints/make0branch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright (C) 2022 TurboRVB group
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Otto Kohulák created on 5th Nov. 2021.

# copy in the present directory makefuns
cp ../../src/makefun.f90 .
cp ../../AD/reverse_cell/makefun_b.f90 .
cp ../../src/makefun_pbc.f90 .
cp ../../AD/reverse_cell/makefun_pbc_b.f90 .
cp ../../src/makefun_bump.f90 .
cp ../../AD/reverse_cell/makefun_bump_b.f90 .

# process the mkefuns
python preprocess.py -c makefun0:[i0=0,indtmin=0,indtm=0] -o makefun0.f90 makefun.f90
python preprocess.py -c makefun0_b:[i0=0,indtmin=0,indtm=0] -o makefun0_b.f90 makefun_b.f90
python preprocess.py -c makefun0_pbc:[i0=0,indtmin=0,indtm=0] -o makefun0_pbc.f90 makefun_pbc.f90
python preprocess.py -c makefun0_pbc_b:[i0=0,indtmin=0,indtm=0] -o makefun0_pbc_b.f90 makefun_pbc_b.f90
python preprocess.py -c makefun0_bump:[i0=0,indtmin=0,indtm=0] -o makefun0_bump.f90 makefun_bump.f90
python preprocess.py -c makefun0_bump_b:[i0=0,indtmin=0,indtm=0] -o makefun0_bump_b.f90 makefun_bump_b.f90

# copy makefuns0
cp makefun0.f90 ../../src/makefun0.f90
cp makefun0_b.f90 ../../AD/reverse_cell/
cp makefun0_pbc.f90 ../../src/makefun0_pbc.f90
cp makefun0_pbc_b.f90 ../../AD/reverse_cell/
cp makefun0_bump.f90 ../../src/makefun0_bump.f90
cp makefun0_bump_b.f90 ../../AD/reverse_cell/
254 changes: 254 additions & 0 deletions devel_tools/adjoints/preprocess.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
#!/usr/bin/env python3
# Copyright (C) 2022 TurboRVB group
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Otto Kohulák created on 5th Nov. 2021.

import argparse
import sys
import re

try:
from icecream import ic
except:
pass

class routine_keeper:

title_endings = [ " *(?:[A-z0-9_])*",
" *::*",
" *\*",
" *,",
" *\("]

def __init__(self):
self.clear()

def __add__(self, line):
line = line.rstrip()
if not self.head_close:
if routine_keeper.filter(line):
self.header.append(line)
return
if len(line) == 0: return
self.head_close = True
self.lines.append(line)
return

def clear(self):
self.lines = []
self.header = []
self.head_close = False

@classmethod
def filter_head(cls, line):
if re.match("^ *subroutine ", line.lower()):
return True
return False

@classmethod
def filter_title(cls, line):
if re.match("^ *!", line.lower()):
return True
if re.match("^ *\&", line.lower()):
return True
return False

@classmethod
def filter_use(cls, line):
if re.match("^ *use (?:[A-z0-9_])*", line.lower()):
return True
return False

@classmethod
def filter_implicitnone(cls, line):
if re.match("^ *implicit *none", line.lower()):
return True
return False

@classmethod
def filter_type(cls, line):
l = line.lower()
if re.match("^ *type *\(.*\)", l):
return True
return False

@classmethod
def filter_logical(cls, line):
l = line.lower()
for te in cls.title_endings:
if re.match("^ *logical" + te, l):
return True
return False

@classmethod
def filter_character(cls, line):
l = line.lower()
for te in cls.title_endings:
if re.match("^ *character" + te, l):
return True
return False

@classmethod
def filter_double(cls, line):
l = line.lower()
for te in cls.title_endings:
if re.match("^ *double precision" + te, l):
return True
return False

@classmethod
def filter_complex(cls, line):
l = line.lower()
for te in cls.title_endings:
if re.match("^ *complex" + te, l):
return True
return False

@classmethod
def filter_real(cls, line):
l = line.lower()
for te in cls.title_endings:
if re.match("^ *real" + te, l):
return True
return False

@classmethod
def filter_integer(cls, line):
l = line.lower()
for te in cls.title_endings:
if re.match("^ *integer" + te, l):
return True
return False

@classmethod
def filter(cls, line):
methods = [ name for name in dir(cls) if callable(getattr(cls, name)) ]
methods = [ name for name in methods if name.startswith("filter_") ]
for method in methods:
if getattr(cls, method)(line):
return True
return False

def get_lines(self, case):
for l in self.lines:
for key, value in case.items():
key = key.strip()
r = f"([^A-z0-9_])({key})([^A-z0-9_]|$)"
rs = f"\g<1>{value}\g<3>"
l = re.sub(r, rs, l)
l = re.sub(r, rs, l)
yield l

def process_header(self, cases, name):
header = "\n".join(self.header)
rex = "(?i)(?:.*)SUBROUTINE *([A-z0-9_]+) *\(([\s\S]*?)\)([\s\S]*)"
m = re.match(rex, header)
name = m.group(1)
variables = m.group(2)
bodyofhead = m.group(3)
rex = "& *\n *&"
bodyofhead = re.sub(rex, "", bodyofhead)
variables = re.sub(rex, "", variables)

#process vars:

variables = ",".join([ x.strip() for x in variables.split(",") if x.strip() not in cases ])

for key, value in cases.items():
bodyofhead = re.sub("(\(.*?)(" + key.strip() + ")(.*?\))", f"\g<1>{value}\g<3>", bodyofhead)
bodyofhead = re.sub("(.*)(, *" + key.strip() + ") *([\n, ].*)", "\g<1>\g<3>", bodyofhead)
bodyofhead = re.sub("(.*)(" + key.strip() + ") *,([\n ].*)", "\g<1>\g<3>", bodyofhead)

header = f"SUBROUTINE {name} ({variables})\n{bodyofhead}"
self.header = header.split("\n")

def p(infile, outfile, cases, name):
message = """

!###########################################################
!# #
!# This is code was generated by preprocess script #
!# #
!###########################################################

"""

entry_re = "(^ *! *PPC) *\{(.*)\}"

start = False
lk = routine_keeper()

with open(infile, "r") as fi:
with open(outfile, "w") as fo:
fo.write(message)
lines = [ l for l in fi ]
for ii, line in enumerate(lines):
rex = "(?i)^( *subroutine *)([A-z0-9_]+)( *\()"
match = re.match(rex, line.lower())
if match:
start = True
line = str(re.sub(rex, f"\g<1>{name}\g<3>", line))
if start:
if re.match("^ *end *subroutine", line.lower()):
line = f"END SUBROUTINE {name}"
start = False
elif re.match("^ *end *$", line.lower()):
start = False
else:
lk + line
continue
if len(lk.header) > 0:
lk.process_header(cases, name)
for l in lk.header:
fo.write(l + "\n")
for ii, cc in enumerate([cases]):
for l in lk.get_lines(cc):
fo.write(l.replace("\n", "") + "\n")
lk.clear()
fo.write(line)
def main():

parser = argparse.ArgumentParser(description='Preproccessng')
parser.add_argument('input', metavar='INPUT', type=str)
parser.add_argument('-o', metavar='OUTPUT', type=str, default = None)
parser.add_argument('-c', metavar='CASES', type=str, default = None)

args = parser.parse_args()

infile = args.input

if args.c is not None:
rex = "([0-9A-z_]+):\[(.*)\]"
match = re.match(rex, args.c)
cases = []
if match:
name = match.group(1)
cc = match.group(2)
cases = { x.split("=")[0] : x.split("=")[1] for x in cc.split(",") }
output = f"{name}.f90"
if args.o is not None:
output = args.o
p(infile, output, cases, name)
sys.exit(0)
else:
print("Bad case string")
sys.exit(1)
else:
print("Please provide case string")


if __name__ == "__main__":
main()
Loading