From 3de33027677ec318fe2d0f2f80a63ac35671ca07 Mon Sep 17 00:00:00 2001 From: Yury Lysogorskiy Date: Wed, 7 Apr 2021 12:20:24 +0200 Subject: [PATCH] remove source files from lib/pace; add lib/pace/Install.py to automatically download the source files from github/ICAMS/lammps-user-pace; add lib/pace/CMakeLists.txt to build libpace.a add lib/pace/README update src/USER-PACE/Install.sh --- lib/pace/CMakeLists.txt | 19 + lib/pace/Install.py | 112 +- lib/pace/LICENSE | 674 ----------- lib/pace/README | 9 + lib/pace/ace_abstract_basis.cpp | 184 --- lib/pace/ace_abstract_basis.h | 169 --- lib/pace/ace_array2dlm.h | 579 --------- lib/pace/ace_arraynd.h | 1949 ------------------------------- lib/pace/ace_c_basis.cpp | 980 ---------------- lib/pace/ace_c_basis.h | 155 --- lib/pace/ace_c_basisfunction.h | 251 ---- lib/pace/ace_complex.h | 266 ----- lib/pace/ace_contigous_array.h | 249 ---- lib/pace/ace_evaluator.cpp | 660 ----------- lib/pace/ace_evaluator.h | 230 ---- lib/pace/ace_flatten_basis.cpp | 130 --- lib/pace/ace_flatten_basis.h | 135 --- lib/pace/ace_radial.cpp | 566 --------- lib/pace/ace_radial.h | 324 ----- lib/pace/ace_recursive.cpp | 1340 --------------------- lib/pace/ace_recursive.h | 247 ---- lib/pace/ace_spherical_cart.cpp | 221 ---- lib/pace/ace_spherical_cart.h | 134 --- lib/pace/ace_timing.h | 126 -- lib/pace/ace_types.h | 45 - lib/pace/ace_version.h | 39 - lib/pace/ships_radial.cpp | 388 ------ lib/pace/ships_radial.h | 158 --- src/USER-PACE/Install.sh | 104 +- 29 files changed, 189 insertions(+), 10254 deletions(-) create mode 100644 lib/pace/CMakeLists.txt delete mode 100644 lib/pace/LICENSE delete mode 100644 lib/pace/ace_abstract_basis.cpp delete mode 100644 lib/pace/ace_abstract_basis.h delete mode 100644 lib/pace/ace_array2dlm.h delete mode 100644 lib/pace/ace_arraynd.h delete mode 100644 lib/pace/ace_c_basis.cpp delete mode 100644 lib/pace/ace_c_basis.h delete mode 100644 lib/pace/ace_c_basisfunction.h delete mode 100644 lib/pace/ace_complex.h delete mode 100644 lib/pace/ace_contigous_array.h delete mode 100644 lib/pace/ace_evaluator.cpp delete mode 100644 lib/pace/ace_evaluator.h delete mode 100644 lib/pace/ace_flatten_basis.cpp delete mode 100644 lib/pace/ace_flatten_basis.h delete mode 100644 lib/pace/ace_radial.cpp delete mode 100644 lib/pace/ace_radial.h delete mode 100644 lib/pace/ace_recursive.cpp delete mode 100644 lib/pace/ace_recursive.h delete mode 100644 lib/pace/ace_spherical_cart.cpp delete mode 100644 lib/pace/ace_spherical_cart.h delete mode 100644 lib/pace/ace_timing.h delete mode 100644 lib/pace/ace_types.h delete mode 100644 lib/pace/ace_version.h delete mode 100644 lib/pace/ships_radial.cpp delete mode 100644 lib/pace/ships_radial.h diff --git a/lib/pace/CMakeLists.txt b/lib/pace/CMakeLists.txt new file mode 100644 index 0000000000..2884c83cb9 --- /dev/null +++ b/lib/pace/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.7) # CMake version check +project(aceevaluator) +set(CMAKE_CXX_STANDARD 11) # Enable c++11 standard + + +set(PACE_EVALUATOR_PATH ${CMAKE_CURRENT_LIST_DIR}/src/USER-PACE) +# message("CMakeLists.txt DEBUG: PACE_EVALUATOR_PATH=${PACE_EVALUATOR_PATH}") +set(PACE_EVALUATOR_SRC_PATH ${PACE_EVALUATOR_PATH}) + +FILE(GLOB PACE_EVALUATOR_SOURCE_FILES ${PACE_EVALUATOR_SRC_PATH}/*.cpp) +list(FILTER PACE_EVALUATOR_SOURCE_FILES EXCLUDE REGEX ".*pair_pace.*") +set(PACE_EVALUATOR_INCLUDE_DIR ${PACE_EVALUATOR_SRC_PATH}) + + +##### aceevaluator ##### +add_library(aceevaluator ${PACE_EVALUATOR_SOURCE_FILES}) +target_include_directories(aceevaluator PUBLIC ${PACE_EVALUATOR_INCLUDE_DIR}) +target_compile_options(aceevaluator PRIVATE -O3) +set_target_properties(aceevaluator PROPERTIES OUTPUT_NAME pace${LAMMPS_MACHINE}) diff --git a/lib/pace/Install.py b/lib/pace/Install.py index f87f5c14cb..640971e011 100644 --- a/lib/pace/Install.py +++ b/lib/pace/Install.py @@ -1 +1,111 @@ -# TODO \ No newline at end of file +# TODO#!/usr/bin/env python + +""" +Install.py tool to download, compile, and setup the pace library +used to automate the steps described in the README file in this dir +""" + +from __future__ import print_function +import sys, os, subprocess, shutil +from argparse import ArgumentParser + +sys.path.append('..') +from install_helpers import fullpath, geturl, checkmd5sum + +parser = ArgumentParser(prog='Install.py', + description="LAMMPS library build wrapper script") + +# settings + +thisdir = fullpath('.') +version = "v.2021.2.3" + +# known checksums for different PACE versions. used to validate the download. +checksums = { \ + 'v.2021.2.3' : '9ebb087cba7e4ca041fde52f7e9e640c', \ + } + + +# help message + +HELP = """ +Syntax from src dir: make lib-pace args="-b" + or: make lib-pace args="-b -v version" +Syntax from lib dir: python Install.py -b + or: python Install.py -b -v version + +Examples: + +make lib-pace args="-b" # install default version of PACE lib +make lib-pace args="-b -v version" # install specified version of PACE lib + + +""" + +pgroup = parser.add_mutually_exclusive_group() +pgroup.add_argument("-b", "--build", action="store_true", + help="download and build base PACE library") +parser.add_argument("-v", "--version", default=version, choices=checksums.keys(), + help="set version of PACE library to download and build (default: %s)" % version) +parser.add_argument("-vv", "--verbose", action="store_true", + help="be more verbose about is happening while this script runs") + +args = parser.parse_args() + +# print help message and exit, if neither build nor path options are given +if not args.build: + parser.print_help() + sys.exit(HELP) + +buildflag = args.build + +verboseflag = args.verbose +version = args.version + + +archive_extension = "tar.gz" +url = "https://github.com/ICAMS/lammps-user-pace/archive/refs/tags/%s.%s" % (version, archive_extension) +unarchived_folder_name = "lammps-user-pace-%s"%(version) + +# download PACE tarball, unpack, build PACE +if buildflag: + + # download entire tarball + + print("Downloading pace tarball ...") + archive_filename = "%s.%s" % (version, archive_extension) + download_filename = "%s/%s" % (thisdir, archive_filename) + print("Downloading from ",url," to ",download_filename, end=" ") + geturl(url, download_filename) + print(" done") + + # verify downloaded archive integrity via md5 checksum, if known. + if version in checksums: + if not checkmd5sum(checksums[version], archive_filename): + sys.exit("Checksum for pace library does not match") + + print("Unpacking pace tarball ...") + src_folder = thisdir+"/src" + cmd = 'cd "%s"; rm -rf "%s"; tar -xvf %s; mv %s %s' % (thisdir, src_folder, archive_filename, unarchived_folder_name, src_folder) + subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) + + # configure + + build_folder = "%s/build"%(thisdir) + print("Configuring libpace ...") + cmd = 'cd %s && mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release' % (thisdir) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) + + # build + print("Building libpace ...") + cmd = 'cd "%s" && make -j2 && cp libpace.a %s/' % (build_folder, thisdir) + txt = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) + if verboseflag: + print(txt.decode("UTF-8")) + +# remove source files + + print("Removing pace build files and archive ...") + cmd = 'rm %s; rm -rf %s' % (download_filename, build_folder) + subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) \ No newline at end of file diff --git a/lib/pace/LICENSE b/lib/pace/LICENSE deleted file mode 100644 index f288702d2f..0000000000 --- a/lib/pace/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/lib/pace/README b/lib/pace/README index e69de29bb2..e9a1ab820a 100644 --- a/lib/pace/README +++ b/lib/pace/README @@ -0,0 +1,9 @@ +This directory contains files required to use the USER-PACE package. + +You can type "make lib-pace" from the src directory to see help on +how to download and build this library via make commands, or you can +do the same thing by typing "python Install.py" from within this +directory. + + + diff --git a/lib/pace/ace_abstract_basis.cpp b/lib/pace/ace_abstract_basis.cpp deleted file mode 100644 index 3d8afafdaf..0000000000 --- a/lib/pace/ace_abstract_basis.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Lysogorskiy Yury on 28.04.2020. - -#include "ace_abstract_basis.h" - -////embedding function -////case nemb = 1 only implementation -////F = sign(x)*( ( 1 - exp(-(w*x)^3) )*abs(x)^m + ((1/w)^(m-1))*exp(-(w*x)^3)*abs(x) ) -//// !! no prefactor wpre -void Fexp(DOUBLE_TYPE x, DOUBLE_TYPE m, DOUBLE_TYPE &F, DOUBLE_TYPE &DF) { - DOUBLE_TYPE w = 1.e6; - DOUBLE_TYPE eps = 1e-10; - - DOUBLE_TYPE lambda = pow(1.0 / w, m - 1.0); - if (abs(x) > eps) { - DOUBLE_TYPE g; - DOUBLE_TYPE a = abs(x); - DOUBLE_TYPE am = pow(a, m); - DOUBLE_TYPE w3x3 = pow(w * a, 3); - DOUBLE_TYPE sign_factor = (signbit(x) ? -1 : 1); - if (w3x3 > 30.0) - g = 0.0; - else - g = exp(-w3x3); - - DOUBLE_TYPE omg = 1.0 - g; - F = sign_factor * (omg * am + lambda * g * a); - DOUBLE_TYPE dg = -3.0 * w * w * w * a * a * g; - DF = m * pow(a, m - 1.0) * omg - am * dg + lambda * dg * a + lambda * g; - } else { - F = lambda * x; - DF = lambda; - } -} - - -//Scaled-shifted embedding function -//F = sign(x)*( ( 1 - exp(-(w*x)^3) )*abs(x)^m + ((1/w)^(m-1))*exp(-(w*x)^3)*abs(x) ) -// !! no prefactor wpre -void FexpShiftedScaled(DOUBLE_TYPE rho, DOUBLE_TYPE mexp, DOUBLE_TYPE &F, DOUBLE_TYPE &DF) { - DOUBLE_TYPE eps = 1e-10; - DOUBLE_TYPE a, xoff, yoff, nx, exprho; - - if (abs(mexp - 1.0) < eps) { - F = rho; - DF = 1; - } else { - a = abs(rho); - exprho = exp(-a); - nx = 1. / mexp; - xoff = pow(nx, (nx / (1.0 - nx))) * exprho; - yoff = pow(nx, (1 / (1.0 - nx))) * exprho; - DOUBLE_TYPE sign_factor = (signbit(rho) ? -1 : 1); - F = sign_factor * (pow(xoff + a, mexp) - yoff); - DF = yoff + mexp * (-xoff + 1.0) * pow(xoff + a, mexp - 1.); - } -} - -void ACEAbstractBasisSet::inner_cutoff(DOUBLE_TYPE rho_core, DOUBLE_TYPE rho_cut, DOUBLE_TYPE drho_cut, - DOUBLE_TYPE &fcut, DOUBLE_TYPE &dfcut) { - - DOUBLE_TYPE rho_low = rho_cut - drho_cut; - if (rho_core >= rho_cut) { - fcut = 0; - dfcut = 0; - } else if (rho_core <= rho_low) { - fcut = 1; - dfcut = 0; - } else { - fcut = 0.5 * (1 + cos(M_PI * (rho_core - rho_low) / drho_cut)); - dfcut = -0.5 * sin(M_PI * (rho_core - rho_low) / drho_cut) * M_PI / drho_cut; - } -} - -void ACEAbstractBasisSet::FS_values_and_derivatives(Array1D &rhos, DOUBLE_TYPE &value, - Array1D &derivatives, DENSITY_TYPE ndensity) { - DOUBLE_TYPE F, DF = 0, wpre, mexp; - for (int p = 0; p < ndensity; p++) { - wpre = FS_parameters.at(p * ndensity + 0); - mexp = FS_parameters.at(p * ndensity + 1); - if (this->npoti == "FinnisSinclair") - Fexp(rhos(p), mexp, F, DF); - else if (this->npoti == "FinnisSinclairShiftedScaled") - FexpShiftedScaled(rhos(p), mexp, F, DF); - value += F * wpre; // * weight (wpre) - derivatives(p) = DF * wpre;// * weight (wpre) - } -} - -void ACEAbstractBasisSet::_clean() { - - delete[] elements_name; - elements_name = nullptr; - delete radial_functions; - radial_functions = nullptr; -} - -ACEAbstractBasisSet::ACEAbstractBasisSet(const ACEAbstractBasisSet &other) { - ACEAbstractBasisSet::_copy_scalar_memory(other); - ACEAbstractBasisSet::_copy_dynamic_memory(other); -} - -ACEAbstractBasisSet &ACEAbstractBasisSet::operator=(const ACEAbstractBasisSet &other) { - if (this != &other) { - // deallocate old memory - ACEAbstractBasisSet::_clean(); - //copy scalar values - ACEAbstractBasisSet::_copy_scalar_memory(other); - //copy dynamic memory - ACEAbstractBasisSet::_copy_dynamic_memory(other); - } - return *this; -} - -ACEAbstractBasisSet::~ACEAbstractBasisSet() { - ACEAbstractBasisSet::_clean(); -} - -void ACEAbstractBasisSet::_copy_scalar_memory(const ACEAbstractBasisSet &src) { - deltaSplineBins = src.deltaSplineBins; - FS_parameters = src.FS_parameters; - npoti = src.npoti; - - nelements = src.nelements; - rankmax = src.rankmax; - ndensitymax = src.ndensitymax; - nradbase = src.nradbase; - lmax = src.lmax; - nradmax = src.nradmax; - cutoffmax = src.cutoffmax; - - spherical_harmonics = src.spherical_harmonics; - - rho_core_cutoffs = src.rho_core_cutoffs; - drho_core_cutoffs = src.drho_core_cutoffs; - - - E0vals = src.E0vals; -} - -void ACEAbstractBasisSet::_copy_dynamic_memory(const ACEAbstractBasisSet &src) {//allocate new memory - if (src.elements_name == nullptr) - throw runtime_error("Could not copy ACEAbstractBasisSet::elements_name - array not initialized"); - elements_name = new string[nelements]; - //copy - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - elements_name[mu] = src.elements_name[mu]; - } - radial_functions = src.radial_functions->clone(); -} - -SPECIES_TYPE ACEAbstractBasisSet::get_species_index_by_name(const string &elemname) { - for (SPECIES_TYPE t = 0; t < nelements; t++) { - if (this->elements_name[t] == elemname) - return t; - } - return -1; -} \ No newline at end of file diff --git a/lib/pace/ace_abstract_basis.h b/lib/pace/ace_abstract_basis.h deleted file mode 100644 index 165ea9496f..0000000000 --- a/lib/pace/ace_abstract_basis.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Lysogorskiy Yury on 28.04.2020. - -#ifndef ACE_EVALUATOR_ACE_ABSTRACT_BASIS_H -#define ACE_EVALUATOR_ACE_ABSTRACT_BASIS_H - -#include -#include - -#include "ace_c_basisfunction.h" -#include "ace_contigous_array.h" -#include "ace_radial.h" -#include "ace_spherical_cart.h" -#include "ace_types.h" - -using namespace std; - -/** - * Abstract basis set class - */ -class ACEAbstractBasisSet { -public: - SPECIES_TYPE nelements = 0; ///< number of elements in basis set - RANK_TYPE rankmax = 0; ///< maximum value of rank - DENSITY_TYPE ndensitymax = 0; ///< maximum number of densities \f$ \rho^{(p)} \f$ - NS_TYPE nradbase = 0; ///< maximum number of radial \f$\textbf{basis}\f$ function \f$ g_{k}(r) \f$ - LS_TYPE lmax = 0; ///< \f$ l_\textrm{max} \f$ - maximum value of orbital moment \f$ l \f$ - NS_TYPE nradmax = 0; ///< maximum number \f$ n \f$ of radial function \f$ R_{nl}(r) \f$ - DOUBLE_TYPE cutoffmax = 0; ///< maximum value of cutoff distance among all species in basis set - DOUBLE_TYPE deltaSplineBins = 0; ///< Spline interpolation density - - string npoti = "FinnisSinclair"; ///< FS and embedding function combination - - string *elements_name = nullptr; ///< Array of elements name for mapping from index (0..nelements-1) to element symbol (string) - - AbstractRadialBasis *radial_functions = nullptr; ///< object to work with radial functions - ACECartesianSphericalHarmonics spherical_harmonics; ///< object to work with spherical harmonics in Cartesian representation - - - Array1D rho_core_cutoffs; ///< energy-based inner cut-off - Array1D drho_core_cutoffs; ///< decay of energy-based inner cut-off - - vector FS_parameters; ///< parameters for cluster functional, see Eq.(3) in implementation notes or Eq.(53) in PRB 99, 014104 (2019) - - // E0 values - Array1D E0vals; - - /** - * Default empty constructor - */ - ACEAbstractBasisSet() = default; - - // copy constructor, operator= and destructor (see. Rule of Three) - - /** - * Copy constructor (see. Rule of Three) - * @param other - */ - ACEAbstractBasisSet(const ACEAbstractBasisSet &other); - - /** - * operator= (see. Rule of Three) - * @param other - * @return - */ - ACEAbstractBasisSet &operator=(const ACEAbstractBasisSet &other); - - /** - * virtual destructor (see. Rule of Three) - */ - virtual ~ACEAbstractBasisSet(); - - /** - * Computing cluster functional \f$ F(\rho_i^{(1)}, \dots, \rho_i^{(P)}) \f$ - * and its derivatives \f$ (\partial F/\partial\rho_i^{(1)}, \dots, \partial F/\partial \rho_i^{(P)} ) \f$ - * @param rhos array with densities \f$ \rho^{(p)} \f$ - * @param value (out) return value of cluster functional - * @param derivatives (out) array of derivatives \f$ (\partial F/\partial\rho_i^{(1)}, \dots, \partial F/\partial \rho_i^{(P)} ) \f$ - * @param ndensity number \f$ P \f$ of densities to use - */ - void FS_values_and_derivatives(Array1D &rhos, DOUBLE_TYPE &value, Array1D &derivatives, - DENSITY_TYPE ndensity); - - /** - * Computing hard core pairwise repulsive potential \f$ f_{cut}(\rho_i^{(\textrm{core})})\f$ and its derivative, - * see Eq.(29) of implementation notes - * @param rho_core value of \f$ \rho_i^{(\textrm{core})} \f$ - * @param rho_cut \f$ \rho_{cut}^{\mu_i} \f$ value - * @param drho_cut \f$ \Delta_{cut}^{\mu_i} \f$ value - * @param fcut (out) return inner cutoff function - * @param dfcut (out) return derivative of inner cutoff function - */ - static void inner_cutoff(DOUBLE_TYPE rho_core, DOUBLE_TYPE rho_cut, DOUBLE_TYPE drho_cut, DOUBLE_TYPE &fcut, - DOUBLE_TYPE &dfcut); - - - /** - * Virtual method to save potential to file - * @param filename file name - */ - virtual void save(const string &filename) = 0; - - /** - * Virtual method to load potential from file - * @param filename file name - */ - virtual void load(const string filename) = 0; - - /** - * Get the species index by its element name - * @param elemname element name - * @return species index - */ - SPECIES_TYPE get_species_index_by_name(const string &elemname); - - - // routines for copying and cleaning dynamic memory of the class (see. Rule of Three) - - /** - * Routine for clean the dynamically allocated memory\n - * IMPORTANT! It must be idempotent for safety. - */ - virtual void _clean(); - - /** - * Copy dynamic memory from src. Must be override and extended in derived classes! - * @param src source object to copy from - */ - virtual void _copy_dynamic_memory(const ACEAbstractBasisSet &src); - - /** - * Copy scalar values from src. Must be override and extended in derived classes! - * @param src source object to copy from - */ - virtual void _copy_scalar_memory(const ACEAbstractBasisSet &src); -}; - -void Fexp(DOUBLE_TYPE rho, DOUBLE_TYPE mexp, DOUBLE_TYPE &F, DOUBLE_TYPE &DF); - -void FexpShiftedScaled(DOUBLE_TYPE rho, DOUBLE_TYPE mexp, DOUBLE_TYPE &F, DOUBLE_TYPE &DF); - -#endif //ACE_EVALUATOR_ACE_ABSTRACT_BASIS_H diff --git a/lib/pace/ace_array2dlm.h b/lib/pace/ace_array2dlm.h deleted file mode 100644 index 2b38602bc7..0000000000 --- a/lib/pace/ace_array2dlm.h +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Yury Lysogorskiy on 11.01.20. - - -#ifndef ACE_ARRAY2DLM_H -#define ACE_ARRAY2DLM_H - -#include -#include - -#include "ace_arraynd.h" -#include "ace_contigous_array.h" -#include "ace_types.h" - -using namespace std; - -/** - * Contiguous array to organize values by \f$ (l,m) \f$ indiced (orbital moment and its projection). - * Only \f$ l_\textrm{max}\f$ should be provided, \f$ m = -l, \dots,l \f$ - * for \f$ l = 0, \dots, l_\textrm{max}\f$ - * @tparam T type of values to store - */ -template -class Array2DLM : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - - LS_TYPE lmax = 0; ///< orbital dimension \f$ l_{max} \f$ - - bool is_proxy = false; ///< flag to show, if object is owning the memory or just represent it (proxying)dimensions - -public: - /** - * Default empty constructor - */ - Array2DLM() = default; - - /** - * Parametrized constructor - * @param lmax maximum value of \f$ l \f$ - * @param array_name name of the array - */ - explicit Array2DLM(LS_TYPE lmax, string array_name = "Array2DLM") { - init(lmax, array_name); - } - - - /** - * Constructor to create slices-proxy array, i.e. to provide access to the memory, but not to own it. - * @param lmax maximum value of \f$ l \f$ - * @param data_ptr pointer to original data - * @param array_name name of the array - */ - Array2DLM(LS_TYPE lmax, T *data_ptr, string array_name = "Array2DLM") { - this->lmax = lmax; - this->size = (lmax + 1) * (lmax + 1); - this->data = data_ptr; - this->array_name = array_name; - is_proxy = true; - }; - - /** - * Destructor - */ - ~Array2DLM() { - if (!is_proxy) { - if (data != nullptr) delete[] data; - } - data = nullptr; - } - - /** - * Initialize array, allocate memory - * @param lmax maximum value of l - * @param array_name name of the array - */ - void init(LS_TYPE lmax, string array_name = "Array2DLM") { - if (is_proxy) { - char s[1024]; - sprintf(s, "Could not re-initialize proxy-array %s\n", this->array_name.c_str()); - throw logic_error(s); - } - this->lmax = lmax; - this->array_name = array_name; - //for m = -l .. l - if (size != (lmax + 1) * (lmax + 1)) { - size = (lmax + 1) * (lmax + 1); - if (data) delete[] data; - data = new T[size]{}; - memset(data, 0.0, size * sizeof(T)); - } else { - memset(data, 0, size * sizeof(T)); - } - } - -#ifdef MULTIARRAY_INDICES_CHECK -/** - * Check if indices (l,m) are within array - */ - void check_indices(LS_TYPE l, MS_TYPE m) const { - - if ((l < 0) | (l > lmax)) { - fprintf(stderr, "%s: Index l = %d out of range (0, %d)\n", array_name.c_str(), l, lmax); - exit(EXIT_FAILURE); - } - - if ((m < -l) | (m > l)) { - fprintf(stderr, "%s: Index m = %d out of range (%d, %d)\n", array_name.c_str(), m, -l, l); - exit(EXIT_FAILURE); - } - size_t ii = l * (l + 1) + m; - if (ii >= size) { - fprintf(stderr, "%s: index = %ld out of range %ld\n", array_name.c_str(), ii, size); - exit(EXIT_FAILURE); - } - } -#endif - - /** - * Accessing the array value by index (l,m) for reading - * @param l - * @param m - * @return array value - */ - inline const T &operator()(LS_TYPE l, MS_TYPE m) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(l, m); -#endif - //l^2 + l + m - return data[l * (l + 1) + m]; - } - - /** - * Accessing the array value by index (l,m) for writing - * @param l - * @param m - * @return array value - */ - inline T &operator()(LS_TYPE l, MS_TYPE m) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(l, m); -#endif - //l^2 + l + m - return data[l * (l + 1) + m]; - } - - /** - * Convert array to STL vector> container - * @return vector> container - */ - vector> to_vector() const { - vector> res; - res.resize(lmax + 1); - - for (int i = 0; i < lmax + 1; i++) { - res[i].resize(i + 1); - for (int j = 0; j < i + 1; j++) { - res[i][j] = operator()(i, j); - } - } - return res; - } -}; - -/** - * Contiguous array to organize values by \f$ (i_0, l , m) \f$ indices. - * Only \f$ d_{0}, l_\textrm{max}\f$ should be provided: \f$ m = -l, \dots,l \f$ - * for \f$ l = 0, \dots, l_\textrm{max}\f$ - * @tparam T type of values to store - */ -template -class Array3DLM : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - - LS_TYPE lmax = 0; ///< orbital dimension \f$ l_{max} \f$ - - - size_t dim[1] = {0}; ///< linear dimension \f$ d_{0} \f$ - - size_t s[1] = {0}; ///< strides for linear dimensions - - Array1D *> _proxy_slices; ///< slices representation -public: - /** - * Default empty constructor - */ - Array3DLM() = default; - - /** - * Parametrized constructor - * @param array_name name of the array - */ - Array3DLM(string array_name) { - this->array_name = array_name; - }; - - /** - * Parametrized constructor - * @param d0 maximum value of \f$ i_0 \f$ - * @param lmax maximum value of \f$ l \f$ - * @param array_name name of the array - */ - explicit Array3DLM(size_t d0, LS_TYPE lmax, string array_name = "Array3DLM") { - init(d0, lmax, array_name); - } - - /** - * Initialize array and its slices - * @param d0 maximum value of \f$ i_0 \f$ - * @param lmax maximum value of \f$ l \f$ - * @param array_name name of the array - */ - void init(size_t d0, LS_TYPE lmax, string array_name = "Array3DLM") { - this->array_name = array_name; - this->lmax = lmax; - dim[0] = d0; - s[0] = lmax * lmax; - if (size != s[0] * dim[0]) { - size = s[0] * dim[0]; - if (data) delete[] data; - data = new T[size]{}; - memset(data, 0, size * sizeof(T)); - } else { - memset(data, 0, size * sizeof(T)); - } - - _proxy_slices.set_array_name(array_name + "_proxy"); - //arrange proxy-slices - _clear_proxies(); - _proxy_slices.resize(dim[0]); - for (size_t i0 = 0; i0 < dim[0]; ++i0) { - _proxy_slices(i0) = new Array2DLM(this->lmax, &this->data[i0 * s[0]], - array_name + "_slice"); - } - } - - /** - * Release pointers to slices - */ - void _clear_proxies() { - for (size_t i0 = 0; i0 < _proxy_slices.get_dim(0); ++i0) { - delete _proxy_slices(i0); - _proxy_slices(i0) = nullptr; - } - } - - /** - * Destructor, clear proxies - */ - ~Array3DLM() { - _clear_proxies(); - } - - /** - * Resize array to new dimensions - * @param d0 - * @param lmax - */ - void resize(size_t d0, LS_TYPE lmax) { - _clear_proxies(); - init(d0, lmax, this->array_name); - } - - /** - * Get array dimensions - * @param d dimension index - * @return dimension along axis 'd' - */ - size_t get_dim(int d) const { - return dim[d]; - } - -#ifdef MULTIARRAY_INDICES_CHECK - /** - * Check if indices (i0, l,m) are within array - */ - void check_indices(size_t i0, LS_TYPE l, MS_TYPE m) const { - if ((l < 0) | (l > lmax)) { - fprintf(stderr, "%s: Index l = %d out of range (0, %d)\n", array_name.c_str(), l, lmax); - exit(EXIT_FAILURE); - } - - if ((m < -l) | (m > l)) { - fprintf(stderr, "%s: Index m = %d out of range (%d, %d)\n", array_name.c_str(), m, -l, l); - exit(EXIT_FAILURE); - } - - if ((i0 < 0) | (i0 >= dim[0])) { - fprintf(stderr, "%s: index i0 = %ld out of range (0, %ld)\n", array_name.c_str(), i0, dim[0] - 1); - exit(EXIT_FAILURE); - } - - size_t ii = i0 * s[0] + l * (l + 1) + m; - if (ii >= size) { - fprintf(stderr, "%s: index = %ld out of range %ld\n", array_name.c_str(), ii, size); - exit(EXIT_FAILURE); - } - } -#endif - - /** - * Accessing the array value by index (i0,l,m) for reading - * @param i0 - * @param l - * @param m - * @return array value - */ - inline const T &operator()(size_t i0, LS_TYPE l, MS_TYPE m) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, l, m); -#endif - return data[i0 * s[0] + l * (l + 1) + m]; - } - - /** - * Accessing the array value by index (i0,l,m) for writing - * @param i0 - * @param l - * @param m - * @return array value - */ - inline T &operator()(size_t i0, LS_TYPE l, MS_TYPE m) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, l, m); -#endif - return data[i0 * s[0] + l * (l + 1) + m]; - } - - /** - * Return proxy Array2DLM pointing to i0, l=0, m=0 to read - * @param i0 - * @return proxy Array2DLM pointing to i0, l=0, m=0 - */ - inline const Array2DLM &operator()(size_t i0) const { - return *_proxy_slices(i0); - } - - /** - * Return proxy Array2DLM pointing to i0, l=0, m=0 to write - * @param i0 - * @return proxy Array2DLM pointing to i0, l=0, m=0 - */ - inline Array2DLM &operator()(size_t i0) { - return *_proxy_slices(i0); - } -}; - - -/** - * Contiguous array to organize values by \f$ (i_0, i_1, l , m) \f$ indices. - * Only \f$ d_{0}, d_{1}, l_\textrm{max}\f$ should be provided: \f$ m = -l, \dots,l \f$ - * for \f$ l = 0, \dots, l_\textrm{max}\f$ - * @tparam T type of values to store - */ -template -class Array4DLM : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - - LS_TYPE lmax = 0; ///< orbital dimension \f$ l_{max} \f$ - size_t dim[2] = {0, 0}; ///< linear dimension \f$ d_{0}, d_{1} \f$ - size_t s[2] = {0, 0}; ///< strides for linear dimensions - - Array2D *> _proxy_slices; ///< slices representation -public: - /** - * Default empty constructor - */ - Array4DLM() = default; - - /** - * Parametrized constructor - * @param array_name name of the array - */ - Array4DLM(string array_name) { - this->array_name = array_name; - }; - - /** - * Parametrized constructor - * @param d0 maximum value of \f$ i_0 \f$ - * @param d1 maximum value of \f$ i_1 \f$ - * @param lmax maximum value of \f$ l \f$ - * @param array_name name of the array - */ - explicit Array4DLM(size_t d0, size_t d1, LS_TYPE lmax, string array_name = "Array4DLM") { - init(d0, d1, lmax, array_name); - } - - /** - * Initialize array, reallocate memory and its slices - * @param d0 maximum value of \f$ i_0 \f$ - * @param d1 maximum value of \f$ i_1 \f$ - * @param lmax maximum value of \f$ l \f$ - * @param array_name name of the array - */ - void init(size_t d0, size_t d1, LS_TYPE lmax, string array_name = "Array4DLM") { - this->array_name = array_name; - this->lmax = lmax; - dim[1] = d1; - dim[0] = d0; - s[1] = lmax * lmax; - s[0] = s[1] * dim[1]; - if (size != s[0] * dim[0]) { - size = s[0] * dim[0]; - if (data) delete[] data; - data = new T[size]{}; - memset(data, 0, size * sizeof(T)); - } else { - memset(data, 0, size * sizeof(T)); - } - - _proxy_slices.set_array_name(array_name + "_proxy"); - //release old memory if there is any - _clear_proxies(); - //arrange proxy-slices - _proxy_slices.resize(dim[0], dim[1]); - for (size_t i0 = 0; i0 < dim[0]; ++i0) - for (size_t i1 = 0; i1 < dim[1]; ++i1) { - _proxy_slices(i0, i1) = new Array2DLM(this->lmax, &this->data[i0 * s[0] + i1 * s[1]], - array_name + "_slice"); - } - } - - /** - * Release pointers to slices - */ - void _clear_proxies() { - - for (size_t i0 = 0; i0 < _proxy_slices.get_dim(0); ++i0) - for (size_t i1 = 0; i1 < _proxy_slices.get_dim(1); ++i1) { - delete _proxy_slices(i0, i1); - _proxy_slices(i0, i1) = nullptr; - } - } - - /** - * Destructor, clear proxies - */ - ~Array4DLM() { - _clear_proxies(); - } - - /** - * Deallocate memory, reallocate with the new dimensions - * @param d0 - * @param lmax - */ - void resize(size_t d0, size_t d1, LS_TYPE lmax) { - _clear_proxies(); - init(d0, d1, lmax, this->array_name); - } - - /** - * Get array dimensions - * @param d dimension index - * @return dimension along axis 'd' - */ - size_t get_dim(int d) const { - return dim[d]; - } - -#ifdef MULTIARRAY_INDICES_CHECK - /** - * Check if indices (i0, l,m) are within array - */ - void check_indices(size_t i0, size_t i1, LS_TYPE l, MS_TYPE m) const { - if ((l < 0) | (l > lmax)) { - fprintf(stderr, "%s: Index l = %d out of range (0, %d)\n", array_name.c_str(), l, lmax); - exit(EXIT_FAILURE); - } - - if ((m < -l) | (m > l)) { - fprintf(stderr, "%s: Index m = %d out of range (%d, %d)\n", array_name.c_str(), m, -l, l); - exit(EXIT_FAILURE); - } - - if ((i0 < 0) | (i0 >= dim[0])) { - fprintf(stderr, "%s: index i0 = %ld out of range (0, %ld)\n", array_name.c_str(), i0, dim[0] - 1); - exit(EXIT_FAILURE); - } - - - if ((i1 < 0) | (i1 >= dim[1])) { - fprintf(stderr, "%s: index i1 = %ld out of range (0, %ld)\n", array_name.c_str(), i1, dim[1] - 1); - exit(EXIT_FAILURE); - } - - size_t ii = i0 * s[0] + i1 * s[1] + l * (l + 1) + m; - if (ii >= size) { - fprintf(stderr, "%s: index = %ld out of range %ld\n", array_name.c_str(), ii, size); - exit(EXIT_FAILURE); - } - } -#endif - - /** - * Accessing the array value by index (i0,l,m) for reading - * @param i0 - * @param i1 - * @param l - * @param m - * @return array value - */ - inline const T &operator()(size_t i0, size_t i1, LS_TYPE l, MS_TYPE m) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, l, m); -#endif - return data[i0 * s[0] + i1 * s[1] + l * (l + 1) + m]; - } - - /** - * Accessing the array value by index (i0,l,m) for writing - * @param i0 - * @param i1 - * @param l - * @param m - * @return array value - */ - inline T &operator()(size_t i0, size_t i1, LS_TYPE l, MS_TYPE m) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, l, m); -#endif - return data[i0 * s[0] + i1 * s[1] + l * (l + 1) + m]; - } - - /** - * Return proxy Array2DLM pointing to i0, i1, l=0, m=0 to read - * @param i0 - * @param i1 - * @return proxy Array2DLM pointing to i0, l=0, m=0 - */ - inline const Array2DLM &operator()(size_t i0, size_t i1) const { - return *_proxy_slices(i0, i1); - } - - /** - * Return proxy Array2DLM pointing to i0, i1, l=0, m=0 to write - * @param i0 - * @param i1 - * @return proxy Array2DLM pointing to i0, l=0, m=0 - */ - inline Array2DLM &operator()(size_t i0, size_t i1) { - return *_proxy_slices(i0, i1); - } -}; - -#endif //ACE_ARRAY2DLM_H \ No newline at end of file diff --git a/lib/pace/ace_arraynd.h b/lib/pace/ace_arraynd.h deleted file mode 100644 index 1044b5654e..0000000000 --- a/lib/pace/ace_arraynd.h +++ /dev/null @@ -1,1949 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -//automatically generate source code - -#ifndef ACE_MULTIARRAY_H -#define ACE_MULTIARRAY_H - -#include -#include -#include - -#include "ace_contigous_array.h" - -using namespace std; - - -/** - * Multidimensional (1 - dimensional) array of type T with contiguous memory layout. - * If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @tparam T data type - */ -template -class Array1D : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - using ContiguousArrayND::is_proxy_; - - size_t dim[1] = {0}; ///< dimensions - size_t s[1] = {0}; ///< strides - int ndim = 1; ///< number of dimensions -public: - - /** - * Default empty constructor - */ - Array1D() = default; - - /** - * Parametrized constructor with array name - * @param array_name name of array (for error logging) - */ - Array1D(const string &array_name) { this->array_name = array_name; } - - /** - * Parametrized constructor - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - Array1D(size_t d0, const string &array_name = "Array1D", T *new_data = nullptr) { - init(d0, array_name, new_data); - } - - /** - * Setup the dimensions and strides of array - * @param d0,... array sizes for different dimensions - */ - void set_dimensions(size_t d0) { - - dim[0] = d0; - - s[0] = 1; - - size = s[0] * dim[0]; - }; - - /** - * Initialize array storage, dimensions and strides - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - void init(size_t d0, const string &array_name = "Array1D", T *new_data = nullptr) { - this->array_name = array_name; - - size_t old_size = size; - set_dimensions(d0); - - bool new_is_proxy = (new_data != nullptr); - - if (new_is_proxy) { - if (!is_proxy_) delete[] data; - data = new_data; - } else { - if (size != old_size) { - T *old_data = data; //preserve the pointer to the old data - data = new T[size]; // allocate new data - if (old_data != nullptr) { // - size_t min_size = old_size < size ? old_size : size; - memcpy(data, old_data, min_size * sizeof(T)); - if (!is_proxy_) delete[] old_data; - } - //memset(data, 0, size * sizeof(T)); - } else { - //memset(data, 0, size * sizeof(T)); - } - } - - is_proxy_ = new_is_proxy; - } - - /** - * Resize array - * @param d0,... array sizes for different dimensions - */ - void resize(size_t d0) { - init(d0, this->array_name); - } - - /** - * Reshape array without reset the data - * @param d0,... array sizes for different dimensions - */ - void reshape(size_t d0) { - //check data size consistency - size_t new_size = d0; - if (new_size != size) - throw invalid_argument("Couldn't reshape array when the size is not conserved"); - set_dimensions(d0); - } - - /** - * Get array size in dimension "d" - * @param d dimension index - */ - size_t get_dim(int d) const { - return dim[d]; - } - -#ifdef MULTIARRAY_INDICES_CHECK - - /** - * Check indices validity. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - void check_indices(size_t i0) const { - - if ((i0 < 0) | (i0 >= dim[0])) { - char buf[1024]; - sprintf(buf, "%s: index i0=%ld out of range (0, %ld)\n", array_name.c_str(), i0, dim[0] - 1); - throw std::out_of_range(buf); - } - - } - -#endif - - /** - * Array access operator() for reading. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline const T &operator()(size_t i0) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0); -#endif - - return data[i0]; - - } - - /** - * Array access operator() for writing. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline T &operator()(size_t i0) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0); -#endif - - return data[i0]; - - } - - /** - * Array comparison operator - * @param other - */ - bool operator==(const Array1D &other) const { - //compare dimensions - for (int d = 0; d < ndim; d++) { - if (this->dim[d] != other.dim[d]) - return false; - } - return ContiguousArrayND::operator==(other); - } - - /** - * Convert to nested vector> container - * @return vector container - */ - vector to_vector() const { - vector res; - - res.resize(dim[0]); - - for (int i0 = 0; i0 < dim[0]; i0++) { - res[i0] = operator()(i0); - - } - - - return res; - } // end to_vector() - - - /** - * Set values to vector> container - * @param vec container - */ - void set_vector(const vector &vec) { - size_t d0 = 0; - d0 = vec.size(); - - - init(d0, array_name); - for (int i0 = 0; i0 < dim[0]; i0++) { - operator()(i0) = vec.at(i0); - - } - - } - - /** - * Parametrized constructor from vector> container - * @param vec container - * @param array_name array name - */ - Array1D(const vector &vec, const string &array_name = "Array1D") { - this->set_vector(vec); - this->array_name = array_name; - } - - /** - * operator= to vector> container - * @param vec container - */ - Array1D &operator=(const vector &vec) { - this->set_vector(vec); - return *this; - } - - - vector get_shape() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = dim[d]; - return sh; - } - - vector get_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d]; - return sh; - } - - vector get_memory_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d] * sizeof(T); - return sh; - } -}; - - -/** - * Multidimensional (2 - dimensional) array of type T with contiguous memory layout. - * If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @tparam T data type - */ -template -class Array2D : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - using ContiguousArrayND::is_proxy_; - - size_t dim[2] = {0}; ///< dimensions - size_t s[2] = {0}; ///< strides - int ndim = 2; ///< number of dimensions -public: - - /** - * Default empty constructor - */ - Array2D() = default; - - /** - * Parametrized constructor with array name - * @param array_name name of array (for error logging) - */ - Array2D(const string &array_name) { this->array_name = array_name; } - - /** - * Parametrized constructor - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - Array2D(size_t d0, size_t d1, const string &array_name = "Array2D", T *new_data = nullptr) { - init(d0, d1, array_name, new_data); - } - - /** - * Setup the dimensions and strides of array - * @param d0,... array sizes for different dimensions - */ - void set_dimensions(size_t d0, size_t d1) { - - dim[0] = d0; - dim[1] = d1; - - s[1] = 1; - s[0] = s[1] * dim[1]; - - size = s[0] * dim[0]; - }; - - /** - * Initialize array storage, dimensions and strides - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - void init(size_t d0, size_t d1, const string &array_name = "Array2D", T *new_data = nullptr) { - this->array_name = array_name; - - size_t old_size = size; - set_dimensions(d0, d1); - - bool new_is_proxy = (new_data != nullptr); - - if (new_is_proxy) { - if (!is_proxy_) delete[] data; - data = new_data; - } else { - if (size != old_size) { - T *old_data = data; //preserve the pointer to the old data - data = new T[size]; // allocate new data - if (old_data != nullptr) { // - size_t min_size = old_size < size ? old_size : size; - memcpy(data, old_data, min_size * sizeof(T)); - if (!is_proxy_) delete[] old_data; - } - //memset(data, 0, size * sizeof(T)); - } else { - //memset(data, 0, size * sizeof(T)); - } - } - - is_proxy_ = new_is_proxy; - } - - /** - * Resize array - * @param d0,... array sizes for different dimensions - */ - void resize(size_t d0, size_t d1) { - init(d0, d1, this->array_name); - } - - /** - * Reshape array without reset the data - * @param d0,... array sizes for different dimensions - */ - void reshape(size_t d0, size_t d1) { - //check data size consistency - size_t new_size = d0 * d1; - if (new_size != size) - throw invalid_argument("Couldn't reshape array when the size is not conserved"); - set_dimensions(d0, d1); - } - - /** - * Get array size in dimension "d" - * @param d dimension index - */ - size_t get_dim(int d) const { - return dim[d]; - } - -#ifdef MULTIARRAY_INDICES_CHECK - - /** - * Check indices validity. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - void check_indices(size_t i0, size_t i1) const { - - if ((i0 < 0) | (i0 >= dim[0])) { - char buf[1024]; - sprintf(buf, "%s: index i0=%ld out of range (0, %ld)\n", array_name.c_str(), i0, dim[0] - 1); - throw std::out_of_range(buf); - } - - if ((i1 < 0) | (i1 >= dim[1])) { - char buf[1024]; - sprintf(buf, "%s: index i1=%ld out of range (0, %ld)\n", array_name.c_str(), i1, dim[1] - 1); - throw std::out_of_range(buf); - } - - } - -#endif - - /** - * Array access operator() for reading. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline const T &operator()(size_t i0, size_t i1) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1); -#endif - - return data[i0 * s[0] + i1]; - - } - - /** - * Array access operator() for writing. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline T &operator()(size_t i0, size_t i1) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1); -#endif - - return data[i0 * s[0] + i1]; - - } - - /** - * Array comparison operator - * @param other - */ - bool operator==(const Array2D &other) const { - //compare dimensions - for (int d = 0; d < ndim; d++) { - if (this->dim[d] != other.dim[d]) - return false; - } - return ContiguousArrayND::operator==(other); - } - - /** - * Convert to nested vector> container - * @return vector container - */ - vector> to_vector() const { - vector> res; - - res.resize(dim[0]); - - for (int i0 = 0; i0 < dim[0]; i0++) { - res[i0].resize(dim[1]); - - - for (int i1 = 0; i1 < dim[1]; i1++) { - res[i0][i1] = operator()(i0, i1); - - } - } - - - return res; - } // end to_vector() - - - /** - * Set values to vector> container - * @param vec container - */ - void set_vector(const vector> &vec) { - size_t d0 = 0; - size_t d1 = 0; - d0 = vec.size(); - - if (d0 > 0) { - d1 = vec.at(0).size(); - - - } - - init(d0, d1, array_name); - for (int i0 = 0; i0 < dim[0]; i0++) { - if (vec.at(i0).size() != d1) - throw std::invalid_argument("Vector size is not constant at dimension 1"); - - for (int i1 = 0; i1 < dim[1]; i1++) { - operator()(i0, i1) = vec.at(i0).at(i1); - - } - } - - } - - /** - * Parametrized constructor from vector> container - * @param vec container - * @param array_name array name - */ - Array2D(const vector> &vec, const string &array_name = "Array2D") { - this->set_vector(vec); - this->array_name = array_name; - } - - /** - * operator= to vector> container - * @param vec container - */ - Array2D &operator=(const vector> &vec) { - this->set_vector(vec); - return *this; - } - - - /** - * operator= to flatten vector container - * @param vec container - */ - Array2D &operator=(const vector &vec) { - this->set_flatten_vector(vec); - return *this; - } - - - vector get_shape() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = dim[d]; - return sh; - } - - vector get_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d]; - return sh; - } - - vector get_memory_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d] * sizeof(T); - return sh; - } -}; - - -/** - * Multidimensional (3 - dimensional) array of type T with contiguous memory layout. - * If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @tparam T data type - */ -template -class Array3D : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - using ContiguousArrayND::is_proxy_; - - size_t dim[3] = {0}; ///< dimensions - size_t s[3] = {0}; ///< strides - int ndim = 3; ///< number of dimensions -public: - - /** - * Default empty constructor - */ - Array3D() = default; - - /** - * Parametrized constructor with array name - * @param array_name name of array (for error logging) - */ - Array3D(const string &array_name) { this->array_name = array_name; } - - /** - * Parametrized constructor - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - Array3D(size_t d0, size_t d1, size_t d2, const string &array_name = "Array3D", T *new_data = nullptr) { - init(d0, d1, d2, array_name, new_data); - } - - /** - * Setup the dimensions and strides of array - * @param d0,... array sizes for different dimensions - */ - void set_dimensions(size_t d0, size_t d1, size_t d2) { - - dim[0] = d0; - dim[1] = d1; - dim[2] = d2; - - s[2] = 1; - s[1] = s[2] * dim[2]; - s[0] = s[1] * dim[1]; - - size = s[0] * dim[0]; - }; - - /** - * Initialize array storage, dimensions and strides - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - void init(size_t d0, size_t d1, size_t d2, const string &array_name = "Array3D", T *new_data = nullptr) { - this->array_name = array_name; - - size_t old_size = size; - set_dimensions(d0, d1, d2); - - bool new_is_proxy = (new_data != nullptr); - - if (new_is_proxy) { - if (!is_proxy_) delete[] data; - data = new_data; - } else { - if (size != old_size) { - T *old_data = data; //preserve the pointer to the old data - data = new T[size]; // allocate new data - if (old_data != nullptr) { // - size_t min_size = old_size < size ? old_size : size; - memcpy(data, old_data, min_size * sizeof(T)); - if (!is_proxy_) delete[] old_data; - } - //memset(data, 0, size * sizeof(T)); - } else { - //memset(data, 0, size * sizeof(T)); - } - } - - is_proxy_ = new_is_proxy; - } - - /** - * Resize array - * @param d0,... array sizes for different dimensions - */ - void resize(size_t d0, size_t d1, size_t d2) { - init(d0, d1, d2, this->array_name); - } - - /** - * Reshape array without reset the data - * @param d0,... array sizes for different dimensions - */ - void reshape(size_t d0, size_t d1, size_t d2) { - //check data size consistency - size_t new_size = d0 * d1 * d2; - if (new_size != size) - throw invalid_argument("Couldn't reshape array when the size is not conserved"); - set_dimensions(d0, d1, d2); - } - - /** - * Get array size in dimension "d" - * @param d dimension index - */ - size_t get_dim(int d) const { - return dim[d]; - } - -#ifdef MULTIARRAY_INDICES_CHECK - - /** - * Check indices validity. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - void check_indices(size_t i0, size_t i1, size_t i2) const { - - if ((i0 < 0) | (i0 >= dim[0])) { - char buf[1024]; - sprintf(buf, "%s: index i0=%ld out of range (0, %ld)\n", array_name.c_str(), i0, dim[0] - 1); - throw std::out_of_range(buf); - } - - if ((i1 < 0) | (i1 >= dim[1])) { - char buf[1024]; - sprintf(buf, "%s: index i1=%ld out of range (0, %ld)\n", array_name.c_str(), i1, dim[1] - 1); - throw std::out_of_range(buf); - } - - if ((i2 < 0) | (i2 >= dim[2])) { - char buf[1024]; - sprintf(buf, "%s: index i2=%ld out of range (0, %ld)\n", array_name.c_str(), i2, dim[2] - 1); - throw std::out_of_range(buf); - } - - } - -#endif - - /** - * Array access operator() for reading. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline const T &operator()(size_t i0, size_t i1, size_t i2) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, i2); -#endif - - return data[i0 * s[0] + i1 * s[1] + i2]; - - } - - /** - * Array access operator() for writing. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline T &operator()(size_t i0, size_t i1, size_t i2) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, i2); -#endif - - return data[i0 * s[0] + i1 * s[1] + i2]; - - } - - /** - * Array comparison operator - * @param other - */ - bool operator==(const Array3D &other) const { - //compare dimensions - for (int d = 0; d < ndim; d++) { - if (this->dim[d] != other.dim[d]) - return false; - } - return ContiguousArrayND::operator==(other); - } - - /** - * Convert to nested vector> container - * @return vector container - */ - vector>> to_vector() const { - vector>> res; - - res.resize(dim[0]); - - for (int i0 = 0; i0 < dim[0]; i0++) { - res[i0].resize(dim[1]); - - - for (int i1 = 0; i1 < dim[1]; i1++) { - res[i0][i1].resize(dim[2]); - - - for (int i2 = 0; i2 < dim[2]; i2++) { - res[i0][i1][i2] = operator()(i0, i1, i2); - - } - } - } - - - return res; - } // end to_vector() - - - /** - * Set values to vector> container - * @param vec container - */ - void set_vector(const vector>> &vec) { - size_t d0 = 0; - size_t d1 = 0; - size_t d2 = 0; - d0 = vec.size(); - - if (d0 > 0) { - d1 = vec.at(0).size(); - if (d1 > 0) { - d2 = vec.at(0).at(0).size(); - - - } - } - - init(d0, d1, d2, array_name); - for (int i0 = 0; i0 < dim[0]; i0++) { - if (vec.at(i0).size() != d1) - throw std::invalid_argument("Vector size is not constant at dimension 1"); - - for (int i1 = 0; i1 < dim[1]; i1++) { - if (vec.at(i0).at(i1).size() != d2) - throw std::invalid_argument("Vector size is not constant at dimension 2"); - - for (int i2 = 0; i2 < dim[2]; i2++) { - operator()(i0, i1, i2) = vec.at(i0).at(i1).at(i2); - - } - } - } - - } - - /** - * Parametrized constructor from vector> container - * @param vec container - * @param array_name array name - */ - Array3D(const vector>> &vec, const string &array_name = "Array3D") { - this->set_vector(vec); - this->array_name = array_name; - } - - /** - * operator= to vector> container - * @param vec container - */ - Array3D &operator=(const vector>> &vec) { - this->set_vector(vec); - return *this; - } - - - /** - * operator= to flatten vector container - * @param vec container - */ - Array3D &operator=(const vector &vec) { - this->set_flatten_vector(vec); - return *this; - } - - - vector get_shape() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = dim[d]; - return sh; - } - - vector get_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d]; - return sh; - } - - vector get_memory_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d] * sizeof(T); - return sh; - } -}; - - -/** - * Multidimensional (4 - dimensional) array of type T with contiguous memory layout. - * If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @tparam T data type - */ -template -class Array4D : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - using ContiguousArrayND::is_proxy_; - - size_t dim[4] = {0}; ///< dimensions - size_t s[4] = {0}; ///< strides - int ndim = 4; ///< number of dimensions -public: - - /** - * Default empty constructor - */ - Array4D() = default; - - /** - * Parametrized constructor with array name - * @param array_name name of array (for error logging) - */ - Array4D(const string &array_name) { this->array_name = array_name; } - - /** - * Parametrized constructor - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - Array4D(size_t d0, size_t d1, size_t d2, size_t d3, const string &array_name = "Array4D", T *new_data = nullptr) { - init(d0, d1, d2, d3, array_name, new_data); - } - - /** - * Setup the dimensions and strides of array - * @param d0,... array sizes for different dimensions - */ - void set_dimensions(size_t d0, size_t d1, size_t d2, size_t d3) { - - dim[0] = d0; - dim[1] = d1; - dim[2] = d2; - dim[3] = d3; - - s[3] = 1; - s[2] = s[3] * dim[3]; - s[1] = s[2] * dim[2]; - s[0] = s[1] * dim[1]; - - size = s[0] * dim[0]; - }; - - /** - * Initialize array storage, dimensions and strides - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - void init(size_t d0, size_t d1, size_t d2, size_t d3, const string &array_name = "Array4D", T *new_data = nullptr) { - this->array_name = array_name; - - size_t old_size = size; - set_dimensions(d0, d1, d2, d3); - - bool new_is_proxy = (new_data != nullptr); - - if (new_is_proxy) { - if (!is_proxy_) delete[] data; - data = new_data; - } else { - if (size != old_size) { - T *old_data = data; //preserve the pointer to the old data - data = new T[size]; // allocate new data - if (old_data != nullptr) { // - size_t min_size = old_size < size ? old_size : size; - memcpy(data, old_data, min_size * sizeof(T)); - if (!is_proxy_) delete[] old_data; - } - //memset(data, 0, size * sizeof(T)); - } else { - //memset(data, 0, size * sizeof(T)); - } - } - - is_proxy_ = new_is_proxy; - } - - /** - * Resize array - * @param d0,... array sizes for different dimensions - */ - void resize(size_t d0, size_t d1, size_t d2, size_t d3) { - init(d0, d1, d2, d3, this->array_name); - } - - /** - * Reshape array without reset the data - * @param d0,... array sizes for different dimensions - */ - void reshape(size_t d0, size_t d1, size_t d2, size_t d3) { - //check data size consistency - size_t new_size = d0 * d1 * d2 * d3; - if (new_size != size) - throw invalid_argument("Couldn't reshape array when the size is not conserved"); - set_dimensions(d0, d1, d2, d3); - } - - /** - * Get array size in dimension "d" - * @param d dimension index - */ - size_t get_dim(int d) const { - return dim[d]; - } - -#ifdef MULTIARRAY_INDICES_CHECK - - /** - * Check indices validity. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - void check_indices(size_t i0, size_t i1, size_t i2, size_t i3) const { - - if ((i0 < 0) | (i0 >= dim[0])) { - char buf[1024]; - sprintf(buf, "%s: index i0=%ld out of range (0, %ld)\n", array_name.c_str(), i0, dim[0] - 1); - throw std::out_of_range(buf); - } - - if ((i1 < 0) | (i1 >= dim[1])) { - char buf[1024]; - sprintf(buf, "%s: index i1=%ld out of range (0, %ld)\n", array_name.c_str(), i1, dim[1] - 1); - throw std::out_of_range(buf); - } - - if ((i2 < 0) | (i2 >= dim[2])) { - char buf[1024]; - sprintf(buf, "%s: index i2=%ld out of range (0, %ld)\n", array_name.c_str(), i2, dim[2] - 1); - throw std::out_of_range(buf); - } - - if ((i3 < 0) | (i3 >= dim[3])) { - char buf[1024]; - sprintf(buf, "%s: index i3=%ld out of range (0, %ld)\n", array_name.c_str(), i3, dim[3] - 1); - throw std::out_of_range(buf); - } - - } - -#endif - - /** - * Array access operator() for reading. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline const T &operator()(size_t i0, size_t i1, size_t i2, size_t i3) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, i2, i3); -#endif - - return data[i0 * s[0] + i1 * s[1] + i2 * s[2] + i3]; - - } - - /** - * Array access operator() for writing. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline T &operator()(size_t i0, size_t i1, size_t i2, size_t i3) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, i2, i3); -#endif - - return data[i0 * s[0] + i1 * s[1] + i2 * s[2] + i3]; - - } - - /** - * Array comparison operator - * @param other - */ - bool operator==(const Array4D &other) const { - //compare dimensions - for (int d = 0; d < ndim; d++) { - if (this->dim[d] != other.dim[d]) - return false; - } - return ContiguousArrayND::operator==(other); - } - - /** - * Convert to nested vector> container - * @return vector container - */ - vector>>> to_vector() const { - vector>>> res; - - res.resize(dim[0]); - - for (int i0 = 0; i0 < dim[0]; i0++) { - res[i0].resize(dim[1]); - - - for (int i1 = 0; i1 < dim[1]; i1++) { - res[i0][i1].resize(dim[2]); - - - for (int i2 = 0; i2 < dim[2]; i2++) { - res[i0][i1][i2].resize(dim[3]); - - - for (int i3 = 0; i3 < dim[3]; i3++) { - res[i0][i1][i2][i3] = operator()(i0, i1, i2, i3); - - } - } - } - } - - - return res; - } // end to_vector() - - - /** - * Set values to vector> container - * @param vec container - */ - void set_vector(const vector>>> &vec) { - size_t d0 = 0; - size_t d1 = 0; - size_t d2 = 0; - size_t d3 = 0; - d0 = vec.size(); - - if (d0 > 0) { - d1 = vec.at(0).size(); - if (d1 > 0) { - d2 = vec.at(0).at(0).size(); - if (d2 > 0) { - d3 = vec.at(0).at(0).at(0).size(); - - - } - } - } - - init(d0, d1, d2, d3, array_name); - for (int i0 = 0; i0 < dim[0]; i0++) { - if (vec.at(i0).size() != d1) - throw std::invalid_argument("Vector size is not constant at dimension 1"); - - for (int i1 = 0; i1 < dim[1]; i1++) { - if (vec.at(i0).at(i1).size() != d2) - throw std::invalid_argument("Vector size is not constant at dimension 2"); - - for (int i2 = 0; i2 < dim[2]; i2++) { - if (vec.at(i0).at(i1).at(i2).size() != d3) - throw std::invalid_argument("Vector size is not constant at dimension 3"); - - for (int i3 = 0; i3 < dim[3]; i3++) { - operator()(i0, i1, i2, i3) = vec.at(i0).at(i1).at(i2).at(i3); - - } - } - } - } - - } - - /** - * Parametrized constructor from vector> container - * @param vec container - * @param array_name array name - */ - Array4D(const vector>>> &vec, const string &array_name = "Array4D") { - this->set_vector(vec); - this->array_name = array_name; - } - - /** - * operator= to vector> container - * @param vec container - */ - Array4D &operator=(const vector>>> &vec) { - this->set_vector(vec); - return *this; - } - - - /** - * operator= to flatten vector container - * @param vec container - */ - Array4D &operator=(const vector &vec) { - this->set_flatten_vector(vec); - return *this; - } - - - vector get_shape() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = dim[d]; - return sh; - } - - vector get_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d]; - return sh; - } - - vector get_memory_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d] * sizeof(T); - return sh; - } -}; - - -/** - * Multidimensional (5 - dimensional) array of type T with contiguous memory layout. - * If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @tparam T data type - */ -template -class Array5D : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - using ContiguousArrayND::is_proxy_; - - size_t dim[5] = {0}; ///< dimensions - size_t s[5] = {0}; ///< strides - int ndim = 5; ///< number of dimensions -public: - - /** - * Default empty constructor - */ - Array5D() = default; - - /** - * Parametrized constructor with array name - * @param array_name name of array (for error logging) - */ - Array5D(const string &array_name) { this->array_name = array_name; } - - /** - * Parametrized constructor - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - Array5D(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4, const string &array_name = "Array5D", - T *new_data = nullptr) { - init(d0, d1, d2, d3, d4, array_name, new_data); - } - - /** - * Setup the dimensions and strides of array - * @param d0,... array sizes for different dimensions - */ - void set_dimensions(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4) { - - dim[0] = d0; - dim[1] = d1; - dim[2] = d2; - dim[3] = d3; - dim[4] = d4; - - s[4] = 1; - s[3] = s[4] * dim[4]; - s[2] = s[3] * dim[3]; - s[1] = s[2] * dim[2]; - s[0] = s[1] * dim[1]; - - size = s[0] * dim[0]; - }; - - /** - * Initialize array storage, dimensions and strides - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - void init(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4, const string &array_name = "Array5D", - T *new_data = nullptr) { - this->array_name = array_name; - - size_t old_size = size; - set_dimensions(d0, d1, d2, d3, d4); - - bool new_is_proxy = (new_data != nullptr); - - if (new_is_proxy) { - if (!is_proxy_) delete[] data; - data = new_data; - } else { - if (size != old_size) { - T *old_data = data; //preserve the pointer to the old data - data = new T[size]; // allocate new data - if (old_data != nullptr) { // - size_t min_size = old_size < size ? old_size : size; - memcpy(data, old_data, min_size * sizeof(T)); - if (!is_proxy_) delete[] old_data; - } - //memset(data, 0, size * sizeof(T)); - } else { - //memset(data, 0, size * sizeof(T)); - } - } - - is_proxy_ = new_is_proxy; - } - - /** - * Resize array - * @param d0,... array sizes for different dimensions - */ - void resize(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4) { - init(d0, d1, d2, d3, d4, this->array_name); - } - - /** - * Reshape array without reset the data - * @param d0,... array sizes for different dimensions - */ - void reshape(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4) { - //check data size consistency - size_t new_size = d0 * d1 * d2 * d3 * d4; - if (new_size != size) - throw invalid_argument("Couldn't reshape array when the size is not conserved"); - set_dimensions(d0, d1, d2, d3, d4); - } - - /** - * Get array size in dimension "d" - * @param d dimension index - */ - size_t get_dim(int d) const { - return dim[d]; - } - -#ifdef MULTIARRAY_INDICES_CHECK - - /** - * Check indices validity. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - void check_indices(size_t i0, size_t i1, size_t i2, size_t i3, size_t i4) const { - - if ((i0 < 0) | (i0 >= dim[0])) { - char buf[1024]; - sprintf(buf, "%s: index i0=%ld out of range (0, %ld)\n", array_name.c_str(), i0, dim[0] - 1); - throw std::out_of_range(buf); - } - - if ((i1 < 0) | (i1 >= dim[1])) { - char buf[1024]; - sprintf(buf, "%s: index i1=%ld out of range (0, %ld)\n", array_name.c_str(), i1, dim[1] - 1); - throw std::out_of_range(buf); - } - - if ((i2 < 0) | (i2 >= dim[2])) { - char buf[1024]; - sprintf(buf, "%s: index i2=%ld out of range (0, %ld)\n", array_name.c_str(), i2, dim[2] - 1); - throw std::out_of_range(buf); - } - - if ((i3 < 0) | (i3 >= dim[3])) { - char buf[1024]; - sprintf(buf, "%s: index i3=%ld out of range (0, %ld)\n", array_name.c_str(), i3, dim[3] - 1); - throw std::out_of_range(buf); - } - - if ((i4 < 0) | (i4 >= dim[4])) { - char buf[1024]; - sprintf(buf, "%s: index i4=%ld out of range (0, %ld)\n", array_name.c_str(), i4, dim[4] - 1); - throw std::out_of_range(buf); - } - - } - -#endif - - /** - * Array access operator() for reading. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline const T &operator()(size_t i0, size_t i1, size_t i2, size_t i3, size_t i4) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, i2, i3, i4); -#endif - - return data[i0 * s[0] + i1 * s[1] + i2 * s[2] + i3 * s[3] + i4]; - - } - - /** - * Array access operator() for writing. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline T &operator()(size_t i0, size_t i1, size_t i2, size_t i3, size_t i4) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, i2, i3, i4); -#endif - - return data[i0 * s[0] + i1 * s[1] + i2 * s[2] + i3 * s[3] + i4]; - - } - - /** - * Array comparison operator - * @param other - */ - bool operator==(const Array5D &other) const { - //compare dimensions - for (int d = 0; d < ndim; d++) { - if (this->dim[d] != other.dim[d]) - return false; - } - return ContiguousArrayND::operator==(other); - } - - /** - * Convert to nested vector> container - * @return vector container - */ - vector>>>> to_vector() const { - vector>>>> res; - - res.resize(dim[0]); - - for (int i0 = 0; i0 < dim[0]; i0++) { - res[i0].resize(dim[1]); - - - for (int i1 = 0; i1 < dim[1]; i1++) { - res[i0][i1].resize(dim[2]); - - - for (int i2 = 0; i2 < dim[2]; i2++) { - res[i0][i1][i2].resize(dim[3]); - - - for (int i3 = 0; i3 < dim[3]; i3++) { - res[i0][i1][i2][i3].resize(dim[4]); - - - for (int i4 = 0; i4 < dim[4]; i4++) { - res[i0][i1][i2][i3][i4] = operator()(i0, i1, i2, i3, i4); - - } - } - } - } - } - - - return res; - } // end to_vector() - - - /** - * Set values to vector> container - * @param vec container - */ - void set_vector(const vector>>>> &vec) { - size_t d0 = 0; - size_t d1 = 0; - size_t d2 = 0; - size_t d3 = 0; - size_t d4 = 0; - d0 = vec.size(); - - if (d0 > 0) { - d1 = vec.at(0).size(); - if (d1 > 0) { - d2 = vec.at(0).at(0).size(); - if (d2 > 0) { - d3 = vec.at(0).at(0).at(0).size(); - if (d3 > 0) { - d4 = vec.at(0).at(0).at(0).at(0).size(); - - - } - } - } - } - - init(d0, d1, d2, d3, d4, array_name); - for (int i0 = 0; i0 < dim[0]; i0++) { - if (vec.at(i0).size() != d1) - throw std::invalid_argument("Vector size is not constant at dimension 1"); - - for (int i1 = 0; i1 < dim[1]; i1++) { - if (vec.at(i0).at(i1).size() != d2) - throw std::invalid_argument("Vector size is not constant at dimension 2"); - - for (int i2 = 0; i2 < dim[2]; i2++) { - if (vec.at(i0).at(i1).at(i2).size() != d3) - throw std::invalid_argument("Vector size is not constant at dimension 3"); - - for (int i3 = 0; i3 < dim[3]; i3++) { - if (vec.at(i0).at(i1).at(i2).at(i3).size() != d4) - throw std::invalid_argument("Vector size is not constant at dimension 4"); - - for (int i4 = 0; i4 < dim[4]; i4++) { - operator()(i0, i1, i2, i3, i4) = vec.at(i0).at(i1).at(i2).at(i3).at(i4); - - } - } - } - } - } - - } - - /** - * Parametrized constructor from vector> container - * @param vec container - * @param array_name array name - */ - Array5D(const vector>>>> &vec, const string &array_name = "Array5D") { - this->set_vector(vec); - this->array_name = array_name; - } - - /** - * operator= to vector> container - * @param vec container - */ - Array5D &operator=(const vector>>>> &vec) { - this->set_vector(vec); - return *this; - } - - - /** - * operator= to flatten vector container - * @param vec container - */ - Array5D &operator=(const vector &vec) { - this->set_flatten_vector(vec); - return *this; - } - - - vector get_shape() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = dim[d]; - return sh; - } - - vector get_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d]; - return sh; - } - - vector get_memory_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d] * sizeof(T); - return sh; - } -}; - - -/** - * Multidimensional (6 - dimensional) array of type T with contiguous memory layout. - * If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @tparam T data type - */ -template -class Array6D : public ContiguousArrayND { - using ContiguousArrayND::array_name; - using ContiguousArrayND::data; - using ContiguousArrayND::size; - using ContiguousArrayND::is_proxy_; - - size_t dim[6] = {0}; ///< dimensions - size_t s[6] = {0}; ///< strides - int ndim = 6; ///< number of dimensions -public: - - /** - * Default empty constructor - */ - Array6D() = default; - - /** - * Parametrized constructor with array name - * @param array_name name of array (for error logging) - */ - Array6D(const string &array_name) { this->array_name = array_name; } - - /** - * Parametrized constructor - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - Array6D(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4, size_t d5, const string &array_name = "Array6D", - T *new_data = nullptr) { - init(d0, d1, d2, d3, d4, d5, array_name, new_data); - } - - /** - * Setup the dimensions and strides of array - * @param d0,... array sizes for different dimensions - */ - void set_dimensions(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4, size_t d5) { - - dim[0] = d0; - dim[1] = d1; - dim[2] = d2; - dim[3] = d3; - dim[4] = d4; - dim[5] = d5; - - s[5] = 1; - s[4] = s[5] * dim[5]; - s[3] = s[4] * dim[4]; - s[2] = s[3] * dim[3]; - s[1] = s[2] * dim[2]; - s[0] = s[1] * dim[1]; - - size = s[0] * dim[0]; - }; - - /** - * Initialize array storage, dimensions and strides - * @param d0,... array sizes for different dimensions - * @param array_name string name of the array - */ - void init(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4, size_t d5, const string &array_name = "Array6D", - T *new_data = nullptr) { - this->array_name = array_name; - - size_t old_size = size; - set_dimensions(d0, d1, d2, d3, d4, d5); - - bool new_is_proxy = (new_data != nullptr); - - if (new_is_proxy) { - if (!is_proxy_) delete[] data; - data = new_data; - } else { - if (size != old_size) { - T *old_data = data; //preserve the pointer to the old data - data = new T[size]; // allocate new data - if (old_data != nullptr) { // - size_t min_size = old_size < size ? old_size : size; - memcpy(data, old_data, min_size * sizeof(T)); - if (!is_proxy_) delete[] old_data; - } - //memset(data, 0, size * sizeof(T)); - } else { - //memset(data, 0, size * sizeof(T)); - } - } - - is_proxy_ = new_is_proxy; - } - - /** - * Resize array - * @param d0,... array sizes for different dimensions - */ - void resize(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4, size_t d5) { - init(d0, d1, d2, d3, d4, d5, this->array_name); - } - - /** - * Reshape array without reset the data - * @param d0,... array sizes for different dimensions - */ - void reshape(size_t d0, size_t d1, size_t d2, size_t d3, size_t d4, size_t d5) { - //check data size consistency - size_t new_size = d0 * d1 * d2 * d3 * d4 * d5; - if (new_size != size) - throw invalid_argument("Couldn't reshape array when the size is not conserved"); - set_dimensions(d0, d1, d2, d3, d4, d5); - } - - /** - * Get array size in dimension "d" - * @param d dimension index - */ - size_t get_dim(int d) const { - return dim[d]; - } - -#ifdef MULTIARRAY_INDICES_CHECK - - /** - * Check indices validity. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - void check_indices(size_t i0, size_t i1, size_t i2, size_t i3, size_t i4, size_t i5) const { - - if ((i0 < 0) | (i0 >= dim[0])) { - char buf[1024]; - sprintf(buf, "%s: index i0=%ld out of range (0, %ld)\n", array_name.c_str(), i0, dim[0] - 1); - throw std::out_of_range(buf); - } - - if ((i1 < 0) | (i1 >= dim[1])) { - char buf[1024]; - sprintf(buf, "%s: index i1=%ld out of range (0, %ld)\n", array_name.c_str(), i1, dim[1] - 1); - throw std::out_of_range(buf); - } - - if ((i2 < 0) | (i2 >= dim[2])) { - char buf[1024]; - sprintf(buf, "%s: index i2=%ld out of range (0, %ld)\n", array_name.c_str(), i2, dim[2] - 1); - throw std::out_of_range(buf); - } - - if ((i3 < 0) | (i3 >= dim[3])) { - char buf[1024]; - sprintf(buf, "%s: index i3=%ld out of range (0, %ld)\n", array_name.c_str(), i3, dim[3] - 1); - throw std::out_of_range(buf); - } - - if ((i4 < 0) | (i4 >= dim[4])) { - char buf[1024]; - sprintf(buf, "%s: index i4=%ld out of range (0, %ld)\n", array_name.c_str(), i4, dim[4] - 1); - throw std::out_of_range(buf); - } - - if ((i5 < 0) | (i5 >= dim[5])) { - char buf[1024]; - sprintf(buf, "%s: index i5=%ld out of range (0, %ld)\n", array_name.c_str(), i5, dim[5] - 1); - throw std::out_of_range(buf); - } - - } - -#endif - - /** - * Array access operator() for reading. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline const T &operator()(size_t i0, size_t i1, size_t i2, size_t i3, size_t i4, size_t i5) const { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, i2, i3, i4, i5); -#endif - - return data[i0 * s[0] + i1 * s[1] + i2 * s[2] + i3 * s[3] + i4 * s[4] + i5]; - - } - - /** - * Array access operator() for writing. If preprocessor macro MULTIARRAY_INDICES_CHECK is defined, then the check of index will - * be performed before accessing memory. By default this is turned off. - * @param i0,... indices - */ - inline T &operator()(size_t i0, size_t i1, size_t i2, size_t i3, size_t i4, size_t i5) { -#ifdef MULTIARRAY_INDICES_CHECK - check_indices(i0, i1, i2, i3, i4, i5); -#endif - - return data[i0 * s[0] + i1 * s[1] + i2 * s[2] + i3 * s[3] + i4 * s[4] + i5]; - - } - - /** - * Array comparison operator - * @param other - */ - bool operator==(const Array6D &other) const { - //compare dimensions - for (int d = 0; d < ndim; d++) { - if (this->dim[d] != other.dim[d]) - return false; - } - return ContiguousArrayND::operator==(other); - } - - /** - * Convert to nested vector> container - * @return vector container - */ - vector>>>>> to_vector() const { - vector>>>>> res; - - res.resize(dim[0]); - - for (int i0 = 0; i0 < dim[0]; i0++) { - res[i0].resize(dim[1]); - - - for (int i1 = 0; i1 < dim[1]; i1++) { - res[i0][i1].resize(dim[2]); - - - for (int i2 = 0; i2 < dim[2]; i2++) { - res[i0][i1][i2].resize(dim[3]); - - - for (int i3 = 0; i3 < dim[3]; i3++) { - res[i0][i1][i2][i3].resize(dim[4]); - - - for (int i4 = 0; i4 < dim[4]; i4++) { - res[i0][i1][i2][i3][i4].resize(dim[5]); - - - for (int i5 = 0; i5 < dim[5]; i5++) { - res[i0][i1][i2][i3][i4][i5] = operator()(i0, i1, i2, i3, i4, i5); - - } - } - } - } - } - } - - - return res; - } // end to_vector() - - - /** - * Set values to vector> container - * @param vec container - */ - void set_vector(const vector>>>>> &vec) { - size_t d0 = 0; - size_t d1 = 0; - size_t d2 = 0; - size_t d3 = 0; - size_t d4 = 0; - size_t d5 = 0; - d0 = vec.size(); - - if (d0 > 0) { - d1 = vec.at(0).size(); - if (d1 > 0) { - d2 = vec.at(0).at(0).size(); - if (d2 > 0) { - d3 = vec.at(0).at(0).at(0).size(); - if (d3 > 0) { - d4 = vec.at(0).at(0).at(0).at(0).size(); - if (d4 > 0) { - d5 = vec.at(0).at(0).at(0).at(0).at(0).size(); - - - } - } - } - } - } - - init(d0, d1, d2, d3, d4, d5, array_name); - for (int i0 = 0; i0 < dim[0]; i0++) { - if (vec.at(i0).size() != d1) - throw std::invalid_argument("Vector size is not constant at dimension 1"); - - for (int i1 = 0; i1 < dim[1]; i1++) { - if (vec.at(i0).at(i1).size() != d2) - throw std::invalid_argument("Vector size is not constant at dimension 2"); - - for (int i2 = 0; i2 < dim[2]; i2++) { - if (vec.at(i0).at(i1).at(i2).size() != d3) - throw std::invalid_argument("Vector size is not constant at dimension 3"); - - for (int i3 = 0; i3 < dim[3]; i3++) { - if (vec.at(i0).at(i1).at(i2).at(i3).size() != d4) - throw std::invalid_argument("Vector size is not constant at dimension 4"); - - for (int i4 = 0; i4 < dim[4]; i4++) { - if (vec.at(i0).at(i1).at(i2).at(i3).at(i4).size() != d5) - throw std::invalid_argument("Vector size is not constant at dimension 5"); - - for (int i5 = 0; i5 < dim[5]; i5++) { - operator()(i0, i1, i2, i3, i4, i5) = vec.at(i0).at(i1).at(i2).at(i3).at(i4).at(i5); - - } - } - } - } - } - } - - } - - /** - * Parametrized constructor from vector> container - * @param vec container - * @param array_name array name - */ - Array6D(const vector>>>>> &vec, const string &array_name = "Array6D") { - this->set_vector(vec); - this->array_name = array_name; - } - - /** - * operator= to vector> container - * @param vec container - */ - Array6D &operator=(const vector>>>>> &vec) { - this->set_vector(vec); - return *this; - } - - - /** - * operator= to flatten vector container - * @param vec container - */ - Array6D &operator=(const vector &vec) { - this->set_flatten_vector(vec); - return *this; - } - - - vector get_shape() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = dim[d]; - return sh; - } - - vector get_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d]; - return sh; - } - - vector get_memory_strides() const { - vector sh(ndim); - for (int d = 0; d < ndim; d++) - sh[d] = s[d] * sizeof(T); - return sh; - } -}; - - -#endif //ACE_MULTIARRAY_H diff --git a/lib/pace/ace_c_basis.cpp b/lib/pace/ace_c_basis.cpp deleted file mode 100644 index d1c55700b7..0000000000 --- a/lib/pace/ace_c_basis.cpp +++ /dev/null @@ -1,980 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Yury Lysogorskiy on 1.04.20. - -#include "ace_c_basis.h" -#include "ships_radial.h" - -using namespace std; - -ACECTildeBasisSet::ACECTildeBasisSet(string filename) { - load(filename); -} - -ACECTildeBasisSet::ACECTildeBasisSet(const ACECTildeBasisSet &other) { - ACECTildeBasisSet::_copy_scalar_memory(other); - ACECTildeBasisSet::_copy_dynamic_memory(other); - pack_flatten_basis(); -} - - -ACECTildeBasisSet &ACECTildeBasisSet::operator=(const ACECTildeBasisSet &other) { - if (this != &other) { - _clean(); - _copy_scalar_memory(other); - _copy_dynamic_memory(other); - pack_flatten_basis(); - } - return *this; -} - - -ACECTildeBasisSet::~ACECTildeBasisSet() { - ACECTildeBasisSet::_clean(); -} - -void ACECTildeBasisSet::_clean() { - // call parent method - ACEFlattenBasisSet::_clean(); - _clean_contiguous_arrays(); - _clean_basis_arrays(); -} - -void ACECTildeBasisSet::_copy_scalar_memory(const ACECTildeBasisSet &src) { - ACEFlattenBasisSet::_copy_scalar_memory(src); - num_ctilde_max = src.num_ctilde_max; -} - -void ACECTildeBasisSet::_copy_dynamic_memory(const ACECTildeBasisSet &src) {//allocate new memory - ACEFlattenBasisSet::_copy_dynamic_memory(src); - - if (src.basis_rank1 == nullptr) - throw runtime_error("Could not copy ACECTildeBasisSet::basis_rank1 - array not initialized"); - if (src.basis == nullptr) throw runtime_error("Could not copy ACECTildeBasisSet::basis - array not initialized"); - - - basis_rank1 = new ACECTildeBasisFunction *[src.nelements]; - basis = new ACECTildeBasisFunction *[src.nelements]; - - //copy basis arrays - for (SPECIES_TYPE mu = 0; mu < src.nelements; ++mu) { - basis_rank1[mu] = new ACECTildeBasisFunction[src.total_basis_size_rank1[mu]]; - - for (size_t i = 0; i < src.total_basis_size_rank1[mu]; i++) { - basis_rank1[mu][i] = src.basis_rank1[mu][i]; - } - - - basis[mu] = new ACECTildeBasisFunction[src.total_basis_size[mu]]; - for (size_t i = 0; i < src.total_basis_size[mu]; i++) { - basis[mu][i] = src.basis[mu][i]; - } - } - //DON"T COPY CONTIGUOUS ARRAY, REBUILD THEM -} - -void ACECTildeBasisSet::_clean_contiguous_arrays() { - ACEFlattenBasisSet::_clean_contiguous_arrays(); - - delete[] full_c_tildes_rank1; - full_c_tildes_rank1 = nullptr; - - delete[] full_c_tildes; - full_c_tildes = nullptr; -} - -//re-pack the constituent dynamic arrays of all basis functions in contiguous arrays -void ACECTildeBasisSet::pack_flatten_basis() { - compute_array_sizes(basis_rank1, basis); - - //1. clean contiguous arrays - _clean_contiguous_arrays(); - //2. allocate contiguous arrays - delete[] full_ns_rank1; - full_ns_rank1 = new NS_TYPE[rank_array_total_size_rank1]; - delete[] full_ls_rank1; - full_ls_rank1 = new NS_TYPE[rank_array_total_size_rank1]; - delete[] full_mus_rank1; - full_mus_rank1 = new SPECIES_TYPE[rank_array_total_size_rank1]; - delete[] full_ms_rank1; - full_ms_rank1 = new MS_TYPE[rank_array_total_size_rank1]; - - delete[] full_c_tildes_rank1; - full_c_tildes_rank1 = new DOUBLE_TYPE[coeff_array_total_size_rank1]; - - - delete[] full_ns; - full_ns = new NS_TYPE[rank_array_total_size]; - delete[] full_ls; - full_ls = new LS_TYPE[rank_array_total_size]; - delete[] full_mus; - full_mus = new SPECIES_TYPE[rank_array_total_size]; - delete[] full_ms; - full_ms = new MS_TYPE[ms_array_total_size]; - - delete[] full_c_tildes; - full_c_tildes = new DOUBLE_TYPE[coeff_array_total_size]; - - - //3. copy the values from private C_tilde_B_basis_function arrays to new contigous space - //4. clean private memory - //5. reassign private array pointers - - //r = 0, rank = 1 - size_t rank_array_ind_rank1 = 0; - size_t coeff_array_ind_rank1 = 0; - size_t ms_array_ind_rank1 = 0; - - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - for (int func_ind_r1 = 0; func_ind_r1 < total_basis_size_rank1[mu]; ++func_ind_r1) { - ACECTildeBasisFunction &func = basis_rank1[mu][func_ind_r1]; - - //copy values ns from c_tilde_basis_function private memory to contigous memory part - full_ns_rank1[rank_array_ind_rank1] = func.ns[0]; - - //copy values ls from c_tilde_basis_function private memory to contigous memory part - full_ls_rank1[rank_array_ind_rank1] = func.ls[0]; - - //copy values mus from c_tilde_basis_function private memory to contigous memory part - full_mus_rank1[rank_array_ind_rank1] = func.mus[0]; - - //copy values ctildes from c_tilde_basis_function private memory to contigous memory part - memcpy(&full_c_tildes_rank1[coeff_array_ind_rank1], func.ctildes, - func.ndensity * sizeof(DOUBLE_TYPE)); - - - //copy values mus from c_tilde_basis_function private memory to contigous memory part - memcpy(&full_ms_rank1[ms_array_ind_rank1], func.ms_combs, - func.num_ms_combs * - func.rank * sizeof(MS_TYPE)); - - //release memory of each ACECTildeBasisFunction if it is not proxy - func._clean(); - - func.mus = &full_mus_rank1[rank_array_ind_rank1]; - func.ns = &full_ns_rank1[rank_array_ind_rank1]; - func.ls = &full_ls_rank1[rank_array_ind_rank1]; - func.ms_combs = &full_ms_rank1[ms_array_ind_rank1]; - func.ctildes = &full_c_tildes_rank1[coeff_array_ind_rank1]; - func.is_proxy = true; - - rank_array_ind_rank1 += func.rank; - ms_array_ind_rank1 += func.rank * - func.num_ms_combs; - coeff_array_ind_rank1 += func.num_ms_combs * func.ndensity; - - } - } - - - //rank>1, r>0 - size_t rank_array_ind = 0; - size_t coeff_array_ind = 0; - size_t ms_array_ind = 0; - - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - for (int func_ind = 0; func_ind < total_basis_size[mu]; ++func_ind) { - ACECTildeBasisFunction &func = basis[mu][func_ind]; - - //copy values mus from c_tilde_basis_function private memory to contigous memory part - memcpy(&full_mus[rank_array_ind], func.mus, - func.rank * sizeof(SPECIES_TYPE)); - - //copy values ns from c_tilde_basis_function private memory to contigous memory part - memcpy(&full_ns[rank_array_ind], func.ns, - func.rank * sizeof(NS_TYPE)); - //copy values ls from c_tilde_basis_function private memory to contigous memory part - memcpy(&full_ls[rank_array_ind], func.ls, - func.rank * sizeof(LS_TYPE)); - //copy values mus from c_tilde_basis_function private memory to contigous memory part - memcpy(&full_ms[ms_array_ind], func.ms_combs, - func.num_ms_combs * - func.rank * sizeof(MS_TYPE)); - - //copy values ctildes from c_tilde_basis_function private memory to contigous memory part - memcpy(&full_c_tildes[coeff_array_ind], func.ctildes, - func.num_ms_combs * func.ndensity * sizeof(DOUBLE_TYPE)); - - - //release memory of each ACECTildeBasisFunction if it is not proxy - func._clean(); - - func.ns = &full_ns[rank_array_ind]; - func.ls = &full_ls[rank_array_ind]; - func.mus = &full_mus[rank_array_ind]; - func.ctildes = &full_c_tildes[coeff_array_ind]; - func.ms_combs = &full_ms[ms_array_ind]; - func.is_proxy = true; - - rank_array_ind += func.rank; - ms_array_ind += func.rank * - func.num_ms_combs; - coeff_array_ind += func.num_ms_combs * func.ndensity; - } - } -} - -void fwrite_c_tilde_b_basis_func(FILE *fptr, ACECTildeBasisFunction &func) { - RANK_TYPE r; - fprintf(fptr, "ctilde_basis_func: "); - fprintf(fptr, "rank=%d ndens=%d mu0=%d ", func.rank, func.ndensity, func.mu0); - - fprintf(fptr, "mu=("); - for (r = 0; r < func.rank; ++r) - fprintf(fptr, " %d ", func.mus[r]); - fprintf(fptr, ")\n"); - - fprintf(fptr, "n=("); - for (r = 0; r < func.rank; ++r) - fprintf(fptr, " %d ", func.ns[r]); - fprintf(fptr, ")\n"); - - fprintf(fptr, "l=("); - for (r = 0; r < func.rank; ++r) - fprintf(fptr, " %d ", func.ls[r]); - fprintf(fptr, ")\n"); - - fprintf(fptr, "num_ms=%d\n", func.num_ms_combs); - - for (int m_ind = 0; m_ind < func.num_ms_combs; m_ind++) { - fprintf(fptr, "<"); - for (r = 0; r < func.rank; ++r) - fprintf(fptr, " %d ", func.ms_combs[m_ind * func.rank + r]); - fprintf(fptr, ">: "); - for (DENSITY_TYPE p = 0; p < func.ndensity; p++) - fprintf(fptr, " %.18f ", func.ctildes[m_ind * func.ndensity + p]); - fprintf(fptr, "\n"); - } - -} - -void ACECTildeBasisSet::save(const string &filename) { - FILE *fptr; - fptr = fopen(filename.c_str(), "w"); - - fprintf(fptr, "nelements=%d\n", nelements); - - //elements mapping - fprintf(fptr, "elements:"); - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) - fprintf(fptr, " %s", elements_name[mu].c_str()); - fprintf(fptr, "\n\n"); - - fprintf(fptr, "lmax=%d\n\n", lmax); - - fprintf(fptr, "embedding-function: %s\n", npoti.c_str()); - - fprintf(fptr, "%ld FS parameters: ", FS_parameters.size()); - for (int i = 0; i < FS_parameters.size(); ++i) { - fprintf(fptr, " %f", FS_parameters.at(i)); - } - fprintf(fptr, "\n"); - - //hard-core energy cutoff repulsion - fprintf(fptr, "core energy-cutoff parameters: "); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - fprintf(fptr, "%.18f %.18f\n", rho_core_cutoffs(mu_i), drho_core_cutoffs(mu_i)); - - // save E0 values - fprintf(fptr, "E0:"); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - fprintf(fptr, " %.18f", E0vals(mu_i)); - fprintf(fptr, "\n"); - - - fprintf(fptr, "\n"); - - - fprintf(fptr, "radbasename=%s\n", radial_functions->radbasename.c_str()); - fprintf(fptr, "nradbase=%d\n", nradbase); - fprintf(fptr, "nradmax=%d\n", nradmax); - - - fprintf(fptr, "cutoffmax=%f\n", cutoffmax); - - fprintf(fptr, "deltaSplineBins=%f\n", deltaSplineBins); - - //hard-core repulsion - fprintf(fptr, "core repulsion parameters: "); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) - fprintf(fptr, "%.18f %.18f\n", radial_functions->prehc(mu_i, mu_j), radial_functions->lambdahc(mu_j, mu_j)); - - - - - - //TODO: radial functions - //radparameter - fprintf(fptr, "radparameter="); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) - fprintf(fptr, " %.18f", radial_functions->lambda(mu_i, mu_j)); - fprintf(fptr, "\n"); - - fprintf(fptr, "cutoff="); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) - fprintf(fptr, " %.18f", radial_functions->cut(mu_i, mu_j)); - fprintf(fptr, "\n"); - - fprintf(fptr, "dcut="); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) - fprintf(fptr, " %.18f", radial_functions->dcut(mu_i, mu_j)); - fprintf(fptr, "\n"); - - fprintf(fptr, "crad="); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) { - for (NS_TYPE k = 0; k < nradbase; k++) { - for (NS_TYPE n = 0; n < nradmax; n++) { - for (LS_TYPE l = 0; l <= lmax; l++) { - fprintf(fptr, " %.18f", radial_functions->crad(mu_i, mu_j, n, l, k)); - } - fprintf(fptr, "\n"); - } - } - } - - fprintf(fptr, "\n"); - - fprintf(fptr, "rankmax=%d\n", rankmax); - fprintf(fptr, "ndensitymax=%d\n", ndensitymax); - fprintf(fptr, "\n"); - - //num_c_tilde_max - fprintf(fptr, "num_c_tilde_max=%d\n", num_ctilde_max); - fprintf(fptr, "num_ms_combinations_max=%d\n", num_ms_combinations_max); - - - //write total_basis_size and total_basis_size_rank1 - fprintf(fptr, "total_basis_size_rank1: "); - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - fprintf(fptr, "%d ", total_basis_size_rank1[mu]); - } - fprintf(fptr, "\n"); - - for (SPECIES_TYPE mu = 0; mu < nelements; mu++) - for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size_rank1[mu]; ++func_ind) - fwrite_c_tilde_b_basis_func(fptr, basis_rank1[mu][func_ind]); - - fprintf(fptr, "total_basis_size: "); - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - fprintf(fptr, "%d ", total_basis_size[mu]); - } - fprintf(fptr, "\n"); - - for (SPECIES_TYPE mu = 0; mu < nelements; mu++) - for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size[mu]; ++func_ind) - fwrite_c_tilde_b_basis_func(fptr, basis[mu][func_ind]); - - - fclose(fptr); -} - -void fread_c_tilde_b_basis_func(FILE *fptr, ACECTildeBasisFunction &func) { - RANK_TYPE r; - int res; - char buf[3][128]; - - res = fscanf(fptr, " ctilde_basis_func: "); - - res = fscanf(fptr, "rank=%s ndens=%s mu0=%s ", buf[0], buf[1], buf[2]); - if (res != 3) - throw invalid_argument("Could not read C-tilde basis function"); - - func.rank = (RANK_TYPE) stol(buf[0]); - func.ndensity = (DENSITY_TYPE) stol(buf[1]); - func.mu0 = (SPECIES_TYPE) stol(buf[2]); - - func.mus = new SPECIES_TYPE[func.rank]; - func.ns = new NS_TYPE[func.rank]; - func.ls = new LS_TYPE[func.rank]; - - res = fscanf(fptr, " mu=("); - for (r = 0; r < func.rank; ++r) { - res = fscanf(fptr, "%s", buf[0]); - if (res != 1) - throw invalid_argument("Could not read C-tilde basis function"); - func.mus[r] = (SPECIES_TYPE) stol(buf[0]); - } - res = fscanf(fptr, " )"); // ")" - - res = fscanf(fptr, " n=("); // "n=" - for (r = 0; r < func.rank; ++r) { - res = fscanf(fptr, "%s", buf[0]); - if (res != 1) - throw invalid_argument("Could not read C-tilde basis function"); - - func.ns[r] = (NS_TYPE) stol(buf[0]); - } - res = fscanf(fptr, " )"); - - res = fscanf(fptr, " l=("); - for (r = 0; r < func.rank; ++r) { - res = fscanf(fptr, "%s", buf[0]); - if (res != 1) - throw invalid_argument("Could not read C-tilde basis function"); - func.ls[r] = (NS_TYPE) stol(buf[0]); - } - res = fscanf(fptr, " )"); - - res = fscanf(fptr, " num_ms=%s\n", buf[0]); - if (res != 1) - throw invalid_argument("Could not read C-tilde basis function"); - - func.num_ms_combs = (SHORT_INT_TYPE) stoi(buf[0]); - - func.ms_combs = new MS_TYPE[func.rank * func.num_ms_combs]; - func.ctildes = new DOUBLE_TYPE[func.ndensity * func.num_ms_combs]; - - for (int m_ind = 0; m_ind < func.num_ms_combs; m_ind++) { - res = fscanf(fptr, " <"); - for (r = 0; r < func.rank; ++r) { - res = fscanf(fptr, "%s", buf[0]); - if (res != 1) - throw invalid_argument("Could not read C-tilde basis function"); - func.ms_combs[m_ind * func.rank + r] = stoi(buf[0]); - } - res = fscanf(fptr, " >:"); - for (DENSITY_TYPE p = 0; p < func.ndensity; p++) { - res = fscanf(fptr, "%s", buf[0]); - if (res != 1) - throw invalid_argument("Could not read C-tilde basis function"); - func.ctildes[m_ind * func.ndensity + p] = stod(buf[0]); - } - } -} - -string -format_error_message(const char *buffer, const string &filename, const string &var_name, const string &expected) { - string err_message = "File '" + filename + "': couldn't read '" + var_name + "'"; - if (buffer) - err_message = err_message + ", read:'" + buffer + "'"; - if (!expected.empty()) - err_message = err_message + ". Expected format: '" + expected + "'"; - return err_message; -} - -void throw_error(const string &filename, const string &var_name, const string expected = "") { - throw invalid_argument(format_error_message(nullptr, filename, var_name, expected)); -} - -DOUBLE_TYPE stod_err(const char *buffer, const string &filename, const string &var_name, const string expected = "") { - try { - return stod(buffer); - } catch (invalid_argument &exc) { - throw invalid_argument(format_error_message(buffer, filename, var_name, expected).c_str()); - } -} - -int stoi_err(const char *buffer, const string &filename, const string &var_name, const string expected = "") { - try { - return stoi(buffer); - } catch (invalid_argument &exc) { - throw invalid_argument(format_error_message(buffer, filename, var_name, expected).c_str()); - } -} - -long int stol_err(const char *buffer, const string &filename, const string &var_name, const string expected = "") { - try { - return stol(buffer); - } catch (invalid_argument &exc) { - throw invalid_argument(format_error_message(buffer, filename, var_name, expected).c_str()); - } -} - -void ACECTildeBasisSet::load(const string filename) { - int res; - char buffer[1024], buffer2[1024]; - string radbasename = "ChebExpCos"; - - FILE *fptr; - fptr = fopen(filename.c_str(), "r"); - if (fptr == NULL) - throw invalid_argument("Could not open file " + filename); - - //read number of elements - res = fscanf(fptr, " nelements="); - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "nelements", "nelements=[number]"); - nelements = stoi_err(buffer, filename, "nelements", "nelements=[number]"); - - //elements mapping - elements_name = new string[nelements]; - res = fscanf(fptr, " elements:"); - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "elements", "elements: Ele1 Ele2 ..."); - elements_name[mu] = buffer; - } - - // load angular basis - only need spherical harmonics parameter - res = fscanf(fptr, " lmax=%s\n", buffer); - if (res != 1) - throw_error(filename, "lmax", "lmax=[number]"); - lmax = stoi_err(buffer, filename, "lmax", "lmax=[number]"); - spherical_harmonics.init(lmax); - - - // reading "embedding-function:" - bool is_embedding_function_specified = false; - res = fscanf(fptr, " embedding-function: %s", buffer); - if (res == 0) { - //throw_error(filename, "E0", " E0: E0-species1 E0-species2 ..."); - this->npoti = "FinnisSinclair"; // default values - //printf("Warning! No embedding-function is specified, embedding-function: FinnisSinclair would be assumed\n"); - is_embedding_function_specified = false; - } else { - this->npoti = buffer; - is_embedding_function_specified = true; - } - int parameters_size; - res = fscanf(fptr, "%s FS parameters:", buffer); - if (res != 1) - throw_error(filename, "FS parameters size", "[number] FS parameters: par1 par2 ..."); - parameters_size = stoi_err(buffer, filename, "FS parameters size", "[number] FS parameters"); - FS_parameters.resize(parameters_size); - for (int i = 0; i < FS_parameters.size(); ++i) { - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "FS parameter", "[number] FS parameters: [par1] [par2] ..."); - FS_parameters[i] = stod_err(buffer, filename, "FS parameter", "[number] FS parameters: [par1] [par2] ..."); - } - - if (!is_embedding_function_specified) { - // assuming non-linear potential, and embedding function type is important - for (int j = 1; j < parameters_size; j += 2) - if (FS_parameters[j] != 1.0) { //if not ensure linearity of embedding function parameters - printf("ERROR! Your potential is non-linear\n"); - printf("Please specify 'embedding-function: FinnisSinclair' or 'embedding-function: FinnisSinclairShiftedScaled' before 'FS parameters size' line\n"); - throw_error(filename, "embedding-function", "FinnisSinclair or FinnisSinclairShiftedScaled"); - } - printf("Notice! No embedding-function is specified, but potential has linear embedding, default embedding-function: FinnisSinclair would be assumed\n"); - } - - //hard-core energy cutoff repulsion - res = fscanf(fptr, " core energy-cutoff parameters:"); - if (res != 0) - throw_error(filename, "core energy-cutoff parameters", "core energy-cutoff parameters: [par1] [par2]"); - - rho_core_cutoffs.init(nelements, "rho_core_cutoffs"); - drho_core_cutoffs.init(nelements, "drho_core_cutoffs"); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) { - res = fscanf(fptr, "%s %s", buffer, buffer2); - if (res != 2) - throw_error(filename, "core energy-cutoff parameters", - "core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ..."); - rho_core_cutoffs(mu_i) = stod_err(buffer, filename, "rho core cutoff", - "core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ..."); - drho_core_cutoffs(mu_i) = stod_err(buffer2, filename, "drho_core_cutoff", - "core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ..."); - } - - // atom energy shift E0 (energy of isolated atom) - E0vals.init(nelements); - - // reading "E0:" - res = fscanf(fptr, " E0: %s", buffer); - if (res == 0) { - //throw_error(filename, "E0", " E0: E0-species1 E0-species2 ..."); - E0vals.fill(0.0); - } else { - double E0 = atof(buffer); - E0vals(0) = E0; - - for (SPECIES_TYPE mu_i = 1; mu_i < nelements; ++mu_i) { - res = fscanf(fptr, " %lf", &E0); - if (res != 1) - throw_error(filename, "E0", " couldn't read one of the E0 values"); - E0vals(mu_i) = E0; - } - res = fscanf(fptr, "\n"); - if (res != 0) - printf("file %s : format seems broken near E0; trying to continue...\n", filename.c_str()); - } - - // check which radial basis we need to load - res = fscanf(fptr, " radbasename=%s\n", buffer); - if (res != 1) { - throw_error(filename, "radbasename", "rabbasename=ChebExpCos|ChebPow|ACE.jl.Basic"); - } else { - radbasename = buffer; - } - -// printf("radbasename = `%s`\n", radbasename.c_str()); - if (radbasename == "ChebExpCos" | radbasename == "ChebPow") { - _load_radial_ACERadial(fptr, filename, radbasename); - } else if (radbasename == "ACE.jl.Basic") { - _load_radial_SHIPsBasic(fptr, filename, radbasename); - } else { - throw invalid_argument( - ("File '" + filename + "': I don't know how to read radbasename = " + radbasename).c_str()); - } - - res = fscanf(fptr, " rankmax="); - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "rankmax", "rankmax=[number]"); - rankmax = stoi_err(buffer, filename, "rankmax", "rankmax=[number]"); - - res = fscanf(fptr, " ndensitymax="); - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "ndensitymax", "ndensitymax=[number]"); - ndensitymax = stoi_err(buffer, filename, "ndensitymax", "ndensitymax=[number]"); - - // read the list of correlations to be put into the basis - //num_c_tilde_max - res = fscanf(fptr, " num_c_tilde_max="); - res = fscanf(fptr, "%s\n", buffer); - if (res != 1) - throw_error(filename, "num_c_tilde_max", "num_c_tilde_max=[number]"); - num_ctilde_max = stol_err(buffer, filename, "num_c_tilde_max", "num_c_tilde_max=[number]"); - - res = fscanf(fptr, " num_ms_combinations_max="); - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "num_ms_combinations_max", "num_ms_combinations_max=[number]"); -// throw invalid_argument(("File '" + filename + "': couldn't read num_ms_combinations_max").c_str()); - num_ms_combinations_max = stol_err(buffer, filename, "num_ms_combinations_max", "num_ms_combinations_max=[number]"); - - //read total_basis_size_rank1 - total_basis_size_rank1 = new SHORT_INT_TYPE[nelements]; - basis_rank1 = new ACECTildeBasisFunction *[nelements]; - res = fscanf(fptr, " total_basis_size_rank1: "); - - - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "total_basis_size_rank1", "total_basis_size_rank1: [size_ele1] [size_ele2] ..."); -// throw invalid_argument(("File '" + filename + "': couldn't read total_basis_size_rank1").c_str()); - total_basis_size_rank1[mu] = stoi_err(buffer, filename, "total_basis_size_rank1", - "total_basis_size_rank1: [size_ele1] [size_ele2] ..."); - basis_rank1[mu] = new ACECTildeBasisFunction[total_basis_size_rank1[mu]]; - } - for (SPECIES_TYPE mu = 0; mu < nelements; mu++) - for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size_rank1[mu]; ++func_ind) { - fread_c_tilde_b_basis_func(fptr, basis_rank1[mu][func_ind]); - } - - //read total_basis_size - res = fscanf(fptr, " total_basis_size: "); - total_basis_size = new SHORT_INT_TYPE[nelements]; - basis = new ACECTildeBasisFunction *[nelements]; - - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "total_basis_size", "total_basis_size: [size_ele1] [size_ele2] ..."); - total_basis_size[mu] = stoi_err(buffer, filename, "total_basis_size", - "total_basis_size: [size_ele1] [size_ele2] ..."); - basis[mu] = new ACECTildeBasisFunction[total_basis_size[mu]]; - } - for (SPECIES_TYPE mu = 0; mu < nelements; mu++) - for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size[mu]; ++func_ind) { - fread_c_tilde_b_basis_func(fptr, basis[mu][func_ind]); - } - - fclose(fptr); - -// radial_functions->radbasename = radbasename; - radial_functions->setuplookupRadspline(); - pack_flatten_basis(); -} - -void ACECTildeBasisSet::compute_array_sizes(ACECTildeBasisFunction **basis_rank1, ACECTildeBasisFunction **basis) { - //compute arrays sizes - rank_array_total_size_rank1 = 0; - //ms_array_total_size_rank1 = rank_array_total_size_rank1; - coeff_array_total_size_rank1 = 0; - - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - if (total_basis_size_rank1[mu] > 0) { - rank_array_total_size_rank1 += total_basis_size_rank1[mu]; - - ACEAbstractBasisFunction &func = basis_rank1[mu][0];//TODO: get total density instead of density from first function - coeff_array_total_size_rank1 += total_basis_size_rank1[mu] * func.ndensity; - } - } - - rank_array_total_size = 0; - coeff_array_total_size = 0; - - ms_array_total_size = 0; - max_dB_array_size = 0; - - - max_B_array_size = 0; - - size_t cur_ms_size = 0; - size_t cur_ms_rank_size = 0; - - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - - cur_ms_size = 0; - cur_ms_rank_size = 0; - for (int func_ind = 0; func_ind < total_basis_size[mu]; ++func_ind) { - auto &func = basis[mu][func_ind]; - rank_array_total_size += func.rank; - ms_array_total_size += func.rank * func.num_ms_combs; - coeff_array_total_size += func.ndensity * func.num_ms_combs; - - cur_ms_size += func.num_ms_combs; - cur_ms_rank_size += func.rank * func.num_ms_combs; - } - - if (cur_ms_size > max_B_array_size) - max_B_array_size = cur_ms_size; - - if (cur_ms_rank_size > max_dB_array_size) - max_dB_array_size = cur_ms_rank_size; - } -} - -void ACECTildeBasisSet::_clean_basis_arrays() { - if (basis_rank1 != nullptr) - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - delete[] basis_rank1[mu]; - basis_rank1[mu] = nullptr; - } - - if (basis != nullptr) - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - delete[] basis[mu]; - basis[mu] = nullptr; - } - delete[] basis; - basis = nullptr; - - delete[] basis_rank1; - basis_rank1 = nullptr; -} - -//pack into 1D array with all basis functions -void ACECTildeBasisSet::flatten_basis(C_tilde_full_basis_vector2d &mu0_ctilde_basis_vector) { - - _clean_basis_arrays(); - basis_rank1 = new ACECTildeBasisFunction *[nelements]; - basis = new ACECTildeBasisFunction *[nelements]; - - delete[] total_basis_size_rank1; - delete[] total_basis_size; - total_basis_size_rank1 = new SHORT_INT_TYPE[nelements]; - total_basis_size = new SHORT_INT_TYPE[nelements]; - - - size_t tot_size_rank1 = 0; - size_t tot_size = 0; - - for (SPECIES_TYPE mu = 0; mu < this->nelements; ++mu) { - tot_size = 0; - tot_size_rank1 = 0; - - for (auto &func: mu0_ctilde_basis_vector[mu]) { - if (func.rank == 1) tot_size_rank1 += 1; - else tot_size += 1; - } - - total_basis_size_rank1[mu] = tot_size_rank1; - basis_rank1[mu] = new ACECTildeBasisFunction[tot_size_rank1]; - - total_basis_size[mu] = tot_size; - basis[mu] = new ACECTildeBasisFunction[tot_size]; - } - - - for (SPECIES_TYPE mu = 0; mu < this->nelements; ++mu) { - size_t ind_rank1 = 0; - size_t ind = 0; - - for (auto &func: mu0_ctilde_basis_vector[mu]) { - if (func.rank == 1) { //r=0, rank=1 - basis_rank1[mu][ind_rank1] = func; - ind_rank1 += 1; - } else { //r>0, rank>1 - basis[mu][ind] = func; - ind += 1; - } - } - - } -} - - -void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, - const string filename, - const string radbasename) { - int res; - char buffer[1024], buffer2[1024]; - - res = fscanf(fptr, " nradbase="); - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "nradbase", "nradbase=[number]"); -// throw invalid_argument(("File '" + filename + "': couldn't read nradbase").c_str()); - nradbase = stoi_err(buffer, filename, "nradbase", "nradbase=[number]"); - - res = fscanf(fptr, " nradmax="); - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "nradmax", "nradmax=[number]"); - nradmax = stoi_err(buffer, filename, "nradmax", "nradmax=[number]"); - - res = fscanf(fptr, " cutoffmax="); - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "cutoffmax", "cutoffmax=[number]"); - cutoffmax = stod_err(buffer, filename, "cutoffmax", "cutoffmax=[number]"); - - - res = fscanf(fptr, " deltaSplineBins="); - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "deltaSplineBins", "deltaSplineBins=[spline density, Angstroms]"); -// throw invalid_argument(("File '" + filename + "': couldn't read ntot").c_str()); - deltaSplineBins = stod_err(buffer, filename, "deltaSplineBins", "deltaSplineBins=[spline density, Angstroms]"); - - - if (radial_functions == nullptr) - radial_functions = new ACERadialFunctions(nradbase, lmax, nradmax, - deltaSplineBins, - nelements, - cutoffmax, radbasename); - else - radial_functions->init(nradbase, lmax, nradmax, - deltaSplineBins, - nelements, - cutoffmax, radbasename); - - - //hard-core repulsion - res = fscanf(fptr, " core repulsion parameters:"); - if (res != 0) - throw_error(filename, "core repulsion parameters", "core repulsion parameters: [prehc lambdahc] ..."); -// throw invalid_argument(("File '" + filename + "': couldn't read core repulsion parameters").c_str()); - - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) { - res = fscanf(fptr, "%s %s", buffer, buffer2); - if (res != 2) - throw_error(filename, "core repulsion parameters", "core repulsion parameters: [prehc lambdahc] ..."); - radial_functions->prehc(mu_i, mu_j) = stod_err(buffer, filename, "core repulsion parameters", - "core repulsion parameters: [prehc lambdahc] ..."); - radial_functions->lambdahc(mu_i, mu_j) = stod_err(buffer2, filename, "core repulsion parameters", - "core repulsion parameters: [prehc lambdahc] ..."); - } - - - - //read radial functions parameter - res = fscanf(fptr, " radparameter="); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) { - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "radparameter", "radparameter=[param_ele1] [param_ele2]"); - radial_functions->lambda(mu_i, mu_j) = stod_err(buffer, filename, "radparameter", - "radparameter=[param_ele1] [param_ele2]"); - } - - - res = fscanf(fptr, " cutoff="); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) { - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "cutoff", "cutoff=[param_ele1] [param_ele2]"); - radial_functions->cut(mu_i, mu_j) = stod_err(buffer, filename, "cutoff", - "cutoff=[param_ele1] [param_ele2]"); - } - - - res = fscanf(fptr, " dcut="); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) { - res = fscanf(fptr, " %s", buffer); - if (res != 1) - throw_error(filename, "dcut", "dcut=[param_ele1] [param_ele2]"); - radial_functions->dcut(mu_i, mu_j) = stod_err(buffer, filename, "dcut", "dcut=[param_ele1] [param_ele2]"); - } - - - res = fscanf(fptr, " crad="); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) - for (NS_TYPE k = 0; k < nradbase; k++) - for (NS_TYPE n = 0; n < nradmax; n++) - for (LS_TYPE l = 0; l <= lmax; l++) { - res = fscanf(fptr, "%s", buffer); - if (res != 1) - throw_error(filename, "crad", "crad=[crad_]...[crad_knl]: nradbase*nrad*(l+1) times"); - radial_functions->crad(mu_i, mu_j, n, l, k) = stod_err(buffer, filename, "crad", - "crad=[crad_]...[crad_knl]: nradbase*nrad*(l+1) times"); - } -} - -void ACECTildeBasisSet::_load_radial_SHIPsBasic(FILE *fptr, - const string filename, - const string radbasename) { - // create a radial basis object, and read it from the file pointer - SHIPsRadialFunctions *ships_radial_functions = new SHIPsRadialFunctions(); - ships_radial_functions->fread(fptr); - - //mimic ships_radial_functions to ACERadialFunctions - ships_radial_functions->nradial = ships_radial_functions->get_maxn(); - ships_radial_functions->nradbase = ships_radial_functions->get_maxn(); - - nradbase = ships_radial_functions->get_maxn(); - nradmax = ships_radial_functions->get_maxn(); - cutoffmax = ships_radial_functions->get_rcut(); - deltaSplineBins = 0.001; - - ships_radial_functions->init(nradbase, lmax, nradmax, - deltaSplineBins, - nelements, - cutoffmax, radbasename); - - - if (radial_functions) delete radial_functions; - radial_functions = ships_radial_functions; - radial_functions->prehc.fill(0); - radial_functions->lambdahc.fill(1); - radial_functions->lambda.fill(0); - - - radial_functions->cut.fill(ships_radial_functions->get_rcut()); - radial_functions->dcut.fill(0); - - radial_functions->crad.fill(0); - -} \ No newline at end of file diff --git a/lib/pace/ace_c_basis.h b/lib/pace/ace_c_basis.h deleted file mode 100644 index ec6b9e8afc..0000000000 --- a/lib/pace/ace_c_basis.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Yury Lysogorskiy on 1.04.20. - -#ifndef ACE_C_BASIS_H -#define ACE_C_BASIS_H - -#include "ace_flatten_basis.h" - -typedef vector> C_tilde_full_basis_vector2d; - -/** - * ACE basis set of C-tilde basis functions - */ -class ACECTildeBasisSet : public ACEFlattenBasisSet { -public: - - ACECTildeBasisFunction **basis_rank1 = nullptr; ///< two-dimensional array of first-rank basis function with indices: [species index][func index] - ACECTildeBasisFunction **basis = nullptr; ///< two-dimensional array of higher rank basis function with indices: [species index][func index] - - DOUBLE_TYPE *full_c_tildes_rank1 = nullptr; ///< C_tilde coefficients contiguous package, size: coeff_array_total_size_rank1 - DOUBLE_TYPE *full_c_tildes = nullptr; ///< C_tilde coefficients contiguous package, size: coeff_array_total_size - - //TODO: remove? - SHORT_INT_TYPE num_ctilde_max = 0; - - - /** - * Default constructor - */ - ACECTildeBasisSet() = default; - - /** - * Constructor from .ace file - */ - ACECTildeBasisSet(const string filename); - - /** - * Copy constructor (see. Rule of Three) - * @param other - */ - ACECTildeBasisSet(const ACECTildeBasisSet &other); - - /** - * operator= (see. Rule of Three) - * @param other - * @return - */ - ACECTildeBasisSet &operator=(const ACECTildeBasisSet &other); - - /** - * Destructor (see. Rule of Three) - */ - ~ACECTildeBasisSet() override; - - /** - * Cleaning dynamic memory of the class (see. Rule of Three) - */ - void _clean() override; - - /** - * Copying and cleaning dynamic memory of the class (see. Rule of Three) - * @param src - */ - void _copy_dynamic_memory(const ACECTildeBasisSet &src); - - /** - * Copying scalar variables - * @param src - */ - void _copy_scalar_memory(const ACECTildeBasisSet &src); - - /** - * Clean contiguous arrays (full_c_tildes_rank1, full_c_tildes) and those of base class - */ - void _clean_contiguous_arrays() override ; - - /** - * Save potential to .ace file - * @param filename .ace file name - */ - void save(const string &filename) override; - - /** - * Load potential from .ace - * @param filename .ace file name - */ - void load(const string filename) override; - - /** - * Load the ACE type radial basis - */ - void _load_radial_ACERadial(FILE *fptr, - const string filename, - const string radbasename); - - void _load_radial_SHIPsBasic(FILE * fptr, - const string filename, - const string radbasename ); - - /** - * Re-pack the constituent dynamic arrays of all basis functions in contiguous arrays - */ - void pack_flatten_basis() override; - - /** - * Computes flatten array sizes - * @param basis_rank1 two-dimensional array of first-rank ACECTildeBasisFunctions - * @param basis two-dimensional array of higher-rank ACECTildeBasisFunctions - */ - void compute_array_sizes(ACECTildeBasisFunction** basis_rank1, ACECTildeBasisFunction** basis); - - /** - * Clean basis arrays 'basis_rank1' and 'basis' - */ - void _clean_basis_arrays(); - - /** - * Pack two-dimensional vector of ACECTildeBasisFunction into 1D dynami array with all basis functions - * @param mu0_ctilde_basis_vector vector> - */ - void flatten_basis(C_tilde_full_basis_vector2d& mu0_ctilde_basis_vector); - - /** - * Empty stub implementation - */ - void flatten_basis() override{}; -}; - -#endif //ACE_C_BASIS_H diff --git a/lib/pace/ace_c_basisfunction.h b/lib/pace/ace_c_basisfunction.h deleted file mode 100644 index 4e2795590e..0000000000 --- a/lib/pace/ace_c_basisfunction.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Yury Lysogorskiy on 26.02.20. - -#ifndef ACE_C_BASISFUNCTION_H -#define ACE_C_BASISFUNCTION_H - -#include -#include -#include -#include - -#include "ace_types.h" - -//macros for copying the member-array from "other" object for C-tilde and B-basis -#define basis_mem_copy(other, array, size, type) if(other.array) { \ - if(!is_proxy) delete[] array;\ - array = new type[(size)];\ - is_proxy = false;\ - memcpy(array, other.array, (size) * sizeof(type));\ -} - -/** - * Abstract basis function, that stores general quantities - */ -struct ACEAbstractBasisFunction { - /** - * flattened array of computed combinations of (m1, m2, ..., m_rank) - * which have non-zero general Clebsch-Gordan coefficient: - * \f$ \mathbf{m}_1, \dots, \mathbf{m}_\mathrm{num ms combs}\f$ = - * \f$ (m_1, m_2, \dots, m_{rank})_1, \dots, (m_1, m_2, \dots, m_{rank})_{\mathrm{num ms combs}} \f$, - * size = num_ms_combs * rank, - * effective shape: [num_ms_combs][rank] - */ - MS_TYPE *ms_combs = nullptr; - - /** - * species types of neighbours atoms \f$ \mathbf{\mu} = (\mu_1, \mu_2, \dots, \mu_{rank}) \f$, - * should be lexicographically sorted, - * size = rank, - * effective shape: [rank] - */ - SPECIES_TYPE *mus = nullptr; - - /** - * indices for radial part \f$ \mathbf{n} = (n_1, n_2, \dots, n_{rank}) \f$, - * should be lexicographically sorted, - * size = rank, - * effective shape: [rank] - */ - NS_TYPE *ns = nullptr; - - - /** - * indices for radial part \f$ \mathbf{l} = (l_1, l_2, \dots, l_{rank}) \f$, - * should be lexicographically sorted, - * size = rank, - * effective shape: [rank] - */ - LS_TYPE *ls = nullptr; - - SHORT_INT_TYPE num_ms_combs = 0; ///< number of different ms-combinations - - RANK_TYPE rank = 0; ///< number of atomic base functions "A"s in basis function product B - - DENSITY_TYPE ndensity = 0; ///< number of densities - - SPECIES_TYPE mu0 = 0; ///< species type of central atom - - /** - * whether ms array contains only "non-negative" ms-combinations. - * positive ms-combination is when the first non-zero m is positive (0 1 -1) - * negative ms-combination is when the first non-zero m is negative (0 -1 1) - */ - bool is_half_ms_basis = false; - - /* - * flag, whether object is "owner" (i.e. responsible for memory cleaning) of - * the ms, ns, ls, mus and other dynamically allocated arrases or just a proxy for them - */ - bool is_proxy = false; - - /** - * Copying static and dynamic memory variables from another ACEAbstractBasisFunction. - * Always copy the dynamic memory, even if the source is a proxy object - * @param other - */ - virtual void _copy_from(const ACEAbstractBasisFunction &other) { - rank = other.rank; - ndensity = other.ndensity; - mu0 = other.mu0; - num_ms_combs = other.num_ms_combs; - is_half_ms_basis = other.is_half_ms_basis; - is_proxy = false; - - basis_mem_copy(other, mus, rank, SPECIES_TYPE) - basis_mem_copy(other, ns, rank, NS_TYPE) - basis_mem_copy(other, ls, rank, LS_TYPE) - basis_mem_copy(other, ms_combs, num_ms_combs * rank, MS_TYPE) - } - - /** - * Clean the dynamically allocated memory if object is responsible for it - */ - virtual void _clean() { - //release memory if the structure is not proxy - if (!is_proxy) { - delete[] mus; - delete[] ns; - delete[] ls; - delete[] ms_combs; - } - - mus = nullptr; - ns = nullptr; - ls = nullptr; - ms_combs = nullptr; - } - -}; - -/** - * Representation of C-tilde basis function, i.e. the function that is summed up over a group of B-functions - * that differs only by intermediate coupling orbital moment \f$ L \f$ and coefficients. - */ -struct ACECTildeBasisFunction : public ACEAbstractBasisFunction { - - /** - * c_tilde coefficients for all densities, - * size = num_ms_combs*ndensity, - * effective shape [num_ms_combs][ndensity] - */ - DOUBLE_TYPE *ctildes = nullptr; - - /* - * Default constructor - */ - ACECTildeBasisFunction() = default; - - // Because the ACECTildeBasisFunction contains dynamically allocated arrays, the Rule of Three should be - // fulfilled, i.e. copy constructor (copy the dynamic arrays), operator= (release previous arrays and - // copy the new dynamic arrays) and destructor (release all dynamically allocated memory) - - /** - * Copy constructor, to fulfill the Rule of Three. - * Always copy the dynamic memory, even if the source is a proxy object. - */ - ACECTildeBasisFunction(const ACECTildeBasisFunction &other) { - _copy_from(other); - } - - /* - * operator=, to fulfill the Rule of Three. - * Always copy the dynamic memory, even if the source is a proxy object - */ - ACECTildeBasisFunction &operator=(const ACECTildeBasisFunction &other) { - _clean(); - _copy_from(other); - return *this; - } - - /* - * Destructor - */ - ~ACECTildeBasisFunction() { - _clean(); - } - - /** - * Copy from another object, always copy the memory, even if the source is a proxy object - * @param other - */ - void _copy_from(const ACECTildeBasisFunction &other) { - ACEAbstractBasisFunction::_copy_from(other); - is_proxy = false; - basis_mem_copy(other, ctildes, num_ms_combs * ndensity, DOUBLE_TYPE) - } - - /** - * Clean the dynamically allocated memory if object is responsible for it - */ - void _clean() override { - ACEAbstractBasisFunction::_clean(); - //release memory if the structure is not proxy - if (!is_proxy) { - delete[] ctildes; - } - ctildes = nullptr; - } - - /** - * Print the information about basis function to cout, in order to ease the output redirection. - */ - void print() const { - using namespace std; - cout << "ACECTildeBasisFunction: ndensity= " << (int) this->ndensity << ", mu0 = " << (int) this->mu0 << " "; - cout << " mus=("; - for (RANK_TYPE r = 0; r < this->rank; r++) - cout << (int) this->mus[r] << " "; - cout << "), ns=("; - for (RANK_TYPE r = 0; r < this->rank; r++) - cout << this->ns[r] << " "; - cout << "), ls=("; - for (RANK_TYPE r = 0; r < this->rank; r++) - cout << this->ls[r] << " "; - - cout << "), " << this->num_ms_combs << " m_s combinations: {" << endl; - - for (int i = 0; i < this->num_ms_combs; i++) { - cout << "\t< "; - for (RANK_TYPE r = 0; r < this->rank; r++) - cout << this->ms_combs[i * this->rank + r] << " "; - cout << " >: c_tilde="; - for (DENSITY_TYPE p = 0; p < this->ndensity; ++p) - cout << " " << this->ctildes[i * this->ndensity + p] << " "; - cout << endl; - } - if (this->is_proxy) - cout << "proxy "; - if (this->is_half_ms_basis) - cout << "half_ms_basis"; - cout << "}" << endl; - } -}; - -#endif //ACE_C_BASISFUNCTION_H diff --git a/lib/pace/ace_complex.h b/lib/pace/ace_complex.h deleted file mode 100644 index 5fdb4b5b93..0000000000 --- a/lib/pace/ace_complex.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Yury Lysogorskiy on 26.02.20. - -#ifndef ACE_COMPLEX_H -#define ACE_COMPLEX_H - - -/** -A custom data structure for complex numbers and overloaded operations with them. -*/ -struct ACEComplex { -public: - /** - Double, real part of the complex number - */ - DOUBLE_TYPE real; - /** - Double, imaginary part of the complex number - */ - DOUBLE_TYPE img; - - ACEComplex &operator=(const ACEComplex &rhs) = default; - - ACEComplex &operator=(const DOUBLE_TYPE &rhs) { - this->real = rhs; - this->img = 0.; - return *this; - } - - /** - Overloading of arithmetical operator += ACEComplex - */ - ACEComplex &operator+=(const ACEComplex &rhs) { - this->real += rhs.real; - this->img += rhs.img; - return *this; // return the result by reference - } - - /** - Overloading of arithmetical operator += DOUBLE_TYPE - */ - ACEComplex &operator+=(const DOUBLE_TYPE &rhs) { - this->real += rhs; - return *this; // return the result by reference - } - - /** - Overloading of arithmetical operator *= DOUBLE_TYPE - */ - ACEComplex &operator*=(const DOUBLE_TYPE &rhs) { - this->real *= rhs; - this->img *= rhs; - return *this; // return the result by reference - } - - /** - Overloading of arithmetical operator *= ACEComplex - */ - ACEComplex &operator*=(const ACEComplex &rhs) { - DOUBLE_TYPE old_real = this->real; - this->real = old_real * rhs.real - this->img * rhs.img; - this->img = old_real * rhs.img + this->img * rhs.real; - return *this; // return the result by reference - } - - /** - Overloading of arithmetical operator * ACEComplex - */ - ACEComplex operator*(const ACEComplex &cm2) const { - ACEComplex res{real * cm2.real - img * cm2.img, - real * cm2.img + img * cm2.real}; - return res; - } - - /* - * Return complex conjugated copy of itself - */ - ACEComplex conjugated() const { - ACEComplex res{real, -img}; - return res; - } - - /* - * Complex conjugate itself inplace - */ - void conjugate() { - img = -img; - } - - /* - * Multiplication by ACEComplex and return real-part only - */ - DOUBLE_TYPE real_part_product(const ACEComplex &cm2) const { - return real * cm2.real - img * cm2.img; - } - - /* - * Multiplication by DOUBLE_TYPE and return real-part only - */ - DOUBLE_TYPE real_part_product(const DOUBLE_TYPE &cm2) const { - return real * cm2; - } - - /* - * Overloading of arithmetical operator * by DOUBLE_TYPE - */ - ACEComplex operator*(const DOUBLE_TYPE &cm2) const { - ACEComplex res{real * cm2, - img * cm2}; - return res; - } - - /* - * Overloading of arithmetical operator + ACEComplex - */ - ACEComplex operator+(const ACEComplex &cm2) const { - ACEComplex res{real + cm2.real, - img + cm2.img}; - return res; - } - - /* - * Overloading of arithmetical operator + with DOUBLE_TYPE - */ - ACEComplex operator+(const DOUBLE_TYPE &cm2) const { - ACEComplex res{real + cm2, img}; - return res; - } - - /* - * Overloading of arithmetical operator == ACEComplex - */ - bool operator==(const ACEComplex &c2) const { - return (real == c2.real) && (img == c2.img); - } - - /* - * Overloading of arithmetical operator == DOUBLE_TYPE - */ - bool operator==(const DOUBLE_TYPE &d2) const { - return (real == d2) && (img == 0.); - } - - /* - * Overloading of arithmetical operator != ACEComplex - */ - bool operator!=(const ACEComplex &c2) const { - return (real != c2.real) || (img != c2.img); - } - - /* - * Overloading of arithmetical operator != DOUBLE_TYPE - */ - bool operator!=(const DOUBLE_TYPE &d2) const { - return (real != d2) || (img != 0.); - } - -}; - -/* - * double * complex for commutativity with complex * double - */ -inline ACEComplex operator*(const DOUBLE_TYPE &real, const ACEComplex &cm) { - return cm * real; -} - -/* - * double + complex for commutativity with complex + double - */ -inline ACEComplex operator+(const DOUBLE_TYPE &real, const ACEComplex &cm) { - return cm + real; -} - -/** -A structure to store the derivative of \f$ Y_{lm} \f$ -*/ -struct ACEDYcomponent { -public: - /** - complex, contains the three components of derivative of Ylm, - \f$ \frac{dY_{lm}}{dx}, \frac{dY_{lm}}{dy} and \frac{dY_{lm}}{dz}\f$ - */ - ACEComplex a[3]; - - /* - * Overloading of arithmetical operator*= DOUBLE_TYPE - */ - ACEDYcomponent &operator*=(const DOUBLE_TYPE &rhs) { - this->a[0] *= rhs; - this->a[1] *= rhs; - this->a[2] *= rhs; - return *this; - } - - /* - * Overloading of arithmetical operator * ACEComplex - */ - ACEDYcomponent operator*(const ACEComplex &rhs) const { - ACEDYcomponent res; - res.a[0] = this->a[0] * rhs; - res.a[1] = this->a[1] * rhs; - res.a[2] = this->a[2] * rhs; - return res; - } - - /* - * Overloading of arithmetical operator * DOUBLE_TYPE - */ - ACEDYcomponent operator*(const DOUBLE_TYPE &rhs) const { - ACEDYcomponent res; - res.a[0] = this->a[0] * rhs; - res.a[1] = this->a[1] * rhs; - res.a[2] = this->a[2] * rhs; - return res; - } - - /* - * Return conjugated copy of itself - */ - ACEDYcomponent conjugated() const { - ACEDYcomponent res; - res.a[0] = this->a[0].conjugated(); - res.a[1] = this->a[1].conjugated(); - res.a[2] = this->a[2].conjugated(); - return res; - } - - /* - * Conjugated itself in-place - */ - void conjugate() { - this->a[0].conjugate(); - this->a[1].conjugate(); - this->a[2].conjugate(); - } - -}; - - -#endif //ACE_COMPLEX_H diff --git a/lib/pace/ace_contigous_array.h b/lib/pace/ace_contigous_array.h deleted file mode 100644 index f008fa203f..0000000000 --- a/lib/pace/ace_contigous_array.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Yury Lysogorskiy on 11.01.20. -#ifndef ACE_CONTIGUOUSARRAYND_H -#define ACE_CONTIGUOUSARRAYND_H - -#include - -#include "ace_types.h" - -using namespace std; - -/** - * Common predecessor class to represent multidimensional array of type T - * and store it in memory contiguous form - * - * @tparam T data type - */ -template -class ContiguousArrayND { -protected: - T *data = nullptr; ///< pointer to contiguous data - size_t size = 0; ///< total array size - string array_name = "Array"; /// 0) { - data = new T[size]; - for (size_t ind = 0; ind < size; ind++) - data[ind] = other.data[ind]; - } - } else { //is proxy, then copy the pointer - data = other.data; - } - } - - /** - * Overload operator= - * @param other another ContiguousArrayND - * @return itself - */ - - ContiguousArrayND &operator=(const ContiguousArrayND &other) { -#ifdef MULTIARRAY_LIFE_CYCLE - cout< 0) { - - if(data!=nullptr) delete[] data; - data = new T[size]; - - for (size_t ind = 0; ind < size; ind++) - data[ind] = other.data[ind]; - } - } else { //is proxy, then copy the pointer - data = other.data; - } - } - return *this; - } - - - //TODO: make destructor virtual, check the destructors in inherited classes - - /** - * Destructor - */ - ~ContiguousArrayND() { -#ifdef MULTIARRAY_LIFE_CYCLE - cout<array_name = name; - } - - /** - * Get total number of elements in array (its size) - * @return array size - */ - size_t get_size() const { - return size; - } - - /** - * Fill array with value - * @param value value to fill - */ - void fill(T value) { - for (size_t ind = 0; ind < size; ind++) - data[ind] = value; - } - - /** - * Get array data at absolute index ind for reading - * @param ind absolute index - * @return array value - */ - inline const T &get_data(size_t ind) const { -#ifdef MULTIARRAY_INDICES_CHECK - if ((ind < 0) | (ind >= size)) { - printf("%s: get_data ind=%d out of range (0, %d)\n", array_name, ind, size); - exit(EXIT_FAILURE); - } -#endif - return data[ind]; - } - - /** - * Get array data at absolute index ind for writing - * @param ind absolute index - * @return array value - */ - inline T &get_data(size_t ind) { -#ifdef MULTIARRAY_INDICES_CHECK - if ((ind < 0) | (ind >= size)) { - printf("%s: get_data ind=%ld out of range (0, %ld)\n", array_name.c_str(), ind, size); - exit(EXIT_FAILURE); - } -#endif - return data[ind]; - } - - /** - * Get array data pointer - * @return data array pointer - */ - inline T* get_data() const { - return data; - } - - /** - * Overload comparison operator== - * Compare the total size and array values elementwise. - * - * @param other another array - * @return - */ - bool operator==(const ContiguousArrayND &other) const { - if (this->size != other.size) - return false; - - for (size_t i = 0; i < this->size; ++i) - if (this->data[i] != other.data[i]) - return false; - - return true; - } - - - /** - * Convert to flatten vector container - * @return vector container - */ - vector to_flatten_vector() const { - vector res; - - res.resize(size); - size_t vec_ind = 0; - - for (int vec_ind = 0; vec_ind < size; vec_ind++) - res.at(vec_ind) = data[vec_ind]; - - return res; - } // end to_flatten_vector() - - - /** - * Set values from flatten vector container - * @param vec container - */ - void set_flatten_vector(const vector &vec) { - if (vec.size() != size) - throw std::invalid_argument("Flatten vector size is not consistent with expected size"); - for (size_t i = 0; i < size; i++) { - data[i] = vec[i]; - } - } - - bool is_proxy(){ - return is_proxy_; - } - -}; - - -#endif //ACE_CONTIGUOUSARRAYND_H \ No newline at end of file diff --git a/lib/pace/ace_evaluator.cpp b/lib/pace/ace_evaluator.cpp deleted file mode 100644 index 987f4502bf..0000000000 --- a/lib/pace/ace_evaluator.cpp +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Yury Lysogorskiy on 31.01.20. - -#include "ace_evaluator.h" - -#include "ace_abstract_basis.h" -#include "ace_types.h" - -void ACEEvaluator::init(ACEAbstractBasisSet *basis_set) { - A.init(basis_set->nelements, basis_set->nradmax + 1, basis_set->lmax + 1, "A"); - A_rank1.init(basis_set->nelements, basis_set->nradbase, "A_rank1"); - - rhos.init(basis_set->ndensitymax + 1, "rhos"); // +1 density for core repulsion - dF_drho.init(basis_set->ndensitymax + 1, "dF_drho"); // +1 density for core repulsion -} - -void ACEEvaluator::init_timers() { - loop_over_neighbour_timer.init(); - forces_calc_loop_timer.init(); - forces_calc_neighbour_timer.init(); - energy_calc_timer.init(); - per_atom_calc_timer.init(); - total_time_calc_timer.init(); -} - -//================================================================================================================ - -void ACECTildeEvaluator::set_basis(ACECTildeBasisSet &bas) { - basis_set = &bas; - init(basis_set); -} - -void ACECTildeEvaluator::init(ACECTildeBasisSet *basis_set) { - - ACEEvaluator::init(basis_set); - - - weights.init(basis_set->nelements, basis_set->nradmax + 1, basis_set->lmax + 1, - "weights"); - - weights_rank1.init(basis_set->nelements, basis_set->nradbase, "weights_rank1"); - - - DG_cache.init(1, basis_set->nradbase, "DG_cache"); - DG_cache.fill(0); - - R_cache.init(1, basis_set->nradmax, basis_set->lmax + 1, "R_cache"); - R_cache.fill(0); - - DR_cache.init(1, basis_set->nradmax, basis_set->lmax + 1, "DR_cache"); - DR_cache.fill(0); - - Y_cache.init(1, basis_set->lmax + 1, "Y_cache"); - Y_cache.fill({0, 0}); - - DY_cache.init(1, basis_set->lmax + 1, "dY_dense_cache"); - DY_cache.fill({0.}); - - //hard-core repulsion - DCR_cache.init(1, "DCR_cache"); - DCR_cache.fill(0); - dB_flatten.init(basis_set->max_dB_array_size, "dB_flatten"); - - -} - -void ACECTildeEvaluator::resize_neighbours_cache(int max_jnum) { - if(basis_set== nullptr) { - throw std::invalid_argument("ACECTildeEvaluator: basis set is not assigned"); - } - if (R_cache.get_dim(0) < max_jnum) { - - //TODO: implement grow - R_cache.resize(max_jnum, basis_set->nradmax, basis_set->lmax + 1); - R_cache.fill(0); - - DR_cache.resize(max_jnum, basis_set->nradmax, basis_set->lmax + 1); - DR_cache.fill(0); - - DG_cache.resize(max_jnum, basis_set->nradbase); - DG_cache.fill(0); - - Y_cache.resize(max_jnum, basis_set->lmax + 1); - Y_cache.fill({0, 0}); - - DY_cache.resize(max_jnum, basis_set->lmax + 1); - DY_cache.fill({0}); - - //hard-core repulsion - DCR_cache.init(max_jnum, "DCR_cache"); - DCR_cache.fill(0); - } -} - - - -// double** r - atomic coordinates of atom I -// int* types - atomic types if atom I -// int **firstneigh - ptr to 1st J int value of each I atom. Usage: jlist = firstneigh[i]; -// Usage: j = jlist_of_i[jj]; -// jnum - number of J neighbors for each I atom. jnum = numneigh[i]; - -void -ACECTildeEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *type, const int jnum, const int *jlist) { - if(basis_set== nullptr) { - throw std::invalid_argument("ACECTildeEvaluator: basis set is not assigned"); - } - per_atom_calc_timer.start(); -#ifdef PRINT_MAIN_STEPS - printf("\n ATOM: ind = %d r_norm=(%f, %f, %f)\n",i, x[i][0], x[i][1], x[i][2]); -#endif - DOUBLE_TYPE evdwl = 0, evdwl_cut = 0, rho_core = 0; - DOUBLE_TYPE r_norm; - DOUBLE_TYPE xn, yn, zn, r_xyz; - DOUBLE_TYPE R, GR, DGR, R_over_r, DR, DCR; - DOUBLE_TYPE *r_hat; - - SPECIES_TYPE mu_j; - RANK_TYPE r, rank, t; - NS_TYPE n; - LS_TYPE l; - MS_TYPE m, m_t; - - SPECIES_TYPE *mus; - NS_TYPE *ns; - LS_TYPE *ls; - MS_TYPE *ms; - - int j, jj, func_ind, ms_ind; - SHORT_INT_TYPE factor; - - ACEComplex Y{0}, Y_DR{0.}; - ACEComplex B{0.}; - ACEComplex dB{0}; - ACEComplex A_cache[basis_set->rankmax]; - - dB_flatten.fill({0.}); - - ACEDYcomponent grad_phi_nlm{0}, DY{0.}; - - //size is +1 of max to avoid out-of-boundary array access in double-triangular scheme - ACEComplex A_forward_prod[basis_set->rankmax + 1]; - ACEComplex A_backward_prod[basis_set->rankmax + 1]; - - DOUBLE_TYPE inv_r_norm; - DOUBLE_TYPE r_norms[jnum]; - DOUBLE_TYPE inv_r_norms[jnum]; - DOUBLE_TYPE rhats[jnum][3];//normalized vector - SPECIES_TYPE elements[jnum]; - const DOUBLE_TYPE xtmp = x[i][0]; - const DOUBLE_TYPE ytmp = x[i][1]; - const DOUBLE_TYPE ztmp = x[i][2]; - DOUBLE_TYPE f_ji[3]; - - bool is_element_mapping = element_type_mapping.get_size() > 0; - SPECIES_TYPE mu_i; - if (is_element_mapping) - mu_i = element_type_mapping(type[i]); - else - mu_i = type[i]; - - const SHORT_INT_TYPE total_basis_size_rank1 = basis_set->total_basis_size_rank1[mu_i]; - const SHORT_INT_TYPE total_basis_size = basis_set->total_basis_size[mu_i]; - - ACECTildeBasisFunction *basis_rank1 = basis_set->basis_rank1[mu_i]; - ACECTildeBasisFunction *basis = basis_set->basis[mu_i]; - - DOUBLE_TYPE rho_cut, drho_cut, fcut, dfcut; - DOUBLE_TYPE dF_drho_core; - - //TODO: lmax -> lmaxi (get per-species type) - const LS_TYPE lmaxi = basis_set->lmax; - - //TODO: nradmax -> nradiali (get per-species type) - const NS_TYPE nradiali = basis_set->nradmax; - - //TODO: nradbase -> nradbasei (get per-species type) - const NS_TYPE nradbasei = basis_set->nradbase; - - //TODO: get per-species type number of densities - const DENSITY_TYPE ndensity= basis_set->ndensitymax; - - neighbours_forces.resize(jnum, 3); - neighbours_forces.fill(0); - - //TODO: shift nullifications to place where arrays are used - weights.fill({0}); - weights_rank1.fill(0); - A.fill({0}); - A_rank1.fill(0); - rhos.fill(0); - dF_drho.fill(0); - -#ifdef EXTRA_C_PROJECTIONS - basis_projections_rank1.init(total_basis_size_rank1, ndensity, "c_projections_rank1"); - basis_projections.init(total_basis_size, ndensity, "c_projections"); -#endif - - //proxy references to spherical harmonics and radial functions arrays - const Array2DLM &ylm = basis_set->spherical_harmonics.ylm; - const Array2DLM &dylm = basis_set->spherical_harmonics.dylm; - - const Array2D &fr = basis_set->radial_functions->fr; - const Array2D &dfr = basis_set->radial_functions->dfr; - - const Array1D &gr = basis_set->radial_functions->gr; - const Array1D &dgr = basis_set->radial_functions->dgr; - - loop_over_neighbour_timer.start(); - - int jj_actual = 0; - SPECIES_TYPE type_j = 0; - int neighbour_index_mapping[jnum]; // jj_actual -> jj - //loop over neighbours, compute distance, consider only atoms within with rradial_functions->cut(mu_i, mu_j); - r_xyz = sqrt(xn * xn + yn * yn + zn * zn); - - if (r_xyz >= current_cutoff) - continue; - - inv_r_norm = 1 / r_xyz; - - r_norms[jj_actual] = r_xyz; - inv_r_norms[jj_actual] = inv_r_norm; - rhats[jj_actual][0] = xn * inv_r_norm; - rhats[jj_actual][1] = yn * inv_r_norm; - rhats[jj_actual][2] = zn * inv_r_norm; - elements[jj_actual] = mu_j; - neighbour_index_mapping[jj_actual] = jj; - jj_actual++; - } - - int jnum_actual = jj_actual; - - //ALGORITHM 1: Atomic base A - for (jj = 0; jj < jnum_actual; ++jj) { - r_norm = r_norms[jj]; - mu_j = elements[jj]; - r_hat = rhats[jj]; - - //proxies - Array2DLM &Y_jj = Y_cache(jj); - Array2DLM &DY_jj = DY_cache(jj); - - - basis_set->radial_functions->evaluate(r_norm, basis_set->nradbase, nradiali, mu_i, mu_j); - basis_set->spherical_harmonics.compute_ylm(r_hat[0], r_hat[1], r_hat[2], lmaxi); - //loop for computing A's - //rank = 1 - for (n = 0; n < basis_set->nradbase; n++) { - GR = gr(n); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("-neigh atom %d\n", jj); - printf("gr(n=%d)(r=%f) = %f\n", n, r_norm, gr(n)); - printf("dgr(n=%d)(r=%f) = %f\n", n, r_norm, dgr(n)); -#endif - DG_cache(jj, n) = dgr(n); - A_rank1(mu_j, n) += GR * Y00; - } - //loop for computing A's - // for rank > 1 - for (n = 0; n < nradiali; n++) { - auto &A_lm = A(mu_j, n); - for (l = 0; l <= lmaxi; l++) { - R = fr(n, l); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("R(nl=%d,%d)(r=%f)=%f\n", n + 1, l, r_norm, R); -#endif - - DR_cache(jj, n, l) = dfr(n, l); - R_cache(jj, n, l) = R; - - for (m = 0; m <= l; m++) { - Y = ylm(l, m); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("Y(lm=%d,%d)=(%f, %f)\n", l, m, Y.real, Y.img); -#endif - A_lm(l, m) += R * Y; //accumulation sum over neighbours - Y_jj(l, m) = Y; - DY_jj(l, m) = dylm(l, m); - } - } - } - - //hard-core repulsion - rho_core += basis_set->radial_functions->cr; - DCR_cache(jj) = basis_set->radial_functions->dcr; - - } //end loop over neighbours - - //complex conjugate A's (for NEGATIVE (-m) terms) - // for rank > 1 - for (mu_j = 0; mu_j < basis_set->nelements; mu_j++) { - for (n = 0; n < nradiali; n++) { - auto &A_lm = A(mu_j, n); - for (l = 0; l <= lmaxi; l++) { - //fill in -m part in the outer loop using the same m <-> -m symmetry as for Ylm - for (m = 1; m <= l; m++) { - factor = m % 2 == 0 ? 1 : -1; - A_lm(l, -m) = A_lm(l, m).conjugated() * factor; - } - } - } - } //now A's are constructed - loop_over_neighbour_timer.stop(); - - // ==================== ENERGY ==================== - - energy_calc_timer.start(); -#ifdef EXTRA_C_PROJECTIONS - basis_projections_rank1.fill(0); - basis_projections.fill(0); -#endif - - //ALGORITHM 2: Basis functions B with iterative product and density rho(p) calculation - //rank=1 - for (int func_rank1_ind = 0; func_rank1_ind < total_basis_size_rank1; ++func_rank1_ind) { - ACECTildeBasisFunction *func = &basis_rank1[func_rank1_ind]; -// ndensity = func->ndensity; -#ifdef PRINT_LOOPS_INDICES - printf("Num density = %d r = 0\n",(int) ndensity ); - print_C_tilde_B_basis_function(*func); -#endif - double A_cur = A_rank1(func->mus[0], func->ns[0] - 1); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("A_r=1(x=%d, n=%d)=(%f)\n", func->mus[0], func->ns[0], A_cur); - printf(" coeff[0] = %f\n", func->ctildes[0]); -#endif - for (DENSITY_TYPE p = 0; p < ndensity; ++p) { - //for rank=1 (r=0) only 1 ms-combination exists (ms_ind=0), so index of func.ctildes is 0..ndensity-1 - rhos(p) += func->ctildes[p] * A_cur; -#ifdef EXTRA_C_PROJECTIONS - //aggregate C-projections separately - basis_projections_rank1(func_rank1_ind, p)+= func->ctildes[p] * A_cur; -#endif - } - } // end loop for rank=1 - - //rank>1 - int func_ms_ind = 0; - int func_ms_t_ind = 0;// index for dB - - for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { - ACECTildeBasisFunction *func = &basis[func_ind]; - //TODO: check if func->ctildes are zero, then skip -// ndensity = func->ndensity; - rank = func->rank; - r = rank - 1; -#ifdef PRINT_LOOPS_INDICES - printf("Num density = %d r = %d\n",(int) ndensity, (int)r ); - print_C_tilde_B_basis_function(*func); -#endif - mus = func->mus; - ns = func->ns; - ls = func->ls; - - //loop over {ms} combinations in sum - for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * rank]; // current ms-combination (of length = rank) - - //loop over m, collect B = product of A with given ms - A_forward_prod[0] = 1; - A_backward_prod[r] = 1; - - //fill forward A-product triangle - for (t = 0; t < rank; t++) { - //TODO: optimize ns[t]-1 -> ns[t] during functions construction - A_cache[t] = A(mus[t], ns[t] - 1, ls[t], ms[t]); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("A(x=%d, n=%d, l=%d, m=%d)=(%f,%f)\n", mus[t], ns[t], ls[t], ms[t], A_cache[t].real, - A_cache[t].img); -#endif - A_forward_prod[t + 1] = A_forward_prod[t] * A_cache[t]; - } - - B = A_forward_prod[t]; - -#ifdef DEBUG_FORCES_CALCULATIONS - printf("B = (%f, %f)\n", (B).real, (B).img); -#endif - //fill backward A-product triangle - for (t = r; t >= 1; t--) { - A_backward_prod[t - 1] = - A_backward_prod[t] * A_cache[t]; - } - - for (t = 0; t < rank; ++t, ++func_ms_t_ind) { - dB = A_forward_prod[t] * A_backward_prod[t]; //dB - product of all A's except t-th - dB_flatten(func_ms_t_ind) = dB; -#ifdef DEBUG_FORCES_CALCULATIONS - m_t = ms[t]; - printf("dB(n,l,m)(%d,%d,%d) = (%f, %f)\n", ns[t], ls[t], m_t, (dB).real, (dB).img); -#endif - } - - for (DENSITY_TYPE p = 0; p < ndensity; ++p) { - //real-part only multiplication - rhos(p) += B.real_part_product(func->ctildes[ms_ind * ndensity + p]); - -#ifdef EXTRA_C_PROJECTIONS - //aggregate C-projections separately - basis_projections(func_ind, p)+=B.real_part_product(func->ctildes[ms_ind * ndensity + p]); -#endif - -#ifdef PRINT_INTERMEDIATE_VALUES - printf("rhos(%d) += %f\n", p, B.real_part_product(func->ctildes[ms_ind * ndensity + p])); - printf("Rho[i = %d][p = %d] = %f\n", i , p , rhos(p)); -#endif - } - }//end of loop over {ms} combinations in sum - }// end loop for rank>1 - -#ifdef DEBUG_FORCES_CALCULATIONS - printf("rhos = "); - for(DENSITY_TYPE p =0; prho_core_cutoffs(mu_i); - drho_cut = basis_set->drho_core_cutoffs(mu_i); - - basis_set->inner_cutoff(rho_core, rho_cut, drho_cut, fcut, dfcut); - basis_set->FS_values_and_derivatives(rhos, evdwl, dF_drho, ndensity); - - dF_drho_core = evdwl * dfcut + 1; - for (DENSITY_TYPE p = 0; p < ndensity; ++p) - dF_drho(p) *= fcut; - evdwl_cut = evdwl * fcut + rho_core; - - // E0 shift - evdwl_cut += basis_set->E0vals(mu_i); - -#ifdef DEBUG_FORCES_CALCULATIONS - printf("dFrhos = "); - for(DENSITY_TYPE p =0; pndensity; - for (DENSITY_TYPE p = 0; p < ndensity; ++p) { - //for rank=1 (r=0) only 1 ms-combination exists (ms_ind=0), so index of func.ctildes is 0..ndensity-1 - weights_rank1(func->mus[0], func->ns[0] - 1) += dF_drho(p) * func->ctildes[p]; - } - } - - // rank>1 - func_ms_ind = 0; - func_ms_t_ind = 0;// index for dB - DOUBLE_TYPE theta = 0; - for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { - ACECTildeBasisFunction *func = &basis[func_ind]; -// ndensity = func->ndensity; - rank = func->rank; - mus = func->mus; - ns = func->ns; - ls = func->ls; - for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * rank]; - theta = 0; - for (DENSITY_TYPE p = 0; p < ndensity; ++p) { - theta += dF_drho(p) * func->ctildes[ms_ind * ndensity + p]; -#ifdef DEBUG_FORCES_CALCULATIONS - printf("(p=%d) theta += dF_drho[p] * func.ctildes[ms_ind * ndensity + p] = %f * %f = %f\n",p, dF_drho(p), func->ctildes[ms_ind * ndensity + p],dF_drho(p)*func->ctildes[ms_ind * ndensity + p]); - printf("theta=%f\n",theta); -#endif - } - - theta *= 0.5; // 0.5 factor due to possible double counting ??? - for (t = 0; t < rank; ++t, ++func_ms_t_ind) { - m_t = ms[t]; - factor = (m_t % 2 == 0 ? 1 : -1); - dB = dB_flatten(func_ms_t_ind); - weights(mus[t], ns[t] - 1, ls[t], m_t) += theta * dB; //Theta_array(func_ms_ind); - // update -m_t (that could also be positive), because the basis is half_basis - weights(mus[t], ns[t] - 1, ls[t], -m_t) += - theta * (dB).conjugated() * factor;// Theta_array(func_ms_ind); -#ifdef DEBUG_FORCES_CALCULATIONS - printf("dB(n,l,m)(%d,%d,%d) = (%f, %f)\n", ns[t], ls[t], m_t, (dB).real, (dB).img); - printf("theta = %f\n",theta); - printf("weights(n,l,m)(%d,%d,%d) += (%f, %f)\n", ns[t], ls[t], m_t, (theta * dB * 0.5).real, - (theta * dB * 0.5).img); - printf("weights(n,l,-m)(%d,%d,%d) += (%f, %f)\n", ns[t], ls[t], -m_t, - ( theta * (dB).conjugated() * factor * 0.5).real, - ( theta * (dB).conjugated() * factor * 0.5).img); -#endif - } - } - } - energy_calc_timer.stop(); - -// ==================== FORCES ==================== -#ifdef PRINT_MAIN_STEPS - printf("\nFORCE CALCULATION\n"); - printf("loop over neighbours\n"); -#endif - - forces_calc_loop_timer.start(); -// loop over neighbour atoms for force calculations - for (jj = 0; jj < jnum_actual; ++jj) { - mu_j = elements[jj]; - r_hat = rhats[jj]; - inv_r_norm = inv_r_norms[jj]; - - Array2DLM &Y_cache_jj = Y_cache(jj); - Array2DLM &DY_cache_jj = DY_cache(jj); - -#ifdef PRINT_LOOPS_INDICES - printf("\nneighbour atom #%d\n", jj); - printf("rhat = (%f, %f, %f)\n", r_hat[0], r_hat[1], r_hat[2]); -#endif - - forces_calc_neighbour_timer.start(); - - f_ji[0] = f_ji[1] = f_ji[2] = 0; - -//for rank = 1 - for (n = 0; n < nradbasei; ++n) { - if (weights_rank1(mu_j, n) == 0) - continue; - auto &DG = DG_cache(jj, n); - DGR = DG * Y00; - DGR *= weights_rank1(mu_j, n); -#ifdef DEBUG_FORCES_CALCULATIONS - printf("r=1: (n,l,m)=(%d, 0, 0)\n",n+1); - printf("\tGR(n=%d, r=%f)=%f\n",n+1,r_norm, gr(n)); - printf("\tDGR(n=%d, r=%f)=%f\n",n+1,r_norm, dgr(n)); - printf("\tdF+=(%f, %f, %f)\n",DGR * r_hat[0], DGR * r_hat[1], DGR * r_hat[2]); -#endif - f_ji[0] += DGR * r_hat[0]; - f_ji[1] += DGR * r_hat[1]; - f_ji[2] += DGR * r_hat[2]; - } - -//for rank > 1 - for (n = 0; n < nradiali; n++) { - for (l = 0; l <= lmaxi; l++) { - R_over_r = R_cache(jj, n, l) * inv_r_norm; - DR = DR_cache(jj, n, l); - - // for m>=0 - for (m = 0; m <= l; m++) { - ACEComplex w = weights(mu_j, n, l, m); - if (w == 0) - continue; - //counting for -m cases if m>0 - if (m > 0) w *= 2; - - DY = DY_cache_jj(l, m); - Y_DR = Y_cache_jj(l, m) * DR; - - grad_phi_nlm.a[0] = Y_DR * r_hat[0] + DY.a[0] * R_over_r; - grad_phi_nlm.a[1] = Y_DR * r_hat[1] + DY.a[1] * R_over_r; - grad_phi_nlm.a[2] = Y_DR * r_hat[2] + DY.a[2] * R_over_r; -#ifdef DEBUG_FORCES_CALCULATIONS - printf("d_phi(n=%d, l=%d, m=%d) = ((%f,%f), (%f,%f), (%f,%f))\n",n+1,l,m, - grad_phi_nlm.a[0].real, grad_phi_nlm.a[0].img, - grad_phi_nlm.a[1].real, grad_phi_nlm.a[1].img, - grad_phi_nlm.a[2].real, grad_phi_nlm.a[2].img); - - printf("weights(n,l,m)(%d,%d,%d) = (%f,%f)\n", n+1, l, m,w.real, w.img); - //if (m>0) w*=2; - printf("dF(n,l,m)(%d, %d, %d) += (%f, %f, %f)\n", n + 1, l, m, - w.real_part_product(grad_phi_nlm.a[0]), - w.real_part_product(grad_phi_nlm.a[1]), - w.real_part_product(grad_phi_nlm.a[2]) - ); -#endif -// real-part multiplication only - f_ji[0] += w.real_part_product(grad_phi_nlm.a[0]); - f_ji[1] += w.real_part_product(grad_phi_nlm.a[1]); - f_ji[2] += w.real_part_product(grad_phi_nlm.a[2]); - } - } - } - - -#ifdef PRINT_INTERMEDIATE_VALUES - printf("f_ji(jj=%d, i=%d)=(%f, %f, %f)\n", jj, i, - f_ji[0], f_ji[1], f_ji[2] - ); -#endif - - //hard-core repulsion - DCR = DCR_cache(jj); -#ifdef DEBUG_FORCES_CALCULATIONS - printf("DCR = %f\n",DCR); -#endif - f_ji[0] += dF_drho_core * DCR * r_hat[0]; - f_ji[1] += dF_drho_core * DCR * r_hat[1]; - f_ji[2] += dF_drho_core * DCR * r_hat[2]; -#ifdef PRINT_INTERMEDIATE_VALUES - printf("with core-repulsion\n"); - printf("f_ji(jj=%d, i=%d)=(%f, %f, %f)\n", jj, i, - f_ji[0], f_ji[1], f_ji[2] - ); - printf("neighbour_index_mapping[jj=%d]=%d\n",jj,neighbour_index_mapping[jj]); -#endif - - neighbours_forces(neighbour_index_mapping[jj], 0) = f_ji[0]; - neighbours_forces(neighbour_index_mapping[jj], 1) = f_ji[1]; - neighbours_forces(neighbour_index_mapping[jj], 2) = f_ji[2]; - - forces_calc_neighbour_timer.stop(); - }// end loop over neighbour atoms for forces - - forces_calc_loop_timer.stop(); - - //now, energies and forces are ready - //energies(i) = evdwl + rho_core; - e_atom = evdwl_cut; - -#ifdef PRINT_INTERMEDIATE_VALUES - printf("energies(i) = FS(...rho_p_accum...) = %f\n", evdwl); -#endif - per_atom_calc_timer.stop(); -} \ No newline at end of file diff --git a/lib/pace/ace_evaluator.h b/lib/pace/ace_evaluator.h deleted file mode 100644 index 356ea52563..0000000000 --- a/lib/pace/ace_evaluator.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Yury Lysogorskiy on 31.01.20. - -#ifndef ACE_EVALUATOR_H -#define ACE_EVALUATOR_H - -#include "ace_abstract_basis.h" -#include "ace_arraynd.h" -#include "ace_array2dlm.h" -#include "ace_c_basis.h" -#include "ace_complex.h" -#include "ace_timing.h" -#include "ace_types.h" - -/** - * Basic evaluator class, that should accept the basis set and implement the "compute_atom" method using given basis set. - */ -class ACEEvaluator { -protected: - - Array2D A_rank1 = Array2D("A_rank1"); ///< 2D-array for storing A's for rank=1, shape: A(mu_j,n) - Array4DLM A = Array4DLM("A"); ///< 4D array with (l,m) last indices for storing A's for rank>1: A(mu_j, n, l, m) - - Array1D rhos = Array1D("rhos"); ///< densities \f$ \rho^{(p)} \f$(ndensity), p = 0 .. ndensity-1 - Array1D dF_drho = Array1D("dF_drho"); ///< derivatives of cluster functional wrt. densities, index = 0 .. ndensity-1 - - /** - * Initialize internal arrays according to basis set sizes - * @param basis_set - */ - void init(ACEAbstractBasisSet *basis_set); - -public: - // set of timers for code profiling - - ACETimer loop_over_neighbour_timer; ///< timer for loop over neighbours when constructing A's for single central atom - ACETimer per_atom_calc_timer; ///< timer for single compute_atom call - - - ACETimer forces_calc_loop_timer; ///< timer for forces calculations for single central atom - ACETimer forces_calc_neighbour_timer; ///< timer for loop over neighbour atoms for force calculations - - ACETimer energy_calc_timer; ///< timer for energy calculation - ACETimer total_time_calc_timer; ///< timer for total calculations of all atoms within given atomic environment system - - /** - * Initialize all timers - */ - void init_timers(); - - /** - * Mapping from external atoms types, i.e. LAMMPS, to internal SPECIES_TYPE, used in basis functions - */ - Array1D element_type_mapping = Array1D("element_type_mapping"); - - - DOUBLE_TYPE e_atom = 0; ///< energy of current atom, including core-repulsion - - /** - * temporary array for the pair forces between current atom_i and its neighbours atom_k - * neighbours_forces(k,3), k = 0..num_of_neighbours(atom_i)-1 - */ - Array2D neighbours_forces = Array2D("neighbours_forces"); - - ACEEvaluator() = default; - - virtual ~ACEEvaluator() = default; - - /** - * The key method to compute energy and forces for atom 'i'. - * Method will update the "e_atom" variable and "neighbours_forces(jj, alpha)" array - * - * @param i atom index - * @param x atomic positions array of the real and ghost atoms, shape: [atom_ind][3] - * @param type atomic types array of the real and ghost atoms, shape: [atom_ind] - * @param jnum number of neighbours of atom_i - * @param jlist array of neighbour indices, shape: [jnum] - */ - virtual void compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *type, const int jnum, const int *jlist) = 0; - - /** - * Resize all caches over neighbours atoms - * @param max_jnum maximum number of neighbours - */ - virtual void resize_neighbours_cache(int max_jnum) = 0; - -#ifdef EXTRA_C_PROJECTIONS - /** - * 2D array to store projections of basis function for rank = 1, shape: [func_ind][ndensity] - */ - Array2D basis_projections_rank1 = Array2D("basis_projections_rank1"); - - /** - * 2D array to store projections of basis function for rank > 1, shape: [func_ind][ndensity] - */ - Array2D basis_projections = Array2D("basis_projections"); -#endif -}; - -//TODO: split into separate file -/** - * Evaluator for C-tilde basis set, that should accept the basis set and implement the "compute_atom" method using given basis set. - */ -class ACECTildeEvaluator : public ACEEvaluator { - - /** - * Weights \f$ \omega_{i \mu n 0 0} \f$ for rank = 1, see Eq.(10) from implementation notes, - * 'i' is fixed for the current atom, shape: [nelements][nradbase] - */ - Array2D weights_rank1 = Array2D("weights_rank1"); - - /** - * Weights \f$ \omega_{i \mu n l m} \f$ for rank > 1, see Eq.(10) from implementation notes, - * 'i' is fixed for the current atom, shape: [nelements][nradbase][l=0..lmax, m] - */ - Array4DLM weights = Array4DLM("weights"); - - /** - * cache for gradients of \f$ g(r)\f$: grad_phi(jj,n)=A2DLM(l,m) - * shape:[max_jnum][nradbase] - */ - Array2D DG_cache = Array2D("DG_cache"); - - - /** - * cache for \f$ R_{nl}(r)\f$ - * shape:[max_jnum][nradbase][0..lmax] - */ - Array3D R_cache = Array3D("R_cache"); - /** - * cache for derivatives of \f$ R_{nl}(r)\f$ - * shape:[max_jnum][nradbase][0..lmax] - */ - Array3D DR_cache = Array3D("DR_cache"); - /** - * cache for \f$ Y_{lm}(\hat{r})\f$ - * shape:[max_jnum][0..lmax][m] - */ - Array3DLM Y_cache = Array3DLM("Y_cache"); - /** - * cache for \f$ \nabla Y_{lm}(\hat{r})\f$ - * shape:[max_jnum][0..lmax][m] - */ - Array3DLM DY_cache = Array3DLM("dY_dense_cache"); - - /** - * cache for derivatives of hard-core repulsion - * shape:[max_jnum] - */ - Array1D DCR_cache = Array1D("DCR_cache"); - - /** - * Partial derivatives \f$ dB_{i \mu n l m t}^{(r)} \f$ with sequential numbering over [func_ind][ms_ind][r], - * shape:[func_ms_r_ind] - */ - Array1D dB_flatten = Array1D("dB_flatten"); - - /** - * pointer to the ACEBasisSet object - */ - ACECTildeBasisSet *basis_set = nullptr; - - /** - * Initialize internal arrays according to basis set sizes - * @param basis_set - */ - void init(ACECTildeBasisSet *basis_set); - -public: - - ACECTildeEvaluator() = default; - - explicit ACECTildeEvaluator(ACECTildeBasisSet &bas) { - set_basis(bas); - } - - /** - * set the basis function to the ACE evaluator - * @param bas - */ - void set_basis(ACECTildeBasisSet &bas); - - /** - * The key method to compute energy and forces for atom 'i'. - * Method will update the "e_atom" variable and "neighbours_forces(jj, alpha)" array - * - * @param i atom index - * @param x atomic positions array of the real and ghost atoms, shape: [atom_ind][3] - * @param type atomic types array of the real and ghost atoms, shape: [atom_ind] - * @param jnum number of neighbours of atom_i - * @param jlist array of neighbour indices, shape: [jnum] - */ - void compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *type, const int jnum, const int *jlist) override; - - /** - * Resize all caches over neighbours atoms - * @param max_jnum maximum number of neighbours - */ - void resize_neighbours_cache(int max_jnum) override; -}; - - -#endif //ACE_EVALUATOR_H \ No newline at end of file diff --git a/lib/pace/ace_flatten_basis.cpp b/lib/pace/ace_flatten_basis.cpp deleted file mode 100644 index 541785a202..0000000000 --- a/lib/pace/ace_flatten_basis.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by yury on 28.04.2020. - -#include "ace_flatten_basis.h" - -ACEFlattenBasisSet::ACEFlattenBasisSet(const ACEFlattenBasisSet &other) { - _copy_scalar_memory(other); - _copy_dynamic_memory(other); -} - -ACEFlattenBasisSet &ACEFlattenBasisSet::operator=(const ACEFlattenBasisSet &other) { - if (this != &other) { - _clean(); - _copy_scalar_memory(other); - _copy_dynamic_memory(other); - } - return *this; -} - - -ACEFlattenBasisSet::~ACEFlattenBasisSet() { - ACEFlattenBasisSet::_clean(); -} - -void ACEFlattenBasisSet::_clean() { - //chained call of base class method - ACEAbstractBasisSet::_clean(); - _clean_contiguous_arrays(); - _clean_basissize_arrays(); - -} - -void ACEFlattenBasisSet::_clean_basissize_arrays() { - delete[] total_basis_size; - total_basis_size = nullptr; - - delete[] total_basis_size_rank1; - total_basis_size_rank1 = nullptr; -} - -void ACEFlattenBasisSet::_clean_contiguous_arrays() { - delete[] full_ns_rank1; - full_ns_rank1 = nullptr; - - delete[] full_ls_rank1; - full_ls_rank1 = nullptr; - - delete[] full_mus_rank1; - full_mus_rank1 = nullptr; - - delete[] full_ms_rank1; - full_ms_rank1 = nullptr; - - ////// - - delete[] full_ns; - full_ns = nullptr; - - delete[] full_ls; - full_ls = nullptr; - - delete[] full_mus; - full_mus = nullptr; - - delete[] full_ms; - full_ms = nullptr; -} - -void ACEFlattenBasisSet::_copy_scalar_memory(const ACEFlattenBasisSet &src) { - ACEAbstractBasisSet::_copy_scalar_memory(src); - - rank_array_total_size_rank1 = src.rank_array_total_size_rank1; - coeff_array_total_size_rank1 = src.coeff_array_total_size_rank1; - rank_array_total_size = src.rank_array_total_size; - ms_array_total_size = src.ms_array_total_size; - coeff_array_total_size = src.coeff_array_total_size; - - max_B_array_size = src.max_B_array_size; - max_dB_array_size = src.max_dB_array_size; - num_ms_combinations_max = src.num_ms_combinations_max; -} - -void ACEFlattenBasisSet::_copy_dynamic_memory(const ACEFlattenBasisSet &src) { //allocate new memory - - ACEAbstractBasisSet::_copy_dynamic_memory(src); - - if (src.total_basis_size_rank1 == nullptr) - throw runtime_error("Could not copy ACEFlattenBasisSet::total_basis_size_rank1 - array not initialized"); - if (src.total_basis_size == nullptr) - throw runtime_error("Could not copy ACEFlattenBasisSet::total_basis_size - array not initialized"); - - delete[] total_basis_size_rank1; - total_basis_size_rank1 = new SHORT_INT_TYPE[nelements]; - delete[] total_basis_size; - total_basis_size = new SHORT_INT_TYPE[nelements]; - - //copy - for (SPECIES_TYPE mu = 0; mu < nelements; ++mu) { - total_basis_size_rank1[mu] = src.total_basis_size_rank1[mu]; - total_basis_size[mu] = src.total_basis_size[mu]; - } -} - diff --git a/lib/pace/ace_flatten_basis.h b/lib/pace/ace_flatten_basis.h deleted file mode 100644 index e21cbb749a..0000000000 --- a/lib/pace/ace_flatten_basis.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Lysogroskiy Yury on 28.04.2020. - -#ifndef ACE_EVALUATOR_ACE_FLATTEN_BASIS_H -#define ACE_EVALUATOR_ACE_FLATTEN_BASIS_H - - -#include "ace_abstract_basis.h" -#include "ace_c_basisfunction.h" -#include "ace_radial.h" -#include "ace_spherical_cart.h" -#include "ace_types.h" - -/** - * Basis set with basis function attributes, i.e. \f$ \mathbf{n}, \mathbf{l}, \mathbf{m}\f$, etc. - * packed into contiguous arrays for the cache-friendly memory layout. - */ -class ACEFlattenBasisSet : public ACEAbstractBasisSet { -public: - //arrays and its sizes for rank = 1 basis functions for packed basis - - size_t rank_array_total_size_rank1 = 0; ///< size for full_ns_rank1, full_ls_rank1, full_Xs_rank1 - size_t coeff_array_total_size_rank1 = 0; ///< size for full coefficients array (depends on B or C-Tilde basis) - - NS_TYPE *full_ns_rank1 = nullptr; ///< ns contiguous package [rank_array_total_size_rank1] - LS_TYPE *full_ls_rank1 = nullptr; ///< ls contiguous package [rank_array_total_size_rank1] - SPECIES_TYPE *full_mus_rank1 = nullptr; ///< mus contiguous package [rank_array_total_size_rank1] - MS_TYPE *full_ms_rank1 = nullptr; ///< m_s contiguous package[rank_array_total_size_rank1] - - //arrays and its sizes for rank > 1 basis functions for packed basis - size_t rank_array_total_size = 0; ///< size for full_ns, full_ls, full_Xs - size_t ms_array_total_size = 0; ///< size for full_ms array - size_t coeff_array_total_size = 0;///< size for full coefficients arrays (depends on B- or C- basis) - - NS_TYPE *full_ns = nullptr; ///< ns contiguous package [rank_array_total_size] - LS_TYPE *full_ls = nullptr; ///< ls contiguous package [rank_array_total_size] - SPECIES_TYPE *full_mus = nullptr; ///< mus contiguous package [rank_array_total_size] - MS_TYPE *full_ms = nullptr; ///< //m_s contiguous package [ms_array_total_size] - - /** - * Rearrange basis functions in contiguous memory to optimize cache access - */ - virtual void pack_flatten_basis() = 0; - - virtual void flatten_basis() = 0; - - //1D flat array basis representation: [mu] - SHORT_INT_TYPE *total_basis_size_rank1 = nullptr; ///< per-species type array of total_basis_rank1[mu] sizes - SHORT_INT_TYPE *total_basis_size = nullptr; ///< per-species type array of total_basis[mu] sizes - - size_t max_B_array_size = 0; ///< maximum over elements array size for B[func_ind][ms_ind] - size_t max_dB_array_size = 0; ///< maximum over elements array size for dB[func_ind][ms_ind][r] - - SHORT_INT_TYPE num_ms_combinations_max = 0; ///< maximum number of ms combinations among all basis functions - - /** - * Default constructor - */ - ACEFlattenBasisSet() = default; - - /** - * Copy constructor (see Rule of Three) - * @param other - */ - ACEFlattenBasisSet(const ACEFlattenBasisSet &other); - - /** - * operator= (see Rule of Three) - * @param other - * @return - */ - ACEFlattenBasisSet &operator=(const ACEFlattenBasisSet &other); - - /** - * Destructor (see Rule of Three) - */ - ~ACEFlattenBasisSet() override; - - // routines for copying and cleaning dynamic memory of the class (see Rule of Three) - /** - * Cleaning dynamic memory of the class (see. Rule of Three), - * must be idempotent for safety - */ - void _clean() override; - - /** - * Copying scalar variables - * @param src - */ - void _copy_scalar_memory(const ACEFlattenBasisSet &src); - - /** - * Copying and cleaning dynamic memory of the class (see. Rule of Three) - * @param src - */ - void _copy_dynamic_memory(const ACEFlattenBasisSet &src); - - /** - * Clean contiguous arrays - */ - virtual void _clean_contiguous_arrays(); - - /** - * Release dynamic arrays with basis set sizes - */ - void _clean_basissize_arrays(); -}; - -#endif //ACE_EVALUATOR_ACE_FLATTEN_BASIS_H diff --git a/lib/pace/ace_radial.cpp b/lib/pace/ace_radial.cpp deleted file mode 100644 index 01348a719c..0000000000 --- a/lib/pace/ace_radial.cpp +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -#include -#include -#include - -#include "ace_radial.h" - -const DOUBLE_TYPE pi = 3.14159265358979323846264338327950288419; // pi - -ACERadialFunctions::ACERadialFunctions(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, - SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, string radbasename) { - init(nradb, lmax, nradial, deltaSplineBins, nelements, cutoff, radbasename); -} - -void ACERadialFunctions::init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, - SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, string radbasename) { - this->nradbase = nradb; - this->lmax = lmax; - this->nradial = nradial; - this->deltaSplineBins = deltaSplineBins; - this->nelements = nelements; - this->cutoff = cutoff; - this->radbasename = radbasename; - - gr.init(nradbase, "gr"); - dgr.init(nradbase, "dgr"); - d2gr.init(nradbase, "d2gr"); - - - fr.init(nradial, lmax + 1, "fr"); - dfr.init(nradial, lmax + 1, "dfr"); - d2fr.init(nradial, lmax + 1, "d2fr"); - - - cheb.init(nradbase + 1, "cheb"); - dcheb.init(nradbase + 1, "dcheb"); - cheb2.init(nradbase + 1, "cheb2"); - - - splines_gk.init(nelements, nelements, "splines_gk"); - splines_rnl.init(nelements, nelements, "splines_rnl"); - splines_hc.init(nelements, nelements, "splines_hc"); - - lambda.init(nelements, nelements, "lambda"); - lambda.fill(1.); - - cut.init(nelements, nelements, "cut"); - cut.fill(1.); - - dcut.init(nelements, nelements, "dcut"); - dcut.fill(1.); - - crad.init(nelements, nelements, nradial, (lmax + 1), nradbase, "crad"); - crad.fill(0.); - - //hard-core repulsion - prehc.init(nelements, nelements, "prehc"); - prehc.fill(0.); - - lambdahc.init(nelements, nelements, "lambdahc"); - lambdahc.fill(1.); - -} - - -/** -Function that computes Chebyshev polynomials of first and second kind - to setup the radial functions and the derivatives - -@param n, x - -@returns cheb1, dcheb1 -*/ -void ACERadialFunctions::calcCheb(NS_TYPE n, DOUBLE_TYPE x) { - if (n < 0) { - char s[1024]; - sprintf(s, "The order n of the polynomials should be positive %d\n", n); - throw std::invalid_argument(s); - } - DOUBLE_TYPE twox = 2.0 * x; - cheb(0) = 1.; - dcheb(0) = 0.; - cheb2(0) = 1.; - - if (nradbase > 1) { - cheb(1) = x; - cheb2(1) = twox; - } - for (NS_TYPE m = 1; m <= n - 1; m++) { - cheb(m + 1) = twox * cheb(m) - cheb(m - 1); - cheb2(m + 1) = twox * cheb2(m) - cheb2(m - 1); - } - for (NS_TYPE m = 1; m <= n; m++) { - dcheb(m) = m * cheb2(m - 1); - } -#ifdef DEBUG_RADIAL - for ( NS_TYPE m=0; m<=n; m++ ) { - printf(" m %d cheb %f dcheb %f \n", m, cheb(m), dcheb(m)); - } -#endif -} - -/** -Function that computes radial basis. - -@param lam, nradbase, cut, dcut, r - -@returns gr, dgr -*/ -void ACERadialFunctions::radbase(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r) { - /*lam is given by the formula (24), that contains cut */ - - if (r < cut) { - if (radbasename == "ChebExpCos") { - chebExpCos(lam, cut, dcut, r); - } else if (radbasename == "ChebPow") { - chebPow(lam, cut, dcut, r); - } else if (radbasename == "ChebLinear") { - chebLinear(lam, cut, dcut, r); - } else { - throw invalid_argument("Unknown radial basis function name: " + radbasename); - } - } else { - gr.fill(0); - dgr.fill(0); - } -} - -/*** - * Radial function: ChebExpCos, cheb exp scaling including cos envelope - * @param lam function parameter - * @param cut cutoff distance - * @param r function input argument - * @return fills in gr and dgr arrays - */ -void -ACERadialFunctions::chebExpCos(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r) { - DOUBLE_TYPE y2, y1, x, dx; - DOUBLE_TYPE env, denv, fcut, dfcut; - /* scaled distance x and derivative*/ - y1 = exp(-lam * r / cut); - y2 = exp(-lam); - x = 1.0 - 2.0 * ((y1 - y2) / (1 - y2)); - dx = 2 * (lam / cut) * (y1 / (1 - y2)); - /* calculation of Chebyshev polynomials from the recursion */ - calcCheb(nradbase - 1, x); - gr(0) = cheb(0); - dgr(0) = dcheb(0) * dx; - for (NS_TYPE n = 2; n <= nradbase; n++) { - gr(n - 1) = 0.5 - 0.5 * cheb(n - 1); - dgr(n - 1) = -0.5 * dcheb(n - 1) * dx; - } - env = 0.5 * (1.0 + cos(M_PI * r / cut)); - denv = -0.5 * sin(M_PI * r / cut) * M_PI / cut; - for (NS_TYPE n = 0; n < nradbase; n++) { - dgr(n) = gr(n) * denv + dgr(n) * env; - gr(n) = gr(n) * env; - } - // for radtype = 3 a smooth cut is already included in the basis function - dx = cut - dcut; - if (r > dx) { - fcut = 0.5 * (1.0 + cos(M_PI * (r - dx) / dcut)); - dfcut = -0.5 * sin(M_PI * (r - dx) / dcut) * M_PI / dcut; - for (NS_TYPE n = 0; n < nradbase; n++) { - dgr(n) = gr(n) * dfcut + dgr(n) * fcut; - gr(n) = gr(n) * fcut; - } - } -} - -/*** -* Radial function: ChebPow, Radial function: ChebPow -* - argument of Chebyshev polynomials -* x = 2.0*( 1.0 - (1.0 - r/rcut)^lam ) - 1.0 -* - radial function -* gr(n) = ( 1.0 - Cheb(n) )/2.0, n = 1,...,nradbase -* - the function fulfills: -* gr(n) = 0 at rcut -* dgr(n) = 0 at rcut for lam >= 1 -* second derivative zero at rcut for lam >= 2 -* -> the radial function does not require a separate cutoff function -* - corresponds to radial basis radtype=5 in Fortran code -* -* @param lam function parameter -* @param cut cutoff distance -* @param r function input argument -* @return fills in gr and dgr arrays -*/ -void -ACERadialFunctions::chebPow(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r) { - DOUBLE_TYPE y, dy, x, dx; - /* scaled distance x and derivative*/ - y = (1.0 - r / cut); - dy = pow(y, (lam - 1.0)); - y = dy * y; - dy = -lam / cut * dy; - - x = 2.0 * (1.0 - y) - 1.0; - dx = -2.0 * dy; - calcCheb(nradbase, x); - for (NS_TYPE n = 1; n <= nradbase; n++) { - gr(n - 1) = 0.5 - 0.5 * cheb(n); - dgr(n - 1) = -0.5 * dcheb(n) * dx; - } -} - - -void -ACERadialFunctions::chebLinear(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r) { - DOUBLE_TYPE x, dx; - /* scaled distance x and derivative*/ - x = (1.0 - r / cut); - dx = -1 / cut; - calcCheb(nradbase, x); - for (NS_TYPE n = 1; n <= nradbase; n++) { - gr(n - 1) = 0.5 - 0.5 * cheb(n); - dgr(n - 1) = -0.5 * dcheb(n) * dx; - } -} - -/** -Function that computes radial functions. - -@param nradbase, nelements, elei, elej - -@returns fr, dfr -*/ -void ACERadialFunctions::radfunc(SPECIES_TYPE elei, SPECIES_TYPE elej) { - DOUBLE_TYPE frval, dfrval; - for (NS_TYPE n = 0; n < nradial; n++) { - for (LS_TYPE l = 0; l <= lmax; l++) { - frval = 0.0; - dfrval = 0.0; - for (NS_TYPE k = 0; k < nradbase; k++) { - frval += crad(elei, elej, n, l, k) * gr(k); - dfrval += crad(elei, elej, n, l, k) * dgr(k); - } - fr(n, l) = frval; - dfr(n, l) = dfrval; - } - } -} - - -void ACERadialFunctions::all_radfunc(SPECIES_TYPE mu_i, SPECIES_TYPE mu_j, DOUBLE_TYPE r) { - DOUBLE_TYPE lam = lambda(mu_i, mu_j); - DOUBLE_TYPE r_cut = cut(mu_i, mu_j); - DOUBLE_TYPE dr_cut = dcut(mu_i, mu_j); - // set up radial functions - radbase(lam, r_cut, dr_cut, r); //update gr, dgr - radfunc(mu_i, mu_j); // update fr(nr, l), dfr(nr, l) -} - - -void ACERadialFunctions::setuplookupRadspline() { - using namespace std::placeholders; - DOUBLE_TYPE lam, r_cut, dr_cut; - DOUBLE_TYPE cr_c, dcr_c, pre, lamhc; - - // at r = rcut + eps the function and its derivatives is zero - for (SPECIES_TYPE elei = 0; elei < nelements; elei++) { - for (SPECIES_TYPE elej = 0; elej < nelements; elej++) { - - lam = lambda(elei, elej); - r_cut = cut(elei, elej); - dr_cut = dcut(elei, elej); - - splines_gk(elei, elej).setupSplines(gr.get_size(), - std::bind(&ACERadialFunctions::radbase, this, lam, r_cut, dr_cut, - _1),//update gr, dgr - gr.get_data(), - dgr.get_data(), deltaSplineBins, cutoff); - - splines_rnl(elei, elej).setupSplines(fr.get_size(), - std::bind(&ACERadialFunctions::all_radfunc, this, elei, elej, - _1), // update fr(nr, l), dfr(nr, l) - fr.get_data(), - dfr.get_data(), deltaSplineBins, cutoff); - - - pre = prehc(elei, elej); - lamhc = lambdahc(elei, elej); -// radcore(r, pre, lamhc, cutoff, cr_c, dcr_c); - splines_hc(elei, elej).setupSplines(1, - std::bind(&ACERadialFunctions::radcore, _1, pre, lamhc, cutoff, - std::ref(cr_c), std::ref(dcr_c)), - &cr_c, - &dcr_c, deltaSplineBins, cutoff); - } - } - -} - -/** -Function that gets radial function from look-up table using splines. - -@param r, nradbase_c, nradial_c, lmax, mu_i, mu_j - -@returns fr, dfr, gr, dgr, cr, dcr -*/ -void -ACERadialFunctions::evaluate(DOUBLE_TYPE r, NS_TYPE nradbase_c, NS_TYPE nradial_c, SPECIES_TYPE mu_i, - SPECIES_TYPE mu_j, bool calc_second_derivatives) { - auto &spline_gk = splines_gk(mu_i, mu_j); - auto &spline_rnl = splines_rnl(mu_i, mu_j); - auto &spline_hc = splines_hc(mu_i, mu_j); - - spline_gk.calcSplines(r, calc_second_derivatives); // populate splines_gk.values, splines_gk.derivatives; - for (NS_TYPE nr = 0; nr < nradbase_c; nr++) { - gr(nr) = spline_gk.values(nr); - dgr(nr) = spline_gk.derivatives(nr); - if (calc_second_derivatives) - d2gr(nr) = spline_gk.second_derivatives(nr); - } - - spline_rnl.calcSplines(r, calc_second_derivatives); - for (size_t ind = 0; ind < fr.get_size(); ind++) { - fr.get_data(ind) = spline_rnl.values.get_data(ind); - dfr.get_data(ind) = spline_rnl.derivatives.get_data(ind); - if (calc_second_derivatives) - d2fr.get_data(ind) = spline_rnl.second_derivatives.get_data(ind); - } - - spline_hc.calcSplines(r, calc_second_derivatives); - cr = spline_hc.values(0); - dcr = spline_hc.derivatives(0); - if (calc_second_derivatives) - d2cr = spline_hc.second_derivatives(0); -} - - -void -ACERadialFunctions::radcore(DOUBLE_TYPE r, DOUBLE_TYPE pre, DOUBLE_TYPE lambda, DOUBLE_TYPE cutoff, DOUBLE_TYPE &cr, - DOUBLE_TYPE &dcr) { -/* pseudocode for hard core repulsion -in: - r: distance - pre: prefactor: read from input, depends on pair of atoms mu_i mu_j - lambda: exponent: read from input, depends on pair of atoms mu_i mu_j - cutoff: cutoff distance: read from input, depends on pair of atoms mu_i mu_j -out: -cr: hard core repulsion -dcr: derivative of hard core repulsion - - function - \$f f_{core} = pre \exp( - \lambda r^2 ) / r \$f - -*/ - - DOUBLE_TYPE r2, lr2, y, x0, env, denv; - -// repulsion strictly positive and decaying - pre = abs(pre); - lambda = abs(lambda); - - r2 = r * r; - lr2 = lambda * r2; - if (lr2 < 50.0) { - y = exp(-lr2); - cr = pre * y / r; - dcr = -pre * y * (2.0 * lr2 + 1.0) / r2; - - x0 = r / cutoff; - env = 0.5 * (1.0 + cos(pi * x0)); - denv = -0.5 * sin(pi * x0) * pi / cutoff; - dcr = cr * denv + dcr * env; - cr = cr * env; - } else { - cr = 0.0; - dcr = 0.0; - } - -} - -void -ACERadialFunctions::evaluate_range(vector r_vec, NS_TYPE nradbase_c, NS_TYPE nradial_c, SPECIES_TYPE mu_i, - SPECIES_TYPE mu_j) { - if (nradbase_c > nradbase) - throw invalid_argument("nradbase_c couldn't be larger than nradbase"); - if (nradial_c > nradial) - throw invalid_argument("nradial_c couldn't be larger than nradial"); - if (mu_i > nelements) - throw invalid_argument("mu_i couldn't be larger than nelements"); - if (mu_j > nelements) - throw invalid_argument("mu_j couldn't be larger than nelements"); - - gr_vec.resize(r_vec.size(), nradbase_c); - dgr_vec.resize(r_vec.size(), nradbase_c); - d2gr_vec.resize(r_vec.size(), nradbase_c); - - fr_vec.resize(r_vec.size(), fr.get_dim(0), fr.get_dim(1)); - dfr_vec.resize(r_vec.size(), fr.get_dim(0), fr.get_dim(1)); - d2fr_vec.resize(r_vec.size(), fr.get_dim(0), fr.get_dim(1)); - - for (size_t i = 0; i < r_vec.size(); i++) { - DOUBLE_TYPE r = r_vec[i]; - this->evaluate(r, nradbase_c, nradial_c, mu_i, mu_j, true); - for (NS_TYPE nr = 0; nr < nradbase_c; nr++) { - gr_vec(i, nr) = gr(nr); - dgr_vec(i, nr) = dgr(nr); - d2gr_vec(i, nr) = d2gr(nr); - } - - for (NS_TYPE nr = 0; nr < nradial_c; nr++) { - for (LS_TYPE l = 0; l <= lmax; l++) { - fr_vec(i, nr, l) = fr(nr, l); - dfr_vec(i, nr, l) = dfr(nr, l); - d2fr_vec(i, nr, l) = d2fr(nr, l); - - } - } - } - -} - -void SplineInterpolator::setupSplines(int num_of_functions, RadialFunctions func, - DOUBLE_TYPE *values, - DOUBLE_TYPE *dvalues, DOUBLE_TYPE deltaSplineBins, DOUBLE_TYPE cutoff) { - - this->deltaSplineBins = deltaSplineBins; - this->cutoff = cutoff; - this->ntot = static_cast(cutoff / deltaSplineBins); - - DOUBLE_TYPE r, c[4]; - this->num_of_functions = num_of_functions; - this->values.resize(num_of_functions); - this->derivatives.resize(num_of_functions); - this->second_derivatives.resize(num_of_functions); - - Array1D f1g(num_of_functions); - Array1D f1gd1(num_of_functions); - f1g.fill(0); - f1gd1.fill(0); - - nlut = ntot; - DOUBLE_TYPE f0, f1, f0d1, f1d1; - int idx; - - // cutoff is global cutoff - rscalelookup = (DOUBLE_TYPE) nlut / cutoff; - invrscalelookup = 1.0 / rscalelookup; - - lookupTable.init(ntot + 1, num_of_functions, 4); - if (values == nullptr & num_of_functions > 0) - throw invalid_argument("SplineInterpolator::setupSplines: values could not be null"); - if (dvalues == nullptr & num_of_functions > 0) - throw invalid_argument("SplineInterpolator::setupSplines: dvalues could not be null"); - - for (int n = nlut; n >= 1; n--) { - r = invrscalelookup * DOUBLE_TYPE(n); - func(r); //populate values and dvalues arrays - for (int func_id = 0; func_id < num_of_functions; func_id++) { - f0 = values[func_id]; - f1 = f1g(func_id); - f0d1 = dvalues[func_id] * invrscalelookup; - f1d1 = f1gd1(func_id); - // evaluate coefficients - c[0] = f0; - c[1] = f0d1; - c[2] = 3.0 * (f1 - f0) - f1d1 - 2.0 * f0d1; - c[3] = -2.0 * (f1 - f0) + f1d1 + f0d1; - // store coefficients - for (idx = 0; idx <= 3; idx++) - lookupTable(n, func_id, idx) = c[idx]; - - // evaluate function values and derivatives at current position - f1g(func_id) = c[0]; - f1gd1(func_id) = c[1]; - } - } - - -} - - -void SplineInterpolator::calcSplines(DOUBLE_TYPE r, bool calc_second_derivatives) { - DOUBLE_TYPE wl, wl2, wl3, w2l1, w3l2, w4l2; - DOUBLE_TYPE c[4]; - int func_id, idx; - DOUBLE_TYPE x = r * rscalelookup; - int nl = static_cast(floor(x)); - - if (nl <= 0) - throw std::invalid_argument("Encountered very small distance. Stopping."); - - if (nl < nlut) { - wl = x - DOUBLE_TYPE(nl); - wl2 = wl * wl; - wl3 = wl2 * wl; - w2l1 = 2.0 * wl; - w3l2 = 3.0 * wl2; - w4l2 = 6.0 * wl; - for (func_id = 0; func_id < num_of_functions; func_id++) { - for (idx = 0; idx <= 3; idx++) { - c[idx] = lookupTable(nl, func_id, idx); - } - values(func_id) = c[0] + c[1] * wl + c[2] * wl2 + c[3] * wl3; - derivatives(func_id) = (c[1] + c[2] * w2l1 + c[3] * w3l2) * rscalelookup; - if (calc_second_derivatives) - second_derivatives(func_id) = (c[2] + c[3] * w4l2) * rscalelookup * rscalelookup * 2; - } - } else { // fill with zeroes - values.fill(0); - derivatives.fill(0); - if (calc_second_derivatives) - second_derivatives.fill(0); - } -} - -void SplineInterpolator::calcSplines(DOUBLE_TYPE r, SHORT_INT_TYPE func_ind) { - DOUBLE_TYPE wl, wl2, wl3, w2l1, w3l2; - DOUBLE_TYPE c[4]; - int idx; - DOUBLE_TYPE x = r * rscalelookup; - int nl = static_cast(floor(x)); - - if (nl <= 0) - throw std::invalid_argument("Encountered very small distance. Stopping."); - - if (nl < nlut) { - wl = x - DOUBLE_TYPE(nl); - wl2 = wl * wl; - wl3 = wl2 * wl; - w2l1 = 2.0 * wl; - w3l2 = 3.0 * wl2; - - for (idx = 0; idx <= 3; idx++) { - c[idx] = lookupTable(nl, func_ind, idx); - } - values(func_ind) = c[0] + c[1] * wl + c[2] * wl2 + c[3] * wl3; - derivatives(func_ind) = (c[1] + c[2] * w2l1 + c[3] * w3l2) * rscalelookup; - - } else { // fill with zeroes - values(func_ind) = 0; - derivatives(func_ind) = 0; - } -} diff --git a/lib/pace/ace_radial.h b/lib/pace/ace_radial.h deleted file mode 100644 index e45cfaec79..0000000000 --- a/lib/pace/ace_radial.h +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -#ifndef ACE_RADIAL_FUNCTIONS_H -#define ACE_RADIAL_FUNCTIONS_H - -#include "ace_arraynd.h" -#include "ace_types.h" -#include - -using namespace std; - -//typedef void (*RadialFunctions)(DOUBLE_TYPE x); -typedef std::function RadialFunctions; - -/** - * Class that implement spline interpolation and caching for radial functions - */ -class SplineInterpolator { -public: - DOUBLE_TYPE cutoff = 0; ///< cutoff - DOUBLE_TYPE deltaSplineBins = 0.001; - int ntot = 10000; ///< Number of bins for look-up tables. - int nlut = 10000; ///< number of nodes in look-up table - DOUBLE_TYPE invrscalelookup = 1; ///< inverse of conversion coefficient from distance to lookup table within cutoff range - DOUBLE_TYPE rscalelookup = 1; ///< conversion coefficient from distance to lookup table within cutoff range - int num_of_functions = 0;///< number of functions to spline-interpolation - - Array1D values;// = Array1D("values"); ///< shape: [func_ind] - Array1D derivatives;// = Array1D("derivatives");///< shape: [func_ind] - Array1D second_derivatives;// = Array1D("second_derivatives");///< shape: [func_ind] - - Array3D lookupTable = Array3D("lookupTable");///< shape: [ntot+1][func_ind][4] - - /** - * Setup splines - * - * @param num_of_functions number of functions - * @param func subroutine, that update `values` and `dvalues` arrays - * @param values values - * @param dvalues derivatives - */ - void setupSplines(int num_of_functions, RadialFunctions func, - DOUBLE_TYPE *values, - DOUBLE_TYPE *dvalues, DOUBLE_TYPE deltaSplineBins, DOUBLE_TYPE cutoff); - - /** - * Populate `values` and `derivatives` arrays with a spline-interpolation for - * all functions - * - * @param r - * - * @return: populate 'values' and 'derivatives' - */ - void calcSplines(DOUBLE_TYPE r, bool calc_second_derivatives = false); - - /** - * Populate `values` and `derivatives` arrays with a spline-interpolation for - * all functions - * - * @param r - * - * @return: populate 'values' and 'derivatives' - */ - void calcSplines(DOUBLE_TYPE r, SHORT_INT_TYPE func_ind); -}; - -/** - * Interface class for radial basis functions with rank=1 (g_k), R_nl (rank>1) and hard-core repulsion radial functions - */ -class AbstractRadialBasis { -public: - SPECIES_TYPE nelements = 0; ///< number of elements - Array2D cut = Array2D("cut"); ///< cutoffs, shape: [nelements][nelements] - Array2D dcut = Array2D("dcut"); ///< decay of cutoff, shape: [nelements][nelements] - DOUBLE_TYPE cutoff = 0; ///< cutoff - -// int ntot = 10000; ///< Number of bins for look-up tables. - DOUBLE_TYPE deltaSplineBins; - LS_TYPE lmax = 0; ///< maximum value of `l` - NS_TYPE nradial = 0; ///< maximum number `n` of radial functions \f$ R_{nl}(r) \f$ - NS_TYPE nradbase = 0; ///< number of radial basis functions \f$ g_k(r) \f$ - - // Arrays for look-up tables. - Array2D splines_gk; ///< array of spline interpolator to store g_k, shape: [nelements][nelements] - Array2D splines_rnl; ///< array of spline interpolator to store R_nl, shape: [nelements][nelements] - Array2D splines_hc; ///< array of spline interpolator to store R_nl shape: [nelements][nelements] - //-------------------------------------------------------------------------- - - string radbasename = "ChebExpCos"; ///< type of radial basis functions \f$ g_{k}(r) \f$ (default="ChebExpCos") - - /** - Arrays to store radial functions. - */ - Array1D gr = Array1D("gr"); ///< g_k(r) functions, shape: [nradbase] - Array1D dgr = Array1D("dgr"); ///< derivatives of g_k(r) functions, shape: [nradbase] - Array1D d2gr = Array1D("d2gr"); ///< derivatives of g_k(r) functions, shape: [nradbase] - - Array2D fr = Array2D("fr"); ///< R_nl(r) functions, shape: [nradial][lmax+1] - Array2D dfr = Array2D( - "dfr"); ///< derivatives of R_nl(r) functions, shape: [nradial][lmax+1] - Array2D d2fr = Array2D( - "d2fr"); ///< derivatives of R_nl(r) functions, shape: [nradial][lmax+1] - - - - DOUBLE_TYPE cr; ///< hard-core repulsion - DOUBLE_TYPE dcr; ///< derivative of hard-core repulsion - DOUBLE_TYPE d2cr; ///< derivative of hard-core repulsion - - Array5D crad = Array5D( - "crad"); ///< expansion coefficients of radial functions into radial basis function, see Eq. (27) of PRB, shape: [nelements][nelements][lmax + 1][nradial][nradbase] - Array2D lambda = Array2D( - "lambda"); ///< distance scaling parameter Eq.(24) of PRB, shape: [nelements][nelements] - - Array2D prehc = Array2D( - "prehc"); ///< hard-core repulsion coefficients (prefactor), shape: [nelements][nelements] - Array2D lambdahc = Array2D( - "lambdahc");; ///< hard-core repulsion coefficients (lambdahc), shape: [nelements][nelements] - - virtual void - evaluate(DOUBLE_TYPE r, NS_TYPE nradbase_c, NS_TYPE nradial_c, SPECIES_TYPE mu_i, SPECIES_TYPE mu_j, - bool calc_second_derivatives = false) = 0; - - virtual void - init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, - string radbasename = "ChebExpCos") = 0; - - /** - * Function that sets up the look-up tables for spline-representation of radial functions. - */ - virtual void setuplookupRadspline() = 0; - - virtual AbstractRadialBasis *clone() const = 0; - - virtual ~AbstractRadialBasis() = default; -}; - - -/** -Class to store radial functions and their associated functions. \n -*/ -class ACERadialFunctions final : public AbstractRadialBasis { -public: - - //-------------------------------------------------------------------------- - - /** - Arrays to store Chebyshev polynomials. - */ - Array1D cheb = Array1D( - "cheb"); ///< Chebyshev polynomials of the first kind, shape: [nradbase+1] - Array1D dcheb = Array1D( - "dcheb"); ///< derivatives Chebyshev polynomials of the first kind, shape: [nradbase+1] - Array1D cheb2 = Array1D( - "cheb2"); ///< Chebyshev polynomials of the second kind, shape: [nradbase+1] - - //-------------------------------------------------------------------------- - - Array2D gr_vec; - Array2D dgr_vec; - Array2D d2gr_vec; - - Array3D fr_vec; - Array3D dfr_vec; - Array3D d2fr_vec; - //------------------------------------------------------------------------ - /** - * Default constructor - */ - ACERadialFunctions() = default; - - /** - * Parametrized constructor - * - * @param nradb number of radial basis function \f$ g_k(r) \f$ - nradbase - * @param lmax maximum orbital moment - lmax - * @param nradial maximum n-index of radial functions \f$ R_{nl}(r) \f$ - nradial - * @param ntot Number of bins for spline look-up tables. - * @param nelements numer of elements - * @param cutoff cutoff - * @param radbasename type of radial basis function \f$ g_k(r) \f$ (default: "ChebExpCos") - */ - ACERadialFunctions(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, - SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, string radbasename = "ChebExpCos"); - - /** - * Initialize arrays for given parameters - * - * @param nradb number of radial basis function \f$ g_k(r) \f$ - nradbase - * @param lmax maximum orbital moment - lmax - * @param nradial maximum n-index of radial functions \f$ R_{nl}(r) \f$ - nradial - * @param ntot Number of bins for spline look-up tables. - * @param nelements numer of elements - * @param cutoff cutoff - * @param radbasename type of radial basis function \f$ g_k(r) \f$ (default: "ChebExpCos") - */ - void init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, - string radbasename = "ChebExpCos") final; - - /** - * Destructor - */ - ~ACERadialFunctions() final = default; - - /** - * Function that computes Chebyshev polynomials of first and second kind - * to setup the radial functions and the derivatives - * - * @param n maximum polynom order - * @param x - * - * @returns fills cheb, dcheb and cheb2 arrays - */ - void calcCheb(NS_TYPE n, DOUBLE_TYPE x); - - /** - * Function that computes radial basis functions \$f g_k(r) \$f, see Eq.(21) of PRB paper - * @param lam \$f \lambda \$f parameter, see eq. (24) of PRB paper - * @param cut cutoff - * @param dcut cutoff decay - * @param r distance - * - * @return function fills gr and dgr arrays - */ - void radbase(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r); - - /** - * Function that computes radial core repulsion \$f f_{core} = pre \exp( - \lambda r^2 ) / r \$f, - * and its derivative, see Eq.(27) of implementation notes. - * - * @param r distance - * @param pre prefactor: read from input, depends on pair of atoms mu_i mu_j - * @param lambda exponent: read from input, depends on pair of atoms mu_i mu_j - * @param cutoff cutoff distance: read from input, depends on pair of atoms mu_i mu_j - * @param cr (out) hard core repulsion - * @param dcr (out) derivative of hard core repulsion - */ - static void radcore(DOUBLE_TYPE r, DOUBLE_TYPE pre, DOUBLE_TYPE lambda, DOUBLE_TYPE cutoff, DOUBLE_TYPE &cr, - DOUBLE_TYPE &dcr); - - /** - * Function that sets up the look-up tables for spline-representation of radial functions. - */ - void setuplookupRadspline() final; - - /** - * Function that computes radial functions \f$ R_{nl}(r)\f$ (see Eq. 27 from PRB paper) - * and its derivatives for all range of n,l, - * ONLY if radial basis functions (gr and dgr) are computed. - * @param elei first species type - * @param elej second species type - * - * @return fills in fr, dfr arrays - */ - void radfunc(SPECIES_TYPE elei, SPECIES_TYPE elej); - - /** - * Compute all radial functions R_nl(r), radial basis functions g_k(r) and hard-core repulsion function hc(r) - * - * @param r distance - * @param nradbase_c - * @param nradial_c - * @param mu_i - * @param mu_j - * - * @return update gr(k), dgr(k), fr(n,l), dfr(n,l), cr, dcr - */ - void evaluate(DOUBLE_TYPE r, NS_TYPE nradbase_c, NS_TYPE nradial_c, SPECIES_TYPE mu_i, SPECIES_TYPE mu_j, - bool calc_second_derivatives = false) final; - - - void - evaluate_range(vector r_vec, NS_TYPE nradbase_c, NS_TYPE nradial_c, SPECIES_TYPE mu_i, - SPECIES_TYPE mu_j); - - void chebExpCos(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r); - - void chebPow(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r); - - void chebLinear(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r); - - /** - * Setup all radial functions for element pair mu_i-mu_j and distance r - * @param mu_i first specie type - * @param mu_j second specie type - * @param r distance - * @return update fr(nr, l), dfr(nr, l) - */ - void all_radfunc(SPECIES_TYPE mu_i, SPECIES_TYPE mu_j, DOUBLE_TYPE r); - - ACERadialFunctions *clone() const override { - return new ACERadialFunctions(*this); - }; -}; - -#endif \ No newline at end of file diff --git a/lib/pace/ace_recursive.cpp b/lib/pace/ace_recursive.cpp deleted file mode 100644 index c895418943..0000000000 --- a/lib/pace/ace_recursive.cpp +++ /dev/null @@ -1,1340 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Christoph Ortner on 20.12.2020 - -#include "ace_recursive.h" - -#include "ace_abstract_basis.h" -#include "ace_types.h" - -/* ------------------------------------------------------------ - * ACEDAG Implementation - * (just the DAG construction, not the traversal) - * ------------------------------------------------------------ */ - -/* Notes on different Tags: - * rec1 - first basic implementation - * rec2 - avoid index arithmetic, contiguous layout, - * canonical evaluator in ACE.jl format - * rec3 - split nodes into interior and leaf nodes - */ - -void ACEDAG::init(Array2D xAspec, - Array2D AAspec, - Array1D orders, - Array2D jl_coeffs, - int _heuristic ) { - - // remember which heuristic we want to use! - heuristic = _heuristic; - - /* stage one of the graph is just extracting the A basis from - * the tensor product format into the linear list; all information - * for that is already stored in Aspec, and the only thing to do here is - * to construct zero-coefficients. Still we have to copy Aspec, since - * the one we have here will (may?) be deleted. */ - int num1 = xAspec.get_dim(0); - Aspec = xAspec; //YL: just copying the multiarray: Aspec = xAspec; - - /* fill the one-particle basis into the DAGmap - * DAGmap[ (i1,...,in) ] = iAA index where the (i1,...,in) basis functions - * lives. - */ - TDAGMAP DAGmap; - for (int iA = 0; iA < num1; iA++) { - vector a(1); - a[0] = iA; - DAGmap[a] = iA; - } - - /* For stage 2 we now want to construct the actual recursion; the - recursion info will be stored in DAGspec, while the - coefficients go into DAGcoeffs. These arrays are initialized to - length `num2`, but they will have to grow as we add additional - artificial nodes into the graph. - - initially we treat all nodes as having children, but then in a - second stage below we reorganize. */ - int num2 = AAspec.get_dim(0); - int ndensity = jl_coeffs.get_dim(1); - nodes_pre.resize(2*num2, 2); - coeffs_pre.resize(2*num2, ndensity); - - /* the first basis function we construct will get index num1, - * since there are already num1 one-particle basis functions - * to collect during stage 1 */ - dag_idx = num1; - /* main loop over AA basis set to transform into DAG */ - for (int iAA = 0; iAA < num2; iAA++) { - // create a vector representing the current basis function - int ord = orders(iAA); - vector aa(ord); - for (int t = 0; t < ord; t++) aa[t] = AAspec(iAA, t); - vector c(ndensity); - for (int p = 0; p < ndensity; p++) c[p] = jl_coeffs(iAA, p); - insert_node(DAGmap, aa, c); - } - - /* convert to 3-stage format through reordering - * interior nodes first, then leaf nodes */ - - // allocate storage - num_nodes = dag_idx; // store total size of dag - // num_nodes - num1 = number of many-body nodes. - nodes.resize(num_nodes - num1, 2); - coeffs.resize(num_nodes - num1, ndensity); - - // find out which nodes have children - haschild.resize(num_nodes - num1); - haschild.fill(false); - for (int iAA = 0; iAA < num_nodes - num1; iAA++) { - if (nodes_pre(iAA, 0) >= num1) - haschild(nodes_pre(iAA, 0)-num1) = true; - if (nodes_pre(iAA, 1) >= num1) - haschild(nodes_pre(iAA, 1)-num1) = true; - } - - // to reorder the graph we need a fresh map from preordered indices to - // postordered indices; for the 1-particle basis the order remains the same. - // TODO: doesn't need to be a map, could be a vector. - map neworder; - for (int iA = 0; iA < num1; iA++) - neworder[iA] = iA; - - // insert all interior nodes - num2_int = 0; - num2_leaf = 0; - dag_idx = num1; - int i1, i2, i1pre, i2pre; - for (int iAA = 0; iAA < num_nodes - num1; iAA++) { - if (haschild(iAA)) { - num2_int += 1; - // indices into AAbuf before reordering - i1pre = nodes_pre(iAA, 0); - i2pre = nodes_pre(iAA, 1); - // indices into AAbuf after reordering - i1 = neworder[i1pre]; - i2 = neworder[i2pre]; - // insert the current node : iAA is old order, dag_idx is new order - neworder[num1+iAA] = dag_idx; - nodes(dag_idx-num1, 0) = i1; - nodes(dag_idx-num1, 1) = i2; - for (int t = 0; t < ndensity; t++) - coeffs(dag_idx-num1, t) = coeffs_pre(iAA, t); - dag_idx++; - } - } - - // insert all leaf nodes - for (int iAA = 0; iAA < num_nodes - num1; iAA++) { - if (!haschild(iAA)) { - num2_leaf += 1; - // indices into AAbuf before reordering - i1pre = nodes_pre(iAA, 0); - i2pre = nodes_pre(iAA, 1); - // insert the current node : no need to remember the new order now - nodes(dag_idx-num1, 0) = neworder[i1pre]; - nodes(dag_idx-num1, 1) = neworder[i2pre]; - for (int t = 0; t < ndensity; t++) - coeffs(dag_idx-num1, t) = coeffs_pre(iAA, t); - dag_idx++; - } - } -#ifdef DEBUG - cout << "num2_int = " << num2_int << "; num2_leaf = " << num2_leaf << "\n"; -#endif - // free up memory that is no longer needed - nodes_pre.resize(0, 0); - coeffs_pre.resize(0, 0); - haschild.resize(0); - - /* finalize dag: allocate buffer storage */ - AAbuf.resize(num1 + num2_int); - w.resize(num_nodes); - // TODO: technically only need num1 + num2_int for w, this can save one - // memory access later, probably not worth the crazy code duplication. -} - -void ACEDAG::insert_node(TDAGMAP &DAGmap, vector a, vector c) { - /* start with a list of all possible partitions into 2 groups - * and check whether any of these nodes are already in the dag */ - auto partitions = find_2partitions(a); - int ndensity = c.size(); - int num1 = get_num1(); - - // TODO: first try to find partitions into nodes that are already parents - // that way we will get more leaf nodes! - for (TPARTITION const& p : partitions) { - /* this is the good case; the parent nodes are both already in the - * graph; add the new node and return. This is also the only place in the - * code where an actual insert happens. */ - if (DAGmap.count(p.first) && DAGmap.count(p.second)) { - if (nodes_pre.get_dim(0) < dag_idx + 1) { //check if array is sufficiently large - int newsize = (dag_idx * 3) / 2; - nodes_pre.resize(newsize, 2); // grow arrays if necessary - coeffs_pre.resize(newsize, ndensity); - } - int i1 = DAGmap[p.first]; - int i2 = DAGmap[p.second]; - nodes_pre(dag_idx - num1, 0) = i1; - nodes_pre(dag_idx - num1, 1) = i2; - DAGmap[a] = dag_idx; - for (int p = 0; p < ndensity; p++) - coeffs_pre(dag_idx - num1, p) = c[p]; - dag_idx += 1; - return; - } - } - - /* if we are here, then this means, the new node cannot yet be inserted. - * We first need to insert some intermediate auxiliary nodes. For this - * we use a simple heuristic: - * try to find a partition where one of the two nodes are already - * in the graph, if there are several, then we remember the longest - * (this is a very greedy heuristic!!) - * .... (continue below) .... - */ - TPARTITION longest; - int longest_length = 0; - for (auto const& p : partitions) { - int len = 0; - if (DAGmap.count(p.first)) { - len = p.first.size(); - } else if (DAGmap.count(p.second)) { - len = p.second.size(); - } - if ((len > 0) && (len > longest_length)) { - longest_length = len; - longest = p; - } - } - - /* sanity check */ - if (longest_length == 0) { - std::stringstream error_message; - error_message << "WARNING : something has gone horribly wrong! `longest_length == 0`! \n"; - error_message << "a = ["; - for (int t = 0; t < a.size(); t++) - error_message << a[t] << ", "; - error_message << "]\n"; - throw std::logic_error(error_message.str()); -// return; - } - - /* If there is a partition with one component already in the graph, - * then we only need to add in the other component. Note that there will - * always be at least one such partition, namely all those containing - * a one-element node e.g. (1,2,3,4) -> (1,) (2,3,4) then (1,) is - * a one-particle basis function and hence always in the graph. - * If heuristic == 0, then we just take one of those partitionas and move on. - * - * We also accept the found partition if longest_length > 1. - * And we also accept it if we have a 2- or 3-correlation. - */ - - if ( (heuristic == 0) - || (longest_length > 1) - || (a.size() <= 3)) { - /* insert the other node that isn't in the DAG yet - * this is an artificial node so it gets zero-coefficients - * This step is recursive, so more than one node might be inserted here */ - vector cz(ndensity); - for (int i = 0; i < ndensity; i++) cz[i] = 0.0; - TPARTITION p = longest; - if (DAGmap.count(p.first)) - insert_node(DAGmap, p.second, cz); - else - insert_node(DAGmap, p.first, cz); - } - - /* Second heuristic : heuristic == 1 - * Focus on inserting artificial 2-correlations - */ - else if (heuristic == 1) { - // and we also know that longest_length == 1 and nu = a.size >= 4. - int nu = a.size(); - // generate an artificial partition - vector a1(2); - for (int i = 0; i < 2; i++) a1[i] = a[i]; - vector a2(nu - 2); - for (int i = 0; i < nu - 2; i++) a2[i] = a[2 + i]; - vector cz(ndensity); - for (int i = 0; i < cz.size(); i++) cz[i] = 0.0; - // and insert both (we know neither are in the DAG yet) - insert_node(DAGmap, a1, cz); - insert_node(DAGmap, a2, cz); - } else { - cout << "WARNING : something has gone horribly wrong! \n"; - // TODO: Throw and error here?!? - return; - } - - - - /* now we should be ready to insert the entire tuple `a` since there is now - * an eligible parent pair. Here we recompute the partition of `a`, but - * that's a small price to pay for a clearer code. Maybe this can be - * optimized a bit by wrapping it all into a while loop or having a second - * version of `insert_node` ... */ - insert_node(DAGmap, a, c); -} - -TPARTITIONS ACEDAG::find_2partitions(vector v) { - int N = v.size(); - int zo; - TPARTITIONS partitions; - TPARTITION part; - /* This is a fun little hack to extract all subsets of the indices 1:N - * the number i will have binary representation with each digit indicating - * whether or not that index belongs to the selected subset */ - for (int i = 1; i < (1< v1(N1); - vector v2(N2); - int i1 =0, i2 = 0; - p = 1; - for (int n = 0; n < N; n++) { - zo = ((i / p) % 2); - p *= 2; - if (zo == 1) { - v1[i1] = v[n]; - i1 += 1; - } else { - v2[i2] = v[n]; - i2 += 1; - } - } - part = make_pair(v1, v2); - partitions.push_back(part); - } - return partitions; -} - -void ACEDAG::print() { - cout << "DAG Specification: \n" ; - cout << " n1 : " << get_num1() << "\n"; - cout << " n2 : " << get_num2() << "\n"; - cout << " num_nodes : " << num_nodes << "\n"; - cout << "--------------------\n"; - cout << "A-spec: \n"; - for (int iA = 0; iA < get_num1(); iA++) { - cout << iA << " : " << Aspec(iA, 0) << - Aspec(iA, 1) << Aspec(iA, 2) << Aspec(iA, 3) << "\n"; - } - - cout << "-----------\n"; - cout << "AA-tree\n"; - - for (int iAA = 0; iAA < get_num2(); iAA++) { - cout << iAA + get_num1() << " : " << - nodes(iAA, 0) << ", " << nodes(iAA, 1) << "\n"; - } -} - - -/* ------------------------------------------------------------ - * ACERecursiveEvaluator - * ------------------------------------------------------------ */ - - -void ACERecursiveEvaluator::set_basis(ACECTildeBasisSet &bas, int heuristic) { - basis_set = &bas; - init(basis_set, heuristic); -} - -void ACERecursiveEvaluator::init(ACECTildeBasisSet *basis_set, int heuristic) { - - ACEEvaluator::init(basis_set); - - - weights.init(basis_set->nelements, basis_set->nradmax + 1, basis_set->lmax + 1, - "weights"); - - weights_rank1.init(basis_set->nelements, basis_set->nradbase, "weights_rank1"); - - - DG_cache.init(1, basis_set->nradbase, "DG_cache"); - DG_cache.fill(0); - - R_cache.init(1, basis_set->nradmax, basis_set->lmax + 1, "R_cache"); - R_cache.fill(0); - - DR_cache.init(1, basis_set->nradmax, basis_set->lmax + 1, "DR_cache"); - DR_cache.fill(0); - - Y_cache.init(1, basis_set->lmax + 1, "Y_cache"); - Y_cache.fill({0, 0}); - - DY_cache.init(1, basis_set->lmax + 1, "dY_dense_cache"); - DY_cache.fill({0.}); - - //hard-core repulsion - DCR_cache.init(1, "DCR_cache"); - DCR_cache.fill(0); - dB_flatten.init(basis_set->max_dB_array_size, "dB_flatten"); - - /* convert to ACE.jl format to prepare for construction of DAG - * This will fill the arrays jl_Aspec, jl_AAspec, jl_orders - */ - acejlformat(); - - // test_acejlformat(); - - // now pass this info into the DAG - dag.init(jl_Aspec, jl_AAspec, jl_orders, jl_coeffs, heuristic); - - // finally empty the temporary arrays to clear up the memory... - // TODO -} - - -void ACERecursiveEvaluator::acejlformat() { - - int func_ms_ind = 0; - int func_ms_t_ind = 0;// index for dB - int j, jj, func_ind, ms_ind; - - SPECIES_TYPE mu_i = 0;//TODO: multispecies - const SHORT_INT_TYPE total_basis_size = basis_set->total_basis_size[mu_i]; - ACECTildeBasisFunction *basis = basis_set->basis[mu_i]; - - int AAidx = 0; - RANK_TYPE order, t; - SPECIES_TYPE *mus; - NS_TYPE *ns; - LS_TYPE *ls; - MS_TYPE *ms; - - /* transform basis into new format: - [A1 ... A_num1] - [(i1,i2)(i1,i2)(...)(i1,i2,i3)(...)] - where each ia represents an A_{ia} - */ - - /* compute max values for mu, n, l, m */ - SPECIES_TYPE maxmu = 0; //TODO: multispecies - NS_TYPE maxn = basis_set->nradmax; - LS_TYPE maxl = basis_set->lmax; - RANK_TYPE maxorder = basis_set->rankmax; - const DENSITY_TYPE ndensity = basis_set->ndensitymax; - - int num1 = 0; - - - /* create a 4D lookup table for the 1-p basis - * TODO: replace with a map?? - */ - Array4D A_lookup(int(maxmu+1), int(maxn), int(maxl+1), int(2*maxl+1)); - for (int mu = 0; mu < maxmu+1; mu++) - for (int n = 0; n < maxn; n++) - for (int l = 0; l < maxl+1; l++) - for (int m = 0; m < 2*maxl+1; m++) - A_lookup(mu, n, l, m) = -1; - int A_idx = 0; // linear index of A basis function (1-particle) - for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { - ACECTildeBasisFunction *func = &basis[func_ind]; -// func->print(); - order = func->rank; mus = func->mus; ns = func->ns; ls = func->ls; - for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * order]; - for (t = 0; t < order; t++) { - int iA = A_lookup(mus[t], ns[t]-1, ls[t], ms[t]+ls[t]); - if (iA == -1) { - A_lookup(mus[t], ns[t] - 1, ls[t], ms[t] + ls[t]) = A_idx; - A_idx += 1; - } - } - } - } - - /* create the reverse list: linear indixes to mu,l,m,n - this keeps only the basis functions we really need */ - num1 = A_idx; - Array2D & Aspec = jl_Aspec; - Aspec.resize(num1, 4); - // Array2D Aspec(num1, 4); - for (int mu = 0; mu <= maxmu; mu++) - for (int n = 1; n <= maxn; n++) - for (int l = 0; l <= maxl; l++) - for (int m = -l; m <= l; m++) { - int iA = A_lookup(mu, n-1, l, l+m); - if (iA != -1) { - Aspec(iA, 0) = mu; - Aspec(iA, 1) = n; - Aspec(iA, 2) = l; - Aspec(iA, 3) = m; - } - } - - /* ============ HALF-BASIS TRICK START ============ */ - for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { - ACECTildeBasisFunction *func = &basis[func_ind]; - order = func->rank; mus = func->mus; ns = func->ns; ls = func->ls; - if (!( (mus[0] <= maxmu) && (ns[0] <= maxn) && (ls[0] <= maxl) )) - continue; - - for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * order]; - - // find first positive and negative index - int pos_idx = order + 1; - int neg_idx = order + 1; - for (t = order-1; t >= 0; t--) - if (ms[t] > 0) pos_idx = t; - else if (ms[t] < 0) neg_idx = t; - - // if neg_idx < pos_idx then this means that ms is non-zero - // and that the first non-zero index is negative, hence this is - // a negative-sign tuple which we want to combine into - // its opposite. - if (neg_idx < pos_idx) { - // find the opposite tuple - int ms_ind2 = 0; - MS_TYPE *ms2; - bool found_opposite = false; - for (ms_ind2 = 0; ms_ind2 < func->num_ms_combs; ++ms_ind2) { - ms2 = &func->ms_combs[ms_ind2 * order]; - bool isopposite = true; - for (t = 0; t < order; t++) - if (ms[t] != -ms2[t]) { - isopposite = false; - break; - } - if (isopposite) { - found_opposite = true; - break; - } - } - - if (ms_ind == ms_ind2) { - cout << "WARNING - ms_ind == ms_ind2 \n"; - } - - // now we need to overwrite the coefficients - if (found_opposite) { - int sig = 1; - for (t = 0; t < order; t++) - if (ms[t] < 0) - sig *= -1; - for (int p = 0; p < ndensity; ++p) { - func->ctildes[ms_ind2 * ndensity + p] += - func->ctildes[ms_ind * ndensity + p]; - func->ctildes[ms_ind * ndensity + p] = 0.0; - } - } - } - } - } - - // /* ============ HALF-BASIS TRICK END ============ */ - - - /* count number of basis functions, keep only non-zero!! */ - int num2 = 0; - for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { - ACECTildeBasisFunction *func = &basis[func_ind]; - for (ms_ind = 0; ms_ind < (&basis[func_ind])->num_ms_combs; ++ms_ind, ++func_ms_ind) { - // check that the coefficients are actually non-zero - bool isnonzero = false; - for (DENSITY_TYPE p = 0; p < ndensity; ++p) - if (func->ctildes[ms_ind * ndensity + p] != 0.0) - isnonzero = true; - if (isnonzero) - num2++; - } - } - - - /* Now create the AA basis links into the A basis */ - num1 = A_idx; // total number of A-basis functions that we keep - // Array1D AAorders(num2); - Array1D & AAorders = jl_orders; - AAorders.resize(num2); - // Array2D AAspec(num2, maxorder); // specs of AA basis functions - Array2D & AAspec = jl_AAspec; - AAspec.resize(num2, maxorder); - jl_coeffs.resize(num2, ndensity); - AAidx = 0; // linear index into AA basis function - int len_flat = 0; - for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { - ACECTildeBasisFunction *func = &basis[func_ind]; - order = func->rank; mus = func->mus; ns = func->ns; ls = func->ls; - if (!((mus[0] <= maxmu) && (ns[0] <= maxn) && (ls[0] <= maxl))) //fool-proofing of functions - continue; - - for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * order]; - - // check that the coefficients are actually non-zero - bool iszero = true; - for (DENSITY_TYPE p = 0; p < ndensity; ++p) - if (func->ctildes[ms_ind * ndensity + p] != 0.0) - iszero = false; - if (iszero) continue; - - AAorders(AAidx) = order; - for (t = 0; t < order; t++) { - int Ait = A_lookup(int(mus[t]), int(ns[t]-1), int(ls[t]), int(ms[t])+int(ls[t])); - AAspec(AAidx, t) = Ait; - len_flat += 1; - } - for (t = order; t < maxorder; t++) AAspec(AAidx, t) = -1; - /* copy over the coefficients */ - for (DENSITY_TYPE p = 0; p < ndensity; ++p) - jl_coeffs(AAidx, p) = func->ctildes[ms_ind * ndensity + p]; - AAidx += 1; - } - } - - // flatten the AAspec array - jl_AAspec_flat.resize(len_flat); - int idx_spec = 0; - for (int AAidx = 0; AAidx < jl_AAspec.get_dim(0); AAidx++) - for (int p = 0; p < jl_orders(AAidx); p++, idx_spec++) - jl_AAspec_flat(idx_spec) = jl_AAspec(AAidx, p); - -} - -void ACERecursiveEvaluator::test_acejlformat() { - - Array2D AAspec = jl_AAspec; - Array2D Aspec = jl_Aspec; - Array1D AAorders = jl_orders; - cout << "num2 = " << AAorders.get_dim(0) << "\n"; - int func_ms_ind = 0; - int func_ms_t_ind = 0;// index for dB - int j, jj, func_ind, ms_ind; - - SPECIES_TYPE mu_i = 0; - const SHORT_INT_TYPE total_basis_size = basis_set->total_basis_size[mu_i]; - ACECTildeBasisFunction *basis = basis_set->basis[mu_i]; - - RANK_TYPE order, t; - SPECIES_TYPE *mus; - NS_TYPE *ns; - LS_TYPE *ls; - MS_TYPE *ms; - - /* ==== test by printing the basis spec ====*/ - // TODO: convert this into an automatic consistency test - int iAA = 0; - for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { - ACECTildeBasisFunction *func = &basis[func_ind]; - order = func->rank; mus = func->mus; ns = func->ns; ls = func->ls; - // func->print(); - //loop over {ms} combinations in sum - for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * order]; - - - cout << iAA << " : |"; - for (t = 0; t < order; t++) - cout << mus[t] << ";" << ns[t] << "," << ls[t] << "," << ms[t] << "|"; - cout << "\n"; - - cout << " ["; - for (t = 0; t < AAorders(iAA); t++) - cout << AAspec(iAA, int(t)) << ","; - cout << "]\n"; - cout << " |"; - for (t = 0; t < AAorders(iAA); t++) { - int iA = AAspec(iAA, t); - // cout << iA << ","; - cout << Aspec(iA, 0) << ";" - << Aspec(iA, 1) << "," - << Aspec(iA, 2) << "," - << Aspec(iA, 3) << "|"; - } - cout << "\n"; - iAA += 1; - } - } - /* ==== END TEST ==== */ - - -} - - - - -void ACERecursiveEvaluator::resize_neighbours_cache(int max_jnum) { - if(basis_set== nullptr) { - throw std::invalid_argument("ACERecursiveEvaluator: basis set is not assigned"); - } - if (R_cache.get_dim(0) < max_jnum) { - - //TODO: implement grow - R_cache.resize(max_jnum, basis_set->nradmax, basis_set->lmax + 1); - R_cache.fill(0); - - DR_cache.resize(max_jnum, basis_set->nradmax, basis_set->lmax + 1); - DR_cache.fill(0); - - DG_cache.resize(max_jnum, basis_set->nradbase); - DG_cache.fill(0); - - Y_cache.resize(max_jnum, basis_set->lmax + 1); - Y_cache.fill({0, 0}); - - DY_cache.resize(max_jnum, basis_set->lmax + 1); - DY_cache.fill({0}); - - //hard-core repulsion - DCR_cache.init(max_jnum, "DCR_cache"); - DCR_cache.fill(0); - } -} - - - -// double** r - atomic coordinates of atom I -// int* types - atomic types if atom I -// int **firstneigh - ptr to 1st J int value of each I atom. Usage: jlist = firstneigh[i]; -// Usage: j = jlist_of_i[jj]; -// jnum - number of J neighbors for each I atom. jnum = numneigh[i]; - -void -ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *type, const int jnum, const int *jlist) { - if(basis_set== nullptr) { - throw std::invalid_argument("ACERecursiveEvaluator: basis set is not assigned"); - } - per_atom_calc_timer.start(); -#ifdef PRINT_MAIN_STEPS - printf("\n ATOM: ind = %d r_norm=(%f, %f, %f)\n",i, x[i][0], x[i][1], x[i][2]); -#endif - DOUBLE_TYPE evdwl = 0, evdwl_cut = 0, rho_core = 0; - DOUBLE_TYPE r_norm; - DOUBLE_TYPE xn, yn, zn, r_xyz; - DOUBLE_TYPE R, GR, DGR, R_over_r, DR, DCR; - DOUBLE_TYPE *r_hat; - - SPECIES_TYPE mu_j; - RANK_TYPE r, rank, t; - NS_TYPE n; - LS_TYPE l; - MS_TYPE m, m_t; - - SPECIES_TYPE *mus; - NS_TYPE *ns; - LS_TYPE *ls; - MS_TYPE *ms; - - int j, jj, func_ind, ms_ind; - SHORT_INT_TYPE factor; - - ACEComplex Y{0}, Y_DR{0.}; - ACEComplex B{0.}; - ACEComplex dB{0}; - ACEComplex A_cache[basis_set->rankmax]; - - ACEComplex dA[basis_set->rankmax]; - int spec[basis_set->rankmax]; - - dB_flatten.fill({0.}); - - ACEDYcomponent grad_phi_nlm{0}, DY{0.}; - - //size is +1 of max to avoid out-of-boundary array access in double-triangular scheme - ACEComplex A_forward_prod[basis_set->rankmax + 1]; - ACEComplex A_backward_prod[basis_set->rankmax + 1]; - - DOUBLE_TYPE inv_r_norm; - DOUBLE_TYPE r_norms[jnum]; - DOUBLE_TYPE inv_r_norms[jnum]; - DOUBLE_TYPE rhats[jnum][3];//normalized vector - SPECIES_TYPE elements[jnum]; - const DOUBLE_TYPE xtmp = x[i][0]; - const DOUBLE_TYPE ytmp = x[i][1]; - const DOUBLE_TYPE ztmp = x[i][2]; - DOUBLE_TYPE f_ji[3]; - - bool is_element_mapping = element_type_mapping.get_size() > 0; - SPECIES_TYPE mu_i; - if (is_element_mapping) - mu_i = element_type_mapping(type[i]); - else - mu_i = type[i]; - - const SHORT_INT_TYPE total_basis_size_rank1 = basis_set->total_basis_size_rank1[mu_i]; - const SHORT_INT_TYPE total_basis_size = basis_set->total_basis_size[mu_i]; - - ACECTildeBasisFunction *basis_rank1 = basis_set->basis_rank1[mu_i]; - ACECTildeBasisFunction *basis = basis_set->basis[mu_i]; - - DOUBLE_TYPE rho_cut, drho_cut, fcut, dfcut; - DOUBLE_TYPE dF_drho_core; - - //TODO: lmax -> lmaxi (get per-species type) - const LS_TYPE lmaxi = basis_set->lmax; - - //TODO: nradmax -> nradiali (get per-species type) - const NS_TYPE nradiali = basis_set->nradmax; - - //TODO: nradbase -> nradbasei (get per-species type) - const NS_TYPE nradbasei = basis_set->nradbase; - - //TODO: get per-species type number of densities - const DENSITY_TYPE ndensity= basis_set->ndensitymax; - - neighbours_forces.resize(jnum, 3); - neighbours_forces.fill(0); - - //TODO: shift nullifications to place where arrays are used - weights.fill({0}); - weights_rank1.fill(0); - A.fill({0}); - A_rank1.fill(0); - rhos.fill(0); - dF_drho.fill(0); - -#ifdef EXTRA_C_PROJECTIONS - basis_projections_rank1.init(total_basis_size_rank1, ndensity, "c_projections_rank1"); - basis_projections.init(total_basis_size, ndensity, "c_projections"); -#endif - - //proxy references to spherical harmonics and radial functions arrays - const Array2DLM &ylm = basis_set->spherical_harmonics.ylm; - const Array2DLM &dylm = basis_set->spherical_harmonics.dylm; - - const Array2D &fr = basis_set->radial_functions->fr; - const Array2D &dfr = basis_set->radial_functions->dfr; - - const Array1D &gr = basis_set->radial_functions->gr; - const Array1D &dgr = basis_set->radial_functions->dgr; - - loop_over_neighbour_timer.start(); - - int jj_actual = 0; - SPECIES_TYPE type_j = 0; - int neighbour_index_mapping[jnum]; // jj_actual -> jj - //loop over neighbours, compute distance, consider only atoms within with rradial_functions->cut(mu_i, mu_j); - r_xyz = sqrt(xn * xn + yn * yn + zn * zn); - - if (r_xyz >= current_cutoff) - continue; - - inv_r_norm = 1 / r_xyz; - - r_norms[jj_actual] = r_xyz; - inv_r_norms[jj_actual] = inv_r_norm; - rhats[jj_actual][0] = xn * inv_r_norm; - rhats[jj_actual][1] = yn * inv_r_norm; - rhats[jj_actual][2] = zn * inv_r_norm; - elements[jj_actual] = mu_j; - neighbour_index_mapping[jj_actual] = jj; - jj_actual++; - } - - int jnum_actual = jj_actual; - - //ALGORITHM 1: Atomic base A - for (jj = 0; jj < jnum_actual; ++jj) { - r_norm = r_norms[jj]; - mu_j = elements[jj]; - r_hat = rhats[jj]; - - //proxies - Array2DLM &Y_jj = Y_cache(jj); - Array2DLM &DY_jj = DY_cache(jj); - - - basis_set->radial_functions->evaluate(r_norm, basis_set->nradbase, nradiali, mu_i, mu_j); - basis_set->spherical_harmonics.compute_ylm(r_hat[0], r_hat[1], r_hat[2], lmaxi); - //loop for computing A's - //rank = 1 - for (n = 0; n < basis_set->nradbase; n++) { - GR = gr(n); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("-neigh atom %d\n", jj); - printf("gr(n=%d)(r=%f) = %f\n", n, r_norm, gr(n)); - printf("dgr(n=%d)(r=%f) = %f\n", n, r_norm, dgr(n)); -#endif - DG_cache(jj, n) = dgr(n); - A_rank1(mu_j, n) += GR * Y00; - } - //loop for computing A's - // for rank > 1 - for (n = 0; n < nradiali; n++) { - auto &A_lm = A(mu_j, n); - for (l = 0; l <= lmaxi; l++) { - R = fr(n, l); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("R(nl=%d,%d)(r=%f)=%f\n", n + 1, l, r_norm, R); -#endif - - DR_cache(jj, n, l) = dfr(n, l); - R_cache(jj, n, l) = R; - - for (m = 0; m <= l; m++) { - Y = ylm(l, m); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("Y(lm=%d,%d)=(%f, %f)\n", l, m, Y.real, Y.img); -#endif - A_lm(l, m) += R * Y; //accumulation sum over neighbours - Y_jj(l, m) = Y; - DY_jj(l, m) = dylm(l, m); - } - } - } - - //hard-core repulsion - rho_core += basis_set->radial_functions->cr; - DCR_cache(jj) = basis_set->radial_functions->dcr; - - } //end loop over neighbours - - //complex conjugate A's (for NEGATIVE (-m) terms) - // for rank > 1 - for (mu_j = 0; mu_j < basis_set->nelements; mu_j++) { - for (n = 0; n < nradiali; n++) { - auto &A_lm = A(mu_j, n); - for (l = 0; l <= lmaxi; l++) { - //fill in -m part in the outer loop using the same m <-> -m symmetry as for Ylm - for (m = 1; m <= l; m++) { - factor = m % 2 == 0 ? 1 : -1; - A_lm(l, -m) = A_lm(l, m).conjugated() * factor; - } - } - } - } //now A's are constructed - loop_over_neighbour_timer.stop(); - - // ==================== ENERGY ==================== - - energy_calc_timer.start(); -#ifdef EXTRA_C_PROJECTIONS - basis_projections_rank1.fill(0); - basis_projections.fill(0); -#endif - - //ALGORITHM 2: Basis functions B with iterative product and density rho(p) calculation - //rank=1 - for (int func_rank1_ind = 0; func_rank1_ind < total_basis_size_rank1; ++func_rank1_ind) { - ACECTildeBasisFunction *func = &basis_rank1[func_rank1_ind]; -// ndensity = func->ndensity; -#ifdef PRINT_LOOPS_INDICES - printf("Num density = %d r = 0\n",(int) ndensity ); - print_C_tilde_B_basis_function(*func); -#endif - double A_cur = A_rank1(func->mus[0], func->ns[0] - 1); -#ifdef DEBUG_ENERGY_CALCULATIONS - printf("A_r=1(x=%d, n=%d)=(%f)\n", func->mus[0], func->ns[0], A_cur); - printf(" coeff[0] = %f\n", func->ctildes[0]); -#endif - for (DENSITY_TYPE p = 0; p < ndensity; ++p) { - //for rank=1 (r=0) only 1 ms-combination exists (ms_ind=0), so index of func.ctildes is 0..ndensity-1 - rhos(p) += func->ctildes[p] * A_cur; -#ifdef EXTRA_C_PROJECTIONS - //aggregate C-projections separately - basis_projections_rank1(func_rank1_ind, p)+= func->ctildes[p] * A_cur; -#endif - } - } // end loop for rank=1 - - // ================ START RECURSIVE EVALUATOR ==================== - // (rank > 1 only) - - /* STAGE 1: - * 1-particle basis is already evaluated, so we only need to - * copy it into the AA value buffer - */ - int num1 = dag.get_num1(); - for (int idx = 0; idx < num1; idx++) - dag.AAbuf(idx) = A( dag.Aspec(idx, 0), - dag.Aspec(idx, 1)-1, - dag.Aspec(idx, 2), - dag.Aspec(idx, 3) ); - - - if (recursive) { - /* STAGE 2: FORWARD PASS - * Forward pass: go through the dag and store all intermediate results - */ - - // rhos.fill(0); note the rhos are already reset and started filling above! - ACEComplex AAcur{0.0}; - int i1, i2; - - int * dag_nodes = dag.nodes.get_data(); - int idx_nodes = 0; - - DOUBLE_TYPE * dag_coefs = dag.coeffs.get_data(); - int idx_coefs = 0; - - int num2_int = dag.get_num2_int(); - int num2_leaf = dag.get_num2_leaf(); - - // interior nodes (save AA) - for (int idx = num1; idx < num1+num2_int; idx++) { - i1 = dag_nodes[idx_nodes]; idx_nodes++; - i2 = dag_nodes[idx_nodes]; idx_nodes++; - AAcur = dag.AAbuf(i1) * dag.AAbuf(i2); - dag.AAbuf(idx) = AAcur; - for (int p = 0; p < ndensity; p++, idx_coefs++) - rhos(p) += AAcur.real_part_product(dag_coefs[idx_coefs]); - } - - // leaf nodes -> no need to store in AAbuf - DOUBLE_TYPE AAcur_re = 0.0; - for (int _idx = 0; _idx < num2_leaf; _idx++) { - i1 = dag_nodes[idx_nodes]; idx_nodes++; - i2 = dag_nodes[idx_nodes]; idx_nodes++; - AAcur_re = dag.AAbuf(i1).real_part_product(dag.AAbuf(i2)); - for (int p = 0; p < ndensity; p++, idx_coefs++) - rhos(p) += AAcur_re * dag_coefs[idx_coefs]; - } - - } else { - - /* non-recursive Julia-style evaluator implementation */ - // TODO: fix array access to enable bounds checking again??? - ACEComplex AAcur{1.0}; - int *AAspec = jl_AAspec_flat.get_data(); - DOUBLE_TYPE *coeffs = jl_coeffs.get_data(); - int idx_spec = 0; - int idx_coefs = 0; - int order = 0; - int max_order = jl_AAspec.get_dim(1); - for (int iAA = 0; iAA < jl_AAspec.get_dim(0); iAA ++) { - AAcur = 1.0; - order = jl_orders(iAA); - for (int r = 0; r < order; r++, idx_spec++) - AAcur *= dag.AAbuf( AAspec[idx_spec] ); - for (int p = 0; p < ndensity; p++, idx_coefs++) - rhos(p) += AAcur.real_part_product(coeffs[idx_coefs]); - } - } - - /* we now have rho and can evaluate lots of things. - -------- this is back to the original PACE code --------- */ - -#ifdef DEBUG_FORCES_CALCULATIONS - printf("rhos = "); - for(DENSITY_TYPE p =0; prho_core_cutoffs(mu_i); - drho_cut = basis_set->drho_core_cutoffs(mu_i); - - basis_set->inner_cutoff(rho_core, rho_cut, drho_cut, fcut, dfcut); - basis_set->FS_values_and_derivatives(rhos, evdwl, dF_drho, ndensity); - - dF_drho_core = evdwl * dfcut + 1; - for (DENSITY_TYPE p = 0; p < ndensity; ++p) - dF_drho(p) *= fcut; - evdwl_cut = evdwl * fcut + rho_core; - - // E0 shift - evdwl_cut += basis_set->E0vals(mu_i); - - /* I've moved this from below the weight calculation - since I believe it only times the energy? the weights - are only needed for the forces? - But I believe we could add a third timer for computing just - the weights; this will allow us to check better where the - bottleneck is. - */ - energy_calc_timer.stop(); - - forces_calc_loop_timer.start(); - - -#ifdef DEBUG_FORCES_CALCULATIONS - printf("dFrhos = "); - for(DENSITY_TYPE p =0; pndensity; - for (DENSITY_TYPE p = 0; p < ndensity; ++p) { - //for rank=1 (r=0) only 1 ms-combination exists (ms_ind=0), so index of func.ctildes is 0..ndensity-1 - weights_rank1(func->mus[0], func->ns[0] - 1) += dF_drho(p) * func->ctildes[p]; - } - } - - /* --------- we now continue with the recursive code --------- */ - - if (recursive) { - /* STAGE 2: BACKWARD PASS */ - int i1, i2; - ACEComplex AA1{0.0}; - ACEComplex AA2{0.0}; - ACEComplex wcur{0.0}; - int num2_int = dag.get_num2_int(); - int num2_leaf = dag.get_num2_leaf(); - /* to prepare for the backward we first need to zero the weights */ - dag.w.fill({0.0}); - - int * dag_nodes = dag.nodes.get_data(); - int idx_nodes = 2 * (num2_int + num2_leaf) - 1; - - DOUBLE_TYPE * dag_coefs = dag.coeffs.get_data(); - int idx_coefs = ndensity * (num2_int + num2_leaf) - 1; - - for (int idx = num1+num2_int+num2_leaf - 1; idx >= num1; idx--) { - i2 = dag_nodes[idx_nodes]; idx_nodes--; - i1 = dag_nodes[idx_nodes]; idx_nodes--; - AA1 = dag.AAbuf(i1); - AA2 = dag.AAbuf(i2); - wcur = dag.w(idx); // [***] - for (int p = ndensity-1; p >= 0; p--, idx_coefs--) - wcur += dF_drho(p) * dag_coefs[idx_coefs]; - dag.w(i1) += wcur * AA2; // TODO: replace with explicit muladd? - dag.w(i2) += wcur * AA1; - } - - /* [***] - * Note that these weights don't really need to be stored for the - * leaf nodes. We tested splitting this for loop into two where - * for the leaf nodes the weight would just be initialized to 0.0 - * instead of reading from an array. The improvement was barely - * measurable, ca 3%, so we reverted to this simpler algorithm - */ - - - } else { - - // non-recursive ACE.jl style implemenation of gradients, but with - // a backward differentiation approach to the prod-A - // (cf. Algorithm 3 in the manuscript) - - dag.w.fill({0.0}); - ACEComplex AAf{1.0}, AAb{1.0}, theta{0.0}; - - int *AAspec = jl_AAspec_flat.get_data(); - DOUBLE_TYPE *coeffs = jl_coeffs.get_data(); - int idx_spec = 0; - int idx_coefs = 0; - int order = 0; - int max_order = jl_AAspec.get_dim(1); - for (int iAA = 0; iAA < jl_AAspec.get_dim(0); iAA ++ ) { - order = jl_orders(iAA); - theta = 0.0; - for (int p = 0; p < ndensity; p++, idx_coefs++) - theta += dF_drho(p) * coeffs[idx_coefs]; - dA[0] = 1.0; - AAf = 1.0; - for (int t = 0; t < order-1; t++, idx_spec++) { - spec[t] = AAspec[idx_spec]; - A_cache[t] = dag.AAbuf(spec[t]); - AAf *= A_cache[t]; - dA[t+1] = AAf; - } - spec[order-1] = AAspec[idx_spec]; idx_spec++; - A_cache[order-1] = dag.AAbuf(spec[order-1]); - AAb = 1.0; - for (int t = order-1; t >= 1; t--) { - AAb *= A_cache[t]; - dA[t-1] *= AAb; - dag.w(spec[t]) += theta * dA[t]; - } - dag.w(spec[0]) += theta * dA[0]; - } - - } - - /* STAGE 3: - * get the gradients from the 1-particle basis gradients and write them - * into the dF/drho derivatives. - */ - /* In order to reuse the original PACE code, we copy the weights back - * into the the PACE datastructure. */ - - for (int idx = 0; idx < num1; idx++) { - int m = dag.Aspec(idx, 3); - if (m >= 0) { - weights(dag.Aspec(idx, 0), // mu - dag.Aspec(idx, 1) - 1, // n - dag.Aspec(idx, 2), // l - m ) += dag.w(idx); - } else { - int factor = (m % 2 == 0 ? 1 : -1); - weights(dag.Aspec(idx, 0), // mu - dag.Aspec(idx, 1) - 1, // n - dag.Aspec(idx, 2), // l - -m ) += factor * dag.w(idx).conjugated(); - } - } - - - /* ------ From here we are now back to the original PACE code ---- */ - -// ==================== FORCES ==================== -#ifdef PRINT_MAIN_STEPS - printf("\nFORCE CALCULATION\n"); - printf("loop over neighbours\n"); -#endif - -// loop over neighbour atoms for force calculations - for (jj = 0; jj < jnum_actual; ++jj) { - mu_j = elements[jj]; - r_hat = rhats[jj]; - inv_r_norm = inv_r_norms[jj]; - - Array2DLM &Y_cache_jj = Y_cache(jj); - Array2DLM &DY_cache_jj = DY_cache(jj); - -#ifdef PRINT_LOOPS_INDICES - printf("\nneighbour atom #%d\n", jj); - printf("rhat = (%f, %f, %f)\n", r_hat[0], r_hat[1], r_hat[2]); -#endif - - forces_calc_neighbour_timer.start(); - - f_ji[0] = f_ji[1] = f_ji[2] = 0; - -//for rank = 1 - for (n = 0; n < nradbasei; ++n) { - if (weights_rank1(mu_j, n) == 0) - continue; - auto &DG = DG_cache(jj, n); - DGR = DG * Y00; - DGR *= weights_rank1(mu_j, n); -#ifdef DEBUG_FORCES_CALCULATIONS - printf("r=1: (n,l,m)=(%d, 0, 0)\n",n+1); - printf("\tGR(n=%d, r=%f)=%f\n",n+1,r_norm, gr(n)); - printf("\tDGR(n=%d, r=%f)=%f\n",n+1,r_norm, dgr(n)); - printf("\tdF+=(%f, %f, %f)\n",DGR * r_hat[0], DGR * r_hat[1], DGR * r_hat[2]); -#endif - f_ji[0] += DGR * r_hat[0]; - f_ji[1] += DGR * r_hat[1]; - f_ji[2] += DGR * r_hat[2]; - } - -//for rank > 1 - for (n = 0; n < nradiali; n++) { - for (l = 0; l <= lmaxi; l++) { - R_over_r = R_cache(jj, n, l) * inv_r_norm; - DR = DR_cache(jj, n, l); - - // for m>=0 - for (m = 0; m <= l; m++) { - ACEComplex w = weights(mu_j, n, l, m); - if (w == 0) - continue; - //counting for -m cases if m>0 - // if (m > 0) w *= 2; // not needed for recursive eval - - DY = DY_cache_jj(l, m); - Y_DR = Y_cache_jj(l, m) * DR; - - grad_phi_nlm.a[0] = Y_DR * r_hat[0] + DY.a[0] * R_over_r; - grad_phi_nlm.a[1] = Y_DR * r_hat[1] + DY.a[1] * R_over_r; - grad_phi_nlm.a[2] = Y_DR * r_hat[2] + DY.a[2] * R_over_r; -#ifdef DEBUG_FORCES_CALCULATIONS - printf("d_phi(n=%d, l=%d, m=%d) = ((%f,%f), (%f,%f), (%f,%f))\n",n+1,l,m, - grad_phi_nlm.a[0].real, grad_phi_nlm.a[0].img, - grad_phi_nlm.a[1].real, grad_phi_nlm.a[1].img, - grad_phi_nlm.a[2].real, grad_phi_nlm.a[2].img); - - printf("weights(n,l,m)(%d,%d,%d) = (%f,%f)\n", n+1, l, m, w.real, w.img); - //if (m>0) w*=2; - printf("dF(n,l,m)(%d, %d, %d) += (%f, %f, %f)\n", n + 1, l, m, - w.real_part_product(grad_phi_nlm.a[0]), - w.real_part_product(grad_phi_nlm.a[1]), - w.real_part_product(grad_phi_nlm.a[2]) - ); -#endif -// real-part multiplication only - f_ji[0] += w.real_part_product(grad_phi_nlm.a[0]); - f_ji[1] += w.real_part_product(grad_phi_nlm.a[1]); - f_ji[2] += w.real_part_product(grad_phi_nlm.a[2]); - } - } - } - - -#ifdef PRINT_INTERMEDIATE_VALUES - printf("f_ji(jj=%d, i=%d)=(%f, %f, %f)\n", jj, i, - f_ji[0], f_ji[1], f_ji[2] - ); -#endif - - //hard-core repulsion - DCR = DCR_cache(jj); -#ifdef DEBUG_FORCES_CALCULATIONS - printf("DCR = %f\n",DCR); -#endif - f_ji[0] += dF_drho_core * DCR * r_hat[0]; - f_ji[1] += dF_drho_core * DCR * r_hat[1]; - f_ji[2] += dF_drho_core * DCR * r_hat[2]; -#ifdef PRINT_INTERMEDIATE_VALUES - printf("with core-repulsion\n"); - printf("f_ji(jj=%d, i=%d)=(%f, %f, %f)\n", jj, i, - f_ji[0], f_ji[1], f_ji[2] - ); - printf("neighbour_index_mapping[jj=%d]=%d\n",jj,neighbour_index_mapping[jj]); -#endif - - neighbours_forces(neighbour_index_mapping[jj], 0) = f_ji[0]; - neighbours_forces(neighbour_index_mapping[jj], 1) = f_ji[1]; - neighbours_forces(neighbour_index_mapping[jj], 2) = f_ji[2]; - - forces_calc_neighbour_timer.stop(); - }// end loop over neighbour atoms for forces - - forces_calc_loop_timer.stop(); - - //now, energies and forces are ready - //energies(i) = evdwl + rho_core; - e_atom = evdwl_cut; - -#ifdef PRINT_INTERMEDIATE_VALUES - printf("energies(i) = FS(...rho_p_accum...) = %f\n", evdwl); -#endif - per_atom_calc_timer.stop(); -} \ No newline at end of file diff --git a/lib/pace/ace_recursive.h b/lib/pace/ace_recursive.h deleted file mode 100644 index 78e74feb86..0000000000 --- a/lib/pace/ace_recursive.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Christoph Ortner on 20.12.2020 - -#ifndef ACE_RECURSIVE_H -#define ACE_RECURSIVE_H - -#include "ace_abstract_basis.h" -#include "ace_arraynd.h" -#include "ace_array2dlm.h" -#include "ace_c_basis.h" -#include "ace_complex.h" -#include "ace_timing.h" -#include "ace_types.h" -#include "ace_evaluator.h" - -#include -#include -#include -#include -#include - -using namespace std; - - -typedef pair, vector > TPARTITION; -typedef list TPARTITIONS; - -typedef map, int> TDAGMAP; - -class ACEDAG { - - TPARTITIONS find_2partitions(vector v); - - void insert_node(TDAGMAP &dagmap, - vector node, - vector c); - - // the following fields are used only for *construction*, not evaluation - int dag_idx; // current index of dag node - Array2D nodes_pre; //TODO: YL: better to use vector<> - Array2D coeffs_pre; //TODO: YL: better to use vector<> - Array1D haschild; //TODO: YL: better to use vector<> - - /* which heuristic to choose for DAG construction? - * 0 : the simple original heuristic - * 1 : prioritize 2-correlation nodes and build the rest from those - */ - int heuristic = 0; - -public: - - ACEDAG() = default; - - void init(Array2D Aspec, Array2D AAspec, - Array1D orders, Array2D coeffs, - int heuristic ); - - Array1D AAbuf; - Array1D w; - - Array2D Aspec; - - // nodes in the graph - Array2D nodes; - Array2D coeffs; - - // total number of nodes in the dag - int num_nodes; - // number of interior nodes (with children) - int num2_int; - // number of leaf nodes (nc = no child) - int num2_leaf; - - - // number of 1-particle basis functions - // (these will be stored in the first num1 entries of AAbuf) - int get_num1() { return Aspec.get_dim(0); }; - // total number of n-correlation basis functions n > 1. - int get_num2() { return num_nodes - get_num1(); }; - int get_num2_int() { return num2_int; }; // with children - int get_num2_leaf() { return num2_leaf; }; // without children - - // debugging tool - void print(); -}; - - -/** - * Recursive Variant of the ACETildeEvaluator; should be 100% compatible - */ -class ACERecursiveEvaluator : public ACEEvaluator { - - /** - * Weights \f$ \omega_{i \mu n 0 0} \f$ for rank = 1, see Eq.(10) from implementation notes, - * 'i' is fixed for the current atom, shape: [nelements][nradbase] - */ - Array2D weights_rank1 = Array2D("weights_rank1"); - - /** - * Weights \f$ \omega_{i \mu n l m} \f$ for rank > 1, see Eq.(10) from implementation notes, - * 'i' is fixed for the current atom, shape: [nelements][nradbase][l=0..lmax, m] - */ - Array4DLM weights = Array4DLM("weights"); - - /** - * cache for gradients of \f$ g(r)\f$: grad_phi(jj,n)=A2DLM(l,m) - * shape:[max_jnum][nradbase] - */ - Array2D DG_cache = Array2D("DG_cache"); - - - /** - * cache for \f$ R_{nl}(r)\f$ - * shape:[max_jnum][nradbase][0..lmax] - */ - Array3D R_cache = Array3D("R_cache"); - /** - * cache for derivatives of \f$ R_{nl}(r)\f$ - * shape:[max_jnum][nradbase][0..lmax] - */ - Array3D DR_cache = Array3D("DR_cache"); - /** - * cache for \f$ Y_{lm}(\hat{r})\f$ - * shape:[max_jnum][0..lmax][m] - */ - Array3DLM Y_cache = Array3DLM("Y_cache"); - /** - * cache for \f$ \nabla Y_{lm}(\hat{r})\f$ - * shape:[max_jnum][0..lmax][m] - */ - Array3DLM DY_cache = Array3DLM("dY_dense_cache"); - - /** - * cache for derivatives of hard-core repulsion - * shape:[max_jnum] - */ - Array1D DCR_cache = Array1D("DCR_cache"); - - /** - * Partial derivatives \f$ dB_{i \mu n l m t}^{(r)} \f$ with sequential numbering over [func_ind][ms_ind][r], - * shape:[func_ms_r_ind] - */ - Array1D dB_flatten = Array1D("dB_flatten"); - - /** - * pointer to the ACEBasisSet object - */ - ACECTildeBasisSet *basis_set = nullptr; - - /** - * Initialize internal arrays according to basis set sizes - * @param basis_set - */ - void init(ACECTildeBasisSet *basis_set, int heuristic); - - /* convert the PACE to the ACE.jl format to prepare for DAG construction*/ - Array2D jl_Aspec; - Array2D jl_AAspec; - Array1D jl_AAspec_flat; - Array1D jl_orders; - Array2D jl_coeffs; - void acejlformat(); - - /* the main event : the computational graph */ - ACEDAG dag; - - bool recursive = true; - -public: - - - ACERecursiveEvaluator() = default; - - explicit ACERecursiveEvaluator(ACECTildeBasisSet &bas, - bool recursive = true) { - set_recursive(recursive); - set_basis(bas); - } - - /** - * set the basis function to the ACE evaluator - * @param bas - */ - void set_basis(ACECTildeBasisSet &bas, int heuristic = 0); - - /** - * The key method to compute energy and forces for atom 'i'. - * Method will update the "e_atom" variable and "neighbours_forces(jj, alpha)" array - * - * @param i atom index - * @param x atomic positions array of the real and ghost atoms, shape: [atom_ind][3] - * @param type atomic types array of the real and ghost atoms, shape: [atom_ind] - * @param jnum number of neighbours of atom_i - * @param jlist array of neighbour indices, shape: [jnum] - */ - void compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *type, const int jnum, const int *jlist) override; - - /** - * Resize all caches over neighbours atoms - * @param max_jnum maximum number of neighbours - */ - void resize_neighbours_cache(int max_jnum) override; - - /******* public functions related to recursive evaluator ********/ - - // print out the DAG for visual inspection - void print_dag() {dag.print();} - - // print out the jl format for visual inspection - // should be converted into a proper test - void test_acejlformat(); - - void set_recursive(bool tf) { recursive = tf; } - - /********************************/ - -}; - - -#endif //ACE_RECURSIVE_H \ No newline at end of file diff --git a/lib/pace/ace_spherical_cart.cpp b/lib/pace/ace_spherical_cart.cpp deleted file mode 100644 index f1f0fccced..0000000000 --- a/lib/pace/ace_spherical_cart.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Ralf Drautz, Yury Lysogorskiy - -#include - -#include "ace_spherical_cart.h" - -ACECartesianSphericalHarmonics::ACECartesianSphericalHarmonics(LS_TYPE lm) { - init(lm); -} - -void ACECartesianSphericalHarmonics::init(LS_TYPE lm) { - lmax = lm; - - alm.init(lmax, "alm"); - blm.init(lmax, "blm"); - cl.init(lmax + 1); - dl.init(lmax + 1); - - plm.init(lmax, "plm"); - dplm.init(lmax, "dplm"); - - ylm.init(lmax, "ylm"); - dylm.init(lmax, "dylm"); - - pre_compute(); -} - -/** -Destructor for ACECartesianSphericalHarmonics. - -@param None - -@returns None -*/ -ACECartesianSphericalHarmonics::~ACECartesianSphericalHarmonics() {} - - -void ACECartesianSphericalHarmonics::pre_compute() { - - DOUBLE_TYPE a, b; - DOUBLE_TYPE lsq, ld, l1, l2; - DOUBLE_TYPE msq; - - for (LS_TYPE l = 1; l <= lmax; l++) { - lsq = l * l; - ld = 2 * l; - l1 = (4 * lsq - 1); - l2 = lsq - ld + 1; - for (MS_TYPE m = 0; m < l - 1; m++) { - msq = m * m; - a = sqrt((DOUBLE_TYPE(l1)) / (DOUBLE_TYPE(lsq - msq))); - b = -sqrt((DOUBLE_TYPE(l2 - msq)) / (DOUBLE_TYPE(4 * l2 - 1))); - alm(l, m) = a; - blm(l, m) = b; - } - } - - for (LS_TYPE l = 1; l <= lmax; l++) { - cl(l) = -sqrt(1.0 + 0.5 / (DOUBLE_TYPE(l))); - dl(l) = sqrt(DOUBLE_TYPE(2 * (l - 1) + 3)); - } -} - - -void ACECartesianSphericalHarmonics::compute_barplm(DOUBLE_TYPE rz, LS_TYPE lmaxi) { - - // requires -1 <= rz <= 1 , NO CHECKING IS PERFORMED !!!!!!!!! - // prefactors include 1/sqrt(2) factor compared to reference - DOUBLE_TYPE t; - - // l=0, m=0 - //plm(0, 0) = Y00/sq1o4pi; //= sq1o4pi; - plm(0, 0) = Y00; //= 1; - dplm(0, 0) = 0.0; - - if (lmaxi > 0) { - - // l=1, m=0 - plm(1, 0) = Y00 * sq3 * rz; - dplm(1, 0) = Y00 * sq3; - - // l=1, m=1 - plm(1, 1) = -sq3o2 * Y00; - dplm(1, 1) = 0.0; - - // loop l = 2, lmax - for (LS_TYPE l = 2; l <= lmaxi; l++) { - for (MS_TYPE m = 0; m < l - 1; m++) { - plm(l, m) = alm(l, m) * (rz * plm(l - 1, m) + blm(l, m) * plm(l - 2, m)); - dplm(l, m) = alm(l, m) * (plm(l - 1, m) + rz * dplm(l - 1, m) + blm(l, m) * dplm(l - 2, m)); - } - t = dl(l) * plm(l - 1, l - 1); - plm(l, l - 1) = t * rz; - dplm(l, l - 1) = t; - plm(l, l) = cl(l) * plm(l - 1, l - 1); - dplm(l, l) = 0.0; - } - } -} //end compute_barplm - - -void ACECartesianSphericalHarmonics::compute_ylm(DOUBLE_TYPE rx, DOUBLE_TYPE ry, DOUBLE_TYPE rz, LS_TYPE lmaxi) { - - // requires rx^2 + ry^2 + rz^2 = 1 , NO CHECKING IS PERFORMED !!!!!!!!! - - DOUBLE_TYPE real; - DOUBLE_TYPE img; - MS_TYPE m; - ACEComplex phase; - ACEComplex phasem, mphasem1; - ACEComplex dyx, dyy, dyz; - ACEComplex rdy; - - phase.real = rx; - phase.img = ry; - //compute barplm - compute_barplm(rz, lmaxi); - - //m = 0 - m = 0; - for (LS_TYPE l = 0; l <= lmaxi; l++) { - - ylm(l, m).real = plm(l, m); - ylm(l, m).img = 0.0; - - dyz.real = dplm(l, m); - rdy.real = dyz.real * rz; - - dylm(l, m).a[0].real = -rdy.real * rx; - dylm(l, m).a[0].img = 0.0; - dylm(l, m).a[1].real = -rdy.real * ry; - dylm(l, m).a[1].img = 0.0; - dylm(l, m).a[2].real = dyz.real - rdy.real * rz; - dylm(l, m).a[2].img = 0; - } - //m = 0 - m = 1; - for (LS_TYPE l = 1; l <= lmaxi; l++) { - - ylm(l, m) = phase * plm(l, m); - -// std::cout << "Re ylm(" << l << "," << m <<")= " << ylm(l, m).real << std::endl; -// std::cout << "Im ylm(" << l << "," << m <<")= " << ylm(l, m).img << std::endl; - - dyx.real = plm(l, m); - dyx.img = 0.0; - dyy.real = 0.0; - dyy.img = plm(l, m); - dyz.real = phase.real * dplm(l, m); - dyz.img = phase.img * dplm(l, m); - - rdy.real = rx * dyx.real + +rz * dyz.real; - rdy.img = ry * dyy.img + rz * dyz.img; - - dylm(l, m).a[0].real = dyx.real - rdy.real * rx; - dylm(l, m).a[0].img = -rdy.img * rx; - dylm(l, m).a[1].real = -rdy.real * ry; - dylm(l, m).a[1].img = dyy.img - rdy.img * ry; - dylm(l, m).a[2].real = dyz.real - rdy.real * rz; - dylm(l, m).a[2].img = dyz.img - rdy.img * rz; - } - - // m > 1 - phasem = phase; - for (MS_TYPE m = 2; m <= lmaxi; m++) { - - mphasem1.real = phasem.real * DOUBLE_TYPE(m); - mphasem1.img = phasem.img * DOUBLE_TYPE(m); - phasem = phasem * phase; - - for (LS_TYPE l = m; l <= lmaxi; l++) { - - ylm(l, m).real = phasem.real * plm(l, m); - ylm(l, m).img = phasem.img * plm(l, m); - - dyx = mphasem1 * plm(l, m); - dyy.real = -dyx.img; - dyy.img = dyx.real; - dyz = phasem * dplm(l, m); - - rdy.real = rx * dyx.real + ry * dyy.real + rz * dyz.real; - rdy.img = rx * dyx.img + ry * dyy.img + rz * dyz.img; - - dylm(l, m).a[0].real = dyx.real - rdy.real * rx; - dylm(l, m).a[0].img = dyx.img - rdy.img * rx; - dylm(l, m).a[1].real = dyy.real - rdy.real * ry; - dylm(l, m).a[1].img = dyy.img - rdy.img * ry; - dylm(l, m).a[2].real = dyz.real - rdy.real * rz; - dylm(l, m).a[2].img = dyz.img - rdy.img * rz; - } - } - -} - diff --git a/lib/pace/ace_spherical_cart.h b/lib/pace/ace_spherical_cart.h deleted file mode 100644 index b2a0cb5913..0000000000 --- a/lib/pace/ace_spherical_cart.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Ralf Drautz, Yury Lysogorskiy - -#ifndef ACE_SPHERICAL_CART_H -#define ACE_SPHERICAL_CART_H - -#include - -#include "ace_arraynd.h" -#include "ace_array2dlm.h" -#include "ace_complex.h" -#include "ace_types.h" - - -using namespace std; - -const DOUBLE_TYPE sq1o4pi = 0.28209479177387814347; // sqrt(1/(4*pi)) -const DOUBLE_TYPE sq4pi = 3.54490770181103176384; // sqrt(4*pi) -const DOUBLE_TYPE sq3 = 1.73205080756887719318;//sqrt(3), numpy -const DOUBLE_TYPE sq3o2 = 1.22474487139158894067;//sqrt(3/2), numpy - -//definition of common factor for spherical harmonics = Y00 -//const DOUBLE_TYPE Y00 = sq1o4pi; -const DOUBLE_TYPE Y00 = 1; - -/** -Class to store spherical harmonics and their associated functions. \n -All the associated members such as \f$ P_{lm}, Y_{lm}\f$ etc are one dimensional arrays of length (L+1)*(L+2)/2. \n -The value that corresponds to a particular l, m configuration can be accessed through a \code ylm(l,m) \endcode \n -*/ -class ACECartesianSphericalHarmonics { -public: - - /** - int, the number of spherical harmonics to be found - */ - LS_TYPE lmax; - - /** - * Default constructor - */ - ACECartesianSphericalHarmonics() = default; - - /** - * Parametrized constructor. Dynamically initialises all the arrays. - * @param lmax maximum orbital moment - */ - explicit ACECartesianSphericalHarmonics(LS_TYPE lmax); - - /** - * Initialize internal arrays and precompute necessary coefficients - * @param lm maximum orbital moment - */ - void init(LS_TYPE lm); - - /** - * Destructor - */ - ~ACECartesianSphericalHarmonics(); - - /** - * Precompute necessaary helper arrays Precomputes the value of \f$ a_{lm}, b_{lm}, c_l, d_l \f$ - */ - void pre_compute(); - - /** - Function that computes \f$ \bar{P}_{lm} \f$ for the corresponding lmax value - Input is \f$ \hat{r}_z \f$ which is the $z$-component of the bond direction. - - For each \f$ \hat{r}_z \f$, this computes the whole range of \f$ \bar{P}_{lm} \f$ values - and its derivatives upto the lmax specified, which is a member of the class. - - @param rz, DOUBLE_TYPE - - @returns None - */ - void compute_barplm(DOUBLE_TYPE rz, LS_TYPE lmaxi); - - /** - Function that computes \f$ Y_{lm} \f$ for the corresponding lmax value - Input is the bond-directon vector \f$ \hat{r}_x, \hat{r}_y, \hat{r}_z \f$ - - Each \f$ Y_{lm} \f$ value is a ACEComplex object with real and imaginary parts. This function also - finds the derivatives, which are stored in the Dycomponent class, with each component being a - ACEComplex object. - - @param rx, DOUBLE_TYPE - @param ry, DOUBLE_TYPE - @param rz, DOUBLE_TYPE - @param lmaxi, int - */ - void compute_ylm(DOUBLE_TYPE rx, DOUBLE_TYPE ry, DOUBLE_TYPE rz, LS_TYPE lmaxi); - - Array2DLM alm; - Array2DLM blm; - Array1D cl; - Array1D dl; - - Array2DLM plm; - Array2DLM dplm; - - Array2DLM ylm; ///< Values of all spherical harmonics after \code compute_ylm(rx,ry,rz, lmaxi) \endcode call - Array2DLM dylm;///< Values of gradients of all spherical harmonics after \code compute_ylm(rx,ry,rz, lmaxi) \endcode call - -}; - - -#endif diff --git a/lib/pace/ace_timing.h b/lib/pace/ace_timing.h deleted file mode 100644 index 7f5243eb99..0000000000 --- a/lib/pace/ace_timing.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Yury Lysogorskiy on 19.02.20. - -#ifndef ACE_TIMING_H -#define ACE_TIMING_H - -#include - -using namespace std::chrono; -using Clock = std::chrono::high_resolution_clock; -using TimePoint = std::chrono::time_point; -using Duration = Clock::duration; - -////////////////////////////////////////// -#ifdef FINE_TIMING -/** - * Helper class for timing the code. - * The timer should be initialized to reset measured time and - * then call "start" and "stop" before and after measured code. - * The measured time is stored in "duration" variable - */ -struct ACETimer { - Duration duration; ///< measured duration - TimePoint start_moment; ///< start moment of current measurement - - ACETimer() { init(); }; - - /** - * Reset timer - */ - void init() { duration = std::chrono::nanoseconds(0); } - - /** - * Start timer - */ - void start() { start_moment = Clock::now(); } - - /** - * Stop timer, update measured "duration" - */ - void stop() { duration += Clock::now() - start_moment; } - - /** - * Get duration in microseconds - */ - long as_microseconds() { return std::chrono::duration_cast(duration).count(); } - - /** - * Get duration in nanoseconds - */ - long as_nanoseconds() { return std::chrono::duration_cast(duration).count(); } - -}; - -#else // EMPTY Definitions -/** - * Helper class for timing the code. - * The timer should be initialized to reset measured time and - * then call "start" and "stop" before and after measured code. - * The measured time is stored in "duration" variable - */ -struct ACETimer { - Duration duration; ///< measured duration - TimePoint start_moment; ///< start moment of current measurement - - ACETimer() {}; - - /** - * Reset timer - */ - void init() {} - - /** - * Start timer - */ - void start() {} - - /** - * Stop timer, update measured "duration" - */ - void stop() {} - - /** - * Get duration in microseconds - */ - long as_microseconds() {return 0; } - - /** - * Get duration in nanoseconds - */ - long as_nanoseconds() {return 0; } - -}; - -#endif -////////////////////////////////////////// - - -#endif //ACE_TIMING_H diff --git a/lib/pace/ace_types.h b/lib/pace/ace_types.h deleted file mode 100644 index f9b3cf7267..0000000000 --- a/lib/pace/ace_types.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Yury Lysogorskiy on 20.01.20. - -#ifndef ACE_TYPES_H -#define ACE_TYPES_H - -typedef char RANK_TYPE; -typedef int SPECIES_TYPE; -typedef short int NS_TYPE; -typedef short int LS_TYPE; - -typedef short int DENSITY_TYPE; - -typedef short int MS_TYPE; - -typedef short int SHORT_INT_TYPE; -typedef double DOUBLE_TYPE; - -#endif \ No newline at end of file diff --git a/lib/pace/ace_version.h b/lib/pace/ace_version.h deleted file mode 100644 index 9d61e5c505..0000000000 --- a/lib/pace/ace_version.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Lysogorskiy Yury on 07.04.2020. - -#ifndef ACE_VERSION_H -#define ACE_VERSION_H - -#define VERSION_YEAR 2021 -#define VERSION_MONTH 2 -#define VERSION_DAY 3 - -#endif //ACE_VERSION_Hls - diff --git a/lib/pace/ships_radial.cpp b/lib/pace/ships_radial.cpp deleted file mode 100644 index e948f03f21..0000000000 --- a/lib/pace/ships_radial.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - -// Created by Christoph Ortner on 03.06.2020 - -#include "ships_radial.h" - -#include -#include -#include - - -using namespace std; - -void SHIPsRadPolyBasis::_init(DOUBLE_TYPE r0, int p, DOUBLE_TYPE rcut, - DOUBLE_TYPE xl, DOUBLE_TYPE xr, - int pl, int pr, size_t maxn) { - this->p = p; - this->r0 = r0; - this->rcut = rcut; - this->xl = xl; - this->xr = xr; - this->pl = pl; - this->pr = pr; - this->maxn = maxn; - this->A.resize(maxn); - this->B.resize(maxn); - this->C.resize(maxn); - this->P.resize(maxn); - this->dP_dr.resize(maxn); -} - - -void SHIPsRadPolyBasis::fread(FILE *fptr) -{ - int res; //for fscanf result - int maxn, p, pl, pr, ntests; - double r0, xl, xr, a, b, c, rcut; - - // transform parameters - res = fscanf(fptr, "transform parameters: p=%d r0=%lf\n", &p, &r0); - if (res != 2) - throw invalid_argument("Couldn't read line: transform parameters: p=%d r0=%lf"); - // cutoff parameters - res = fscanf(fptr, "cutoff parameters: rcut=%lf xl=%lf xr=%lf pl=%d pr=%d\n", - &rcut, &xl, &xr, &pl, &pr); - if (res != 5) - throw invalid_argument("Couldn't read cutoff parameters: rcut=%lf xl=%lf xr=%lf pl=%d pr=%d"); - // basis size - res = fscanf(fptr, "recursion coefficients: maxn = %d\n", &maxn); - if (res != 1) - throw invalid_argument("Couldn't read recursion coefficients: maxn = %d"); - // initialize and allocate - this->_init(r0, p, rcut, xl, xr, pl, pr, maxn); - - // read basis coefficients - for (int i = 0; i < maxn; i++) { - res = fscanf(fptr, " %lf %lf %lf\n", &a, &b, &c); - if (res != 3) - throw invalid_argument("Couldn't read line: A_n B_n C_n"); - this->A(i) = DOUBLE_TYPE(a); - this->B(i) = DOUBLE_TYPE(b); - this->C(i) = DOUBLE_TYPE(c); - } - - // // check there are no consistency tests (I don't have time to fix this now) - // res = fscanf(fptr, "tests: ntests = %d\n", &ntests); - // if (res != 1) - // throw invalid_argument("Couldn't read line: tests: ntests = %d"); - // if (ntests != 0) - // throw invalid_argument("must have ntests = 0!"); - - // --------------------------------------------------------------------- - // run the consistency test this could be moved into a separate function - double r, Pn, dPn; - double err = 0.0; - - res = fscanf(fptr, "tests: ntests = %d\n", &ntests); - if (res != 1) - throw invalid_argument("Couldn't read line: tests: ntests = %d"); - for (size_t itest = 0; itest < ntests; itest++) { - // read an r argument - res = fscanf(fptr, " r=%lf\n", &r); - // printf("r = %lf \n", r); - if (res != 1) - throw invalid_argument("Couldn't read line: r=%lf"); - // printf("test %d, r=%f, maxn=%d \n", itest, r, maxn); - // evaluate the basis - this->calcP(r, maxn, SPECIES_TYPE(0), SPECIES_TYPE(0)); - // compare against the stored values - for (size_t n = 0; n < maxn; n++) { - res = fscanf(fptr, " %lf %lf\n", &Pn, &dPn); - if (res != 2) - throw invalid_argument("Couldn't read test value line: %lf %lf"); - err = max(err, abs(Pn - this->P(n)) + abs(dPn - this->dP_dr(n))); - // printf(" %d %e %e \n", int(n), - // abs(Pn - this->P(n)), - // abs(dPn - this->dP_dr(n))); - } - } - if (ntests > 0) - printf("Maximum Test error = %e\n", err); - // --------------------------------------------------------------------- - -} - - - - -size_t SHIPsRadPolyBasis::get_maxn() -{ - return this->maxn; -} - - -// Julia code: ((1+r0)/(1+r))^p -void SHIPsRadPolyBasis::transform(const DOUBLE_TYPE r, DOUBLE_TYPE &x_out, DOUBLE_TYPE &dx_out) const { - x_out = pow((1 + r0) / (1 + r), p); // ==pow( (1 + r) / (1 + r0), -p ); - dx_out = -p * pow((1 + r) / (1 + r0), -p - 1) / (1 + r0); -} - -void SHIPsRadPolyBasis::fcut(const DOUBLE_TYPE x, DOUBLE_TYPE &f_out, DOUBLE_TYPE &df_out) const { - if ( ((x < xl) && (pl > 0)) || ((x > xr) && (pr > 0)) ) { - f_out = 0.0; - df_out = 0.0; - } else { - f_out = pow(x - xl, pl) * pow(x - xr, pr); - df_out = pl * pow(x - xl, pl - 1) * pow(x - xr, pr) + pow(x - xl, pl) * pr * pow(x - xr, pr - 1); - } -} - - /* ------------------------------------------------------------------------ -Julia Code -P[1] = J.A[1] * _fcut_(J.pl, J.tl, J.pr, J.tr, t) -if length(J) == 1; return P; end -P[2] = (J.A[2] * t + J.B[2]) * P[1] -@inbounds for n = 3:length(J) - P[n] = (J.A[n] * t + J.B[n]) * P[n-1] + J.C[n] * P[n-2] -end -return P ------------------------------------------------------------------------- */ - -void SHIPsRadPolyBasis::calcP(DOUBLE_TYPE r, size_t maxn, - SPECIES_TYPE z1, SPECIES_TYPE z2) { - if (maxn > this->maxn) - throw invalid_argument("Given maxn couldn't be larger than global maxn"); - - if (maxn > P.get_size()) - throw invalid_argument("Given maxn couldn't be larger than global length of P"); - - DOUBLE_TYPE x, dx_dr; // dx -> dx/dr - transform(r, x, dx_dr); - // printf("r = %f, x = %f, fcut = %f \n", r, x, fcut(x)); - DOUBLE_TYPE f, df_dx; - fcut(x, f, df_dx); // df -> df/dx - - //fill with zeros - P.fill(0); - dP_dr.fill(0); - - P(0) = A(0) * f; - dP_dr(0) = A(0) * df_dx * dx_dr; // dP/dr; chain rule: df_cut/dr = df_cut/dx * dx/dr - if (maxn > 0) { - P(1) = (A(1) * x + B(1)) * P(0); - dP_dr(1) = A(1) * dx_dr * P(0) + (A(1) * x + B(1)) * dP_dr(0); - } - for (size_t n = 2; n < maxn; n++) { - P(n) = (A(n) * x + B(n)) * P(n - 1) + C(n) * P(n - 2); - dP_dr(n) = A(n) * dx_dr * P(n - 1) + (A(n) * x + B(n)) * dP_dr(n - 1) + C(n) * dP_dr(n - 2); - } -} - - -// ==================================================================== - - -bool SHIPsRadialFunctions::has_pair() { - return this->haspair; -} - -void SHIPsRadialFunctions::load(string fname) { - FILE * fptr = fopen(fname.data(), "r"); - size_t res = fscanf(fptr, "radbasename=ACE.jl.Basic\n"); - if (res != 0) - throw("SHIPsRadialFunctions::load : couldnt read radbasename=ACE.jl.Basic"); - this->fread(fptr); - fclose(fptr); -} - -void SHIPsRadialFunctions::fread(FILE *fptr){ - int res; - size_t maxn; - char hasE0, haspair; - DOUBLE_TYPE c; - - // check whether we have a pair potential - res = fscanf(fptr, "haspair: %c\n", &haspair); - if (res != 1) - throw("SHIPsRadialFunctions::load : couldn't read haspair"); - - // read the radial basis - this->radbasis.fread(fptr); - - // read the pair potential - if (haspair == 't') { - this->haspair=true; - fscanf(fptr, "begin repulsive potential\n"); - fscanf(fptr, "begin polypairpot\n"); - // read the basis parameters - pairbasis.fread(fptr); - maxn = pairbasis.get_maxn(); - // read the coefficients - fscanf(fptr, "coefficients\n"); - paircoeffs.resize(maxn); - for (size_t n = 0; n < maxn; n++) { - fscanf(fptr, "%lf\n", &c); - paircoeffs(n) = c; - } - fscanf(fptr, "end polypairpot\n"); - // read the spline parameters - fscanf(fptr, "spline parameters\n"); - fscanf(fptr, " e_0 + B exp(-A*(r/ri-1)) * (ri/r)\n"); - fscanf(fptr, "ri=%lf\n", &(this->ri)); - fscanf(fptr, "e0=%lf\n", &(this->e0)); - fscanf(fptr, "A=%lf\n", &(this->A)); - fscanf(fptr, "B=%lf\n", &(this->B)); - fscanf(fptr, "end repulsive potential\n"); - } -} - - -size_t SHIPsRadialFunctions::get_maxn() -{ - return this->radbasis.get_maxn(); -} - -DOUBLE_TYPE SHIPsRadialFunctions::get_rcut() -{ - return max(radbasis.rcut, pairbasis.rcut); -} - - -void SHIPsRadialFunctions::fill_gk(DOUBLE_TYPE r, NS_TYPE maxn, SPECIES_TYPE z1, SPECIES_TYPE z2) { - radbasis.calcP(r, maxn, z1, z2); - for (NS_TYPE n = 0; n < maxn; n++) { - gr(n) = radbasis.P(n); - dgr(n) = radbasis.dP_dr(n); - } -} - - -void SHIPsRadialFunctions::fill_Rnl(DOUBLE_TYPE r, NS_TYPE maxn, SPECIES_TYPE z1, SPECIES_TYPE z2) { - radbasis.calcP(r, maxn, z1, z2); - for (NS_TYPE n = 0; n < maxn; n++) { - for (LS_TYPE l = 0; l <= lmax; l++) { - fr(n, l) = radbasis.P(n); - dfr(n, l) = radbasis.dP_dr(n); - } - } -} - - -void SHIPsRadialFunctions::setuplookupRadspline() { -} - - -void SHIPsRadialFunctions::init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, - SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, string radbasename) { - //mimic ACERadialFunctions::init - this->nradbase = nradb; - this->lmax = lmax; - this->nradial = nradial; - this->deltaSplineBins = deltaSplineBins; - this->nelements = nelements; - this->cutoff = cutoff; - this->radbasename = radbasename; - - gr.init(nradbase, "gr"); - dgr.init(nradbase, "dgr"); - - - fr.init(nradial, lmax + 1, "fr"); - dfr.init(nradial, lmax + 1, "dfr"); - - splines_gk.init(nelements, nelements, "splines_gk"); - splines_rnl.init(nelements, nelements, "splines_rnl"); - splines_hc.init(nelements, nelements, "splines_hc"); - - lambda.init(nelements, nelements, "lambda"); - lambda.fill(1.); - - cut.init(nelements, nelements, "cut"); - cut.fill(1.); - - dcut.init(nelements, nelements, "dcut"); - dcut.fill(1.); - - crad.init(nelements, nelements, (lmax + 1), nradial, nradbase, "crad"); - crad.fill(0.); - - //hard-core repulsion - prehc.init(nelements, nelements, "prehc"); - prehc.fill(0.); - - lambdahc.init(nelements, nelements, "lambdahc"); - lambdahc.fill(1.); -} - - -void SHIPsRadialFunctions::evaluate(DOUBLE_TYPE r, NS_TYPE nradbase_c, NS_TYPE nradial_c, SPECIES_TYPE mu_i, - SPECIES_TYPE mu_j, bool calc_second_derivatives) { - if (calc_second_derivatives) - throw invalid_argument("SHIPsRadialFunctions has not `calc_second_derivatives` option"); - - radbasis.calcP(r, nradbase_c, mu_i, mu_j); - for (NS_TYPE nr = 0; nr < nradbase_c; nr++) { - gr(nr) = radbasis.P(nr); - dgr(nr) = radbasis.dP_dr(nr); - } - for (NS_TYPE nr = 0; nr < nradial_c; nr++) { - for (LS_TYPE l = 0; l <= this->lmax; l++) { - fr(nr, l) = radbasis.P(nr); - dfr(nr, l) = radbasis.dP_dr(nr); - } - } - - if (this->has_pair()) - this->evaluate_pair(r, mu_i, mu_j); - else { - cr = 0; - dcr = 0; - } -} - -void SHIPsRadialFunctions::evaluate_pair(DOUBLE_TYPE r, - SPECIES_TYPE mu_i, - SPECIES_TYPE mu_j, - bool calc_second_derivatives) { - // spline_hc.calcSplines(r); - // cr = spline_hc.values(0); - // dcr = spline_hc.derivatives(0); - - // the outer polynomial potential - if (r > ri) { - pairbasis.calcP(r, pairbasis.get_maxn(), mu_i, mu_j); - cr = 0; - dcr = 0; - for (size_t n = 0; n < pairbasis.get_maxn(); n++) { - cr += paircoeffs(n) * pairbasis.P(n); - dcr += paircoeffs(n) * pairbasis.dP_dr(n); - } - } - else { // the repulsive core part - cr = e0 + B * exp(-A * (r/ri - 1)) * (ri/r); - dcr = B * exp( - A * (r/ri-1) ) * ri * ( - A / ri / r - 1/(r*r) ); - } - // fix double-counting - cr *= 0.5; - dcr *= 0.5; -} - - - diff --git a/lib/pace/ships_radial.h b/lib/pace/ships_radial.h deleted file mode 100644 index 60a82448cd..0000000000 --- a/lib/pace/ships_radial.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Performant implementation of atomic cluster expansion and interface to LAMMPS - * - * Copyright 2021 (c) Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - * Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - * Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - * - * ^1: Ruhr-University Bochum, Bochum, Germany - * ^2: University of Cambridge, Cambridge, United Kingdom - * ^3: Sandia National Laboratories, Albuquerque, New Mexico, USA - * ^4: University of British Columbia, Vancouver, BC, Canada - * - * - * See the LICENSE file. - * This FILENAME 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 . - */ - - -// Created by Christoph Ortner on 03.06.2020 - -#ifndef SHIPs_RADIAL_FUNCTIONS_H -#define SHIPs_RADIAL_FUNCTIONS_H - -#include "ace_arraynd.h" -#include "ace_types.h" -#include "ace_radial.h" - -class SHIPsRadPolyBasis { - -public: - - // transform parameters - int p = 0; - DOUBLE_TYPE r0 = 0.0; - - // cutoff parameters - DOUBLE_TYPE rcut = 0.0; - DOUBLE_TYPE xl = 0.0; - DOUBLE_TYPE xr = 0.0; - int pl = 0; - int pr = 0; - - // basis size - size_t maxn = 0; - - // recursion parameters - Array1D A = Array1D("SHIPs radial basis: A"); - Array1D B = Array1D("SHIPs radial basis: B"); - Array1D C = Array1D("SHIPs radial basis: C"); - - // temporary storage for evaluating the basis - Array1D P = Array1D("SHIPs radial basis: P"); - Array1D dP_dr = Array1D("SHIPs radial basis: dP"); - -////////////////////////////////// - - SHIPsRadPolyBasis() = default; - - ~SHIPsRadPolyBasis() = default; - - // distance transform - void transform(const DOUBLE_TYPE r, DOUBLE_TYPE &x_out, DOUBLE_TYPE &dx_out) const; - - // cutoff function - void fcut(const DOUBLE_TYPE x, DOUBLE_TYPE &f_out, DOUBLE_TYPE &df_out) const; - - void fread(FILE *fptr); - - void _init(DOUBLE_TYPE r0, int p, DOUBLE_TYPE rcut, - DOUBLE_TYPE xl, DOUBLE_TYPE xr, - int pl, int pr, size_t maxn); - - void calcP(DOUBLE_TYPE r, size_t maxn, SPECIES_TYPE z1, SPECIES_TYPE z2); - - size_t get_maxn(); - -}; - - - - -class SHIPsRadialFunctions : public AbstractRadialBasis { -public: - - // radial basis - SHIPsRadPolyBasis radbasis; - - // pair potential basis - bool haspair = false; - SHIPsRadPolyBasis pairbasis; - - // pair potential coefficients - Array1D paircoeffs = Array1D("SHIPs pairpot coeffs: paircoeffs"); - - // spline parameters for repulsive core - DOUBLE_TYPE ri = 0.0; - DOUBLE_TYPE e0 = 0.0; - DOUBLE_TYPE A = 0.0; - DOUBLE_TYPE B = 0.0; - -////////////////////////////////// - - SHIPsRadialFunctions() = default; - - ~SHIPsRadialFunctions() override = default; - - - void fread(FILE *fptr); - - void load(string fname); - - size_t get_maxn(); - DOUBLE_TYPE get_rcut(); - - bool has_pair(); - - void init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, - string radbasename) override; - - void - evaluate(DOUBLE_TYPE r, NS_TYPE nradbase_c, NS_TYPE nradial_c, SPECIES_TYPE mu_i, SPECIES_TYPE mu_j, - bool calc_second_derivatives = false) override; - - void - evaluate_pair(DOUBLE_TYPE r, SPECIES_TYPE mu_i, SPECIES_TYPE mu_j, - bool calc_second_derivatives = false); - - void setuplookupRadspline() override; - - SHIPsRadialFunctions *clone() const override { - return new SHIPsRadialFunctions(*this); - }; - - /** - * Helper method, that populate `fr` and `dfr` 2D-arrays (n,l) with P(n), dP_dr for given coordinate r - * @param r - * @param maxn - * @param z1 - * @param z2 - */ - void fill_Rnl(DOUBLE_TYPE r, NS_TYPE maxn, SPECIES_TYPE z1, SPECIES_TYPE z2); - - void fill_gk(DOUBLE_TYPE r, NS_TYPE maxn, SPECIES_TYPE z1, SPECIES_TYPE z2); -}; - - -#endif diff --git a/src/USER-PACE/Install.sh b/src/USER-PACE/Install.sh index 4d87b0e3ed..c099ddd2c4 100644 --- a/src/USER-PACE/Install.sh +++ b/src/USER-PACE/Install.sh @@ -1,68 +1,64 @@ -# Install.sh file that integrates the settings from the lib folder into the conventional build process (make build?) +# Install/unInstall package files in LAMMPS +# mode = 0/1/2 for uninstall/install/update -# COPIED FROM src/KIM/Install.sh: +mode=$1 -# # Install/unInstall package files in LAMMPS -# # mode = 0/1/2 for uninstall/install/update +# enforce using portable C locale +LC_ALL=C +export LC_ALL -# mode=$1 +# arg1 = file, arg2 = file it depends on -# # enforce using portable C locale -# LC_ALL=C -# export LC_ALL +action () { + if (test $mode = 0) then + rm -f ../$1 + elif (! cmp -s $1 ../$1) then + if (test -z "$2" || test -e ../$2) then + cp $1 .. + if (test $mode = 2) then + echo " updating src/$1" + fi + fi + elif (test -n "$2") then + if (test ! -e ../$2) then + rm -f ../$1 + fi + fi +} -# # arg1 = file, arg2 = file it depends on +# all package files with no dependencies -# action () { -# if (test $mode = 0) then -# rm -f ../$1 -# elif (! cmp -s $1 ../$1) then -# if (test -z "$2" || test -e ../$2) then -# cp $1 .. -# if (test $mode = 2) then -# echo " updating src/$1" -# fi -# fi -# elif (test -n "$2") then -# if (test ! -e ../$2) then -# rm -f ../$1 -# fi -# fi -# } +for file in *.cpp *.h; do + test -f ${file} && action $file +done -# # all package files with no dependencies +# edit 2 Makefile.package files to include/exclude package info -# for file in *.cpp *.h; do -# test -f ${file} && action $file -# done +if (test $1 = 1) then -# # edit 2 Makefile.package files to include/exclude package info + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*pace[^ \t]* //' ../Makefile.package + sed -i -e 's|^PKG_SYSINC =[ \t]*|&$(pace_SYSINC) |' ../Makefile.package + sed -i -e 's|^PKG_SYSLIB =[ \t]*|&$(pace_SYSLIB) |' ../Makefile.package + sed -i -e 's|^PKG_SYSPATH =[ \t]*|&$(pace_SYSPATH) |' ../Makefile.package + fi -# if (test $1 = 1) then + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*pace.*$/d' ../Makefile.package.settings + # multiline form needed for BSD sed on Macs + sed -i -e '4 i \ +include ..\/..\/lib\/pace\/Makefile.lammps +' ../Makefile.package.settings + fi -# if (test -e ../Makefile.package) then -# sed -i -e 's/[^ \t]*kim[^ \t]* //' ../Makefile.package -# sed -i -e 's|^PKG_SYSINC =[ \t]*|&$(kim_SYSINC) |' ../Makefile.package -# sed -i -e 's|^PKG_SYSLIB =[ \t]*|&$(kim_SYSLIB) |' ../Makefile.package -# sed -i -e 's|^PKG_SYSPATH =[ \t]*|&$(kim_SYSPATH) |' ../Makefile.package -# fi +elif (test $1 = 0) then -# if (test -e ../Makefile.package.settings) then -# sed -i -e '/^include.*kim.*$/d' ../Makefile.package.settings -# # multiline form needed for BSD sed on Macs -# sed -i -e '4 i \ -# include ..\/..\/lib\/kim\/Makefile.lammps -# ' ../Makefile.package.settings -# fi + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*pace[^ \t]* //' ../Makefile.package + fi -# elif (test $1 = 0) then + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*pace.*$/d' ../Makefile.package.settings + fi -# if (test -e ../Makefile.package) then -# sed -i -e 's/[^ \t]*kim[^ \t]* //' ../Makefile.package -# fi - -# if (test -e ../Makefile.package.settings) then -# sed -i -e '/^include.*kim.*$/d' ../Makefile.package.settings -# fi - -# fi +fi