diff --git a/CMakeLists.txt b/CMakeLists.txt index 11b6e1c..d3ff20f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,81 +1,110 @@ +# ============================================================================= +# file CMakeLists.txt +# +# @author Till Junge +# +# @date 08 Jan 2018 +# +# @brief Main configuration file +# +# @section LICENCE +# +# Copyright © 2018 Till Junge +# +# µSpectre 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, or (at +# your option) any later version. +# +# µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# ============================================================================= + cmake_minimum_required(VERSION 3.7.0) -project(µSpectre_prototype) +project(µSpectre) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(BUILD_SHARED_LIBS ON) add_compile_options(-Wall -Wextra -Weffc++) enable_testing() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # using Clang add_compile_options(-Wno-missing-braces) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # using GCC string( TOLOWER "${CMAKE_BUILD_TYPE}" build_type ) if ("release" STREQUAL "${build_type}" ) add_compile_options(-march=native) endif() if ("debug" STREQUAL "${build_type}" ) add_compile_options(-O0) endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") # using Intel C++ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # using Visual Studio C++ endif() find_package(Boost COMPONENTS unit_test_framework REQUIRED) find_package(Eigen3 3.3 REQUIRED NO_MODULE) include_directories( tests src ${EIGEN3_INCLUDE_DIRS} ) #find_package(MPI REQUIRED) find_package(FFTW REQUIRED) #find_package(FFTWMPI REQUIRED) #build tests file( GLOB TEST_SRCS "${CMAKE_SOURCE_DIR}/tests/test_*.cc") add_executable(main_test_suite tests/main_test_suite.cc ${TEST_SRCS}) target_link_libraries(main_test_suite ${Boost_LIBRARIES} muSpectre) add_test(main_test_suite main_test_suite --report_level=detailed --build_info=TRUE) #add_test(main_test_suite main_test_suite --build_info=TRUE) # compile the library add_compile_options( -Werror) add_subdirectory( "${CMAKE_SOURCE_DIR}/src/" ) #compile executables file( GLOB binaries "${CMAKE_SOURCE_DIR}/bin/*.cc") foreach(binaryfile ${binaries}) get_filename_component(binaryname ${binaryfile} NAME_WE) add_executable(${binaryname} ${binaryfile}) target_link_libraries(${binaryname} ${Boost_LIBRARIES} muSpectre) endforeach(binaryfile ${binaries}) # compile benchmarks file(GLOB benchmarks "${CMAKE_SOURCE_DIR}/benchmarks/benchmark*cc") foreach(benchmark ${benchmarks}) get_filename_component(benchmark_name ${benchmark} NAME_WE) add_executable(${benchmark_name} ${benchmark}) target_link_libraries(${benchmark_name} ${BOOST_LIBRARIES} muSpectre) endforeach(benchmark ${benchmark}) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..520ea65 --- /dev/null +++ b/LICENSE @@ -0,0 +1,189 @@ +GNU GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright © 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 \ No newline at end of file diff --git a/bin/demonstrator1.cc b/bin/demonstrator1.cc index 1dd4ff2..5fd2edc 100644 --- a/bin/demonstrator1.cc +++ b/bin/demonstrator1.cc @@ -1,141 +1,151 @@ /** * file demonstrator1.cc * * @author Till Junge * * @date 03 Jan 2018 * * @brief larger problem to show off * * @section LICENCE * - * Copyright (C) 2018 Till Junge + * Copyright © 2018 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include "external/cxxopts.hpp" #include "common/common.hh" #include "common/ccoord_operations.hh" #include "system/system_factory.hh" #include "materials/material_hyper_elastic1.hh" #include "solver/solvers.hh" #include "solver/solver_cg.hh" using opt_ptr = std::unique_ptr; opt_ptr parse_args(int argc, char **argv) { opt_ptr options = std::make_unique(argv[0], "Tests MPI fft scalability"); try { options->add_options() ("0,N0", "number of rows", cxxopts::value(), "N0") ("h,help", "print help") ("positional", "Positional arguments: these are the arguments that are entered " "without an option", cxxopts::value>()); options->parse_positional(std::vector{"N0", "positional"}); options->parse(argc, argv); if (options->count("help")) { std::cout << options->help({"", "Group"}) << std::endl; exit(0); } if (options->count("N0") != 1 ) { throw cxxopts::OptionException("Parameter N0 missing"); } else if ((*options)["N0"].as()%2 != 1) { throw cxxopts::OptionException("N0 must be odd"); } else if (options->count("positional") > 0) { throw cxxopts::OptionException("There are too many positional arguments"); } } catch (const cxxopts::OptionException & e) { std::cout << "Error parsing options: " << e.what() << std::endl; exit(1); } return options; } using namespace muSpectre; int main(int argc, char *argv[]) { + + std::cout + << "µSpectre demonstrator1 Copyright © 2018 Till Junge " + << std::endl + << "This program comes with ABSOLUTELY NO WARRANTY." + << std::endl + << "This is free software, and you are welcome to redistribute it" + << std::endl + << "under certain conditions, see the license file." + << std::endl << std::endl; auto options{parse_args(argc, argv)}; auto & opt{*options}; const Dim_t size{opt["N0"].as()}; constexpr Real fsize{1.}; constexpr Dim_t dim{3}; const Dim_t nb_dofs{ipow(size, dim)*ipow(dim, 2)}; std::cout << "Number of dofs: " << nb_dofs << std::endl; constexpr Formulation form{Formulation::finite_strain}; const Rcoord_t lengths{CcoordOps::get_cube(fsize)}; const Ccoord_t resolutions{CcoordOps::get_cube(size)}; auto system{make_system(resolutions, lengths)}; constexpr Real E{1.0030648180242636}; constexpr Real nu{0.29930675909878679}; using Material_t = MaterialHyperElastic1; auto Material_soft{std::make_unique("soft", E, nu)}; auto Material_hard{std::make_unique("hard", 10*E, nu)}; int counter{0}; for (const auto && pixel:system) { int sum = 0; for (Dim_t i = 0; i < dim; ++i) { sum += pixel[i]*2 / resolutions[i]; } if (sum == 0) { Material_hard->add_pixel(pixel); counter ++; } else { Material_soft->add_pixel(pixel); } } std::cout << counter << " Pixel out of " << system.size() << " are in the hard material" << std::endl; system.add_material(std::move(Material_soft)); system.add_material(std::move(Material_hard)); system.initialise(FFT_PlanFlags::measure); constexpr Real newton_tol{1e-4}; constexpr Real cg_tol{1e-7}; const size_t maxiter = nb_dofs; Grad_t DeltaF{Grad_t::Zero()}; DeltaF(0, 1) = .1; Dim_t verbose {1}; auto start = std::chrono::high_resolution_clock::now(); GradIncrements grads{DeltaF}; de_geus(system, grads, form, cg_tol, newton_tol, maxiter, verbose); std::chrono::duration dur = std::chrono::high_resolution_clock::now() - start; std::cout << "Resolution time = " << dur.count() << "s" << std::endl; return 0; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index de78f4e..f20adbd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,19 +1,48 @@ +# ============================================================================= +# file CMakeLists.txt +# +# @author Till Junge +# +# @date 08 Jan 2018 +# +# @brief Configuration for libmuSpectre +# +# @section LICENCE +# +# Copyright © 2018 Till Junge +# +# µSpectre 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, or (at +# your option) any later version. +# +# µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# ============================================================================= + include_directories( common materials system external ) set (muSpectre_SRC ) add_subdirectory(common) add_subdirectory(materials) add_subdirectory(fft) add_subdirectory(system) add_subdirectory(solver) find_package(FFTW REQUIRED) add_library(muSpectre ${muSpectre_SRC}) target_link_libraries(muSpectre Eigen3::Eigen ${FFTW_LIBRARIES}) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 0751144..6da31d3 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,10 +1,39 @@ +# ============================================================================= +# file CMakeLists.txt +# +# @author Till Junge +# +# @date 08 Jan 2018 +# +# @brief configuration for files in common +# +# @section LICENCE +# +# Copyright © 2018 Till Junge +# +# µSpectre 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, or (at +# your option) any later version. +# +# µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# ============================================================================= + set (common_SRC #${CMAKE_CURRENT_SOURCE_DIR}/units.cc ${CMAKE_CURRENT_SOURCE_DIR}/common.cc ${CMAKE_CURRENT_SOURCE_DIR}/voigt_conversion.cc ) set (muSpectre_SRC ${muSpectre_SRC} ${common_SRC} PARENT_SCOPE) diff --git a/src/common/T4_map_proxy.hh b/src/common/T4_map_proxy.hh index 878a418..b00f856 100644 --- a/src/common/T4_map_proxy.hh +++ b/src/common/T4_map_proxy.hh @@ -1,193 +1,193 @@ /** * file T4_map_proxy.hh * * @author Till Junge * * @date 19 Nov 2017 * * @brief Map type to allow fourth-order tensor-like maps on 2D matrices * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef T4_MAP_PROXY_H #define T4_MAP_PROXY_H #include "common/eigen_tools.hh" #include #include #include namespace muSpectre { /** * simple adapter function to create a matrix that can be mapped as a tensor */ template using T4Mat = Eigen::Matrix; template using T4MatMap = std::conditional_t>, Eigen::Map>>; template inline auto get(T4&& t4, Dim_t i, Dim_t j, Dim_t k, Dim_t l) -> decltype(t4.coeffRef(i,j)) { constexpr Dim_t Dim{EigenCheck::tensor_4_dim::value}; const auto myColStride{ (t4.colStride() == 1) ? t4.colStride(): t4.colStride()/Dim}; const auto myRowStride{ (t4.rowStride() == 1) ? t4.rowStride(): t4.rowStride()/Dim}; return t4.coeffRef(i * myRowStride + j * myColStride, k * myRowStride + l * myColStride); } // /* ---------------------------------------------------------------------- */ // /** Proxy class mapping a fourth-order tensor onto a 2D matrix (in // order to avoid the use of Eigen::Tensor. This class is, however // byte-compatible with Tensors (i.e., you can map this onto a // tensor instead of a matrix) // **/ // template > // class T4Map: // public Eigen::MapBase> // { // public: // typedef Eigen::MapBase Base; // EIGEN_DENSE_PUBLIC_INTERFACE(T4Map); // using matrix_type = Eigen::Matrix; // using PlainObjectType = // std::conditional_t; // using ConstType = T4Map; // using Base::colStride; // using Base::rowStride; // using Base::IsRowMajor; // typedef typename Base::PointerType PointerType; // typedef PointerType PointerArgType; // using trueScalar = std::conditional_t; // EIGEN_DEVICE_FUNC // inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } // EIGEN_DEVICE_FUNC // inline Eigen::Index innerStride() const // { // return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; // } // template // inline T4Map & operator=(const Eigen::MatrixBase & other) { // this->map = other; // return *this; // } // EIGEN_DEVICE_FUNC // inline Eigen::Index outerStride() const // { // return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() // : IsVectorAtCompileTime ? this->size() // : int(Flags)&Eigen::RowMajorBit ? this->cols() // : this->rows(); // } // /** Constructor in the fixed-size case. // * // * \param dataPtr pointer to the array to map // * \param stride optional Stride object, passing the strides. // */ // EIGEN_DEVICE_FUNC // explicit inline T4Map(PointerArgType dataPtr, const StrideType& stride = StrideType()) // : Base(cast_to_pointer_type(dataPtr)), m_stride(stride), // map(cast_to_pointer_type(dataPtr)) // { // PlainObjectType::Base::_check_template_params(); // } // EIGEN_INHERIT_ASSIGNMENT_OPERATORS(T4Map); // /** My accessor to mimick tensorial access // **/ // inline const Scalar& operator()(Dim_t i, Dim_t j, Dim_t k, Dim_t l ) const { // const auto myColStride{ // (colStride() == 1) ? colStride(): colStride()/Dim}; // const auto myRowStride{ // (rowStride() == 1) ? rowStride(): rowStride()/Dim}; // return this->map.coeff(i * myRowStride + j * myColStride, // k * myRowStride + l * myColStride); // } // inline trueScalar& operator()(Dim_t i, Dim_t j, Dim_t k, Dim_t l ) { // const auto myColStride{ // (colStride() == 1) ? colStride(): colStride()/Dim}; // const auto myRowStride{ // (rowStride() == 1) ? rowStride(): rowStride()/Dim}; // return this->map.coeffRef(i * myRowStride + j * myColStride, // k * myRowStride + l * myColStride); // } // protected: // StrideType m_stride; // Eigen::Map map; // }; } // muSpectre // namespace Eigen { // //! forward declarations // template struct traits; // /* ---------------------------------------------------------------------- */ // namespace internal { // template // struct traits > // : public traits> // { // using PlainObjectType = Matrix; // typedef traits TraitsBase; // enum { // InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 // ? int(PlainObjectType::InnerStrideAtCompileTime) // : int(StrideType::InnerStrideAtCompileTime), // OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 // ? int(PlainObjectType::OuterStrideAtCompileTime) // : int(StrideType::OuterStrideAtCompileTime), // Alignment = int(MapOptions)&int(AlignedMask), // Flags0 = TraitsBase::Flags & (~NestByRefBit), // Flags = is_lvalue::value ? int(Flags0) : (int(Flags0) & ~LvalueBit) // }; // private: // enum { Options }; // Expressions don't have Options // }; // } // namespace internal // } // namespace Eigen #endif /* T4_MAP_PROXY_H */ diff --git a/src/common/ccoord_operations.hh b/src/common/ccoord_operations.hh index fa7aa69..a4a7dd1 100644 --- a/src/common/ccoord_operations.hh +++ b/src/common/ccoord_operations.hh @@ -1,267 +1,267 @@ /** * file ccoord_operations.hh * * @author Till Junge * * @date 29 Sep 2017 * * @brief common operations on pixel addressing * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "common/common.hh" #include "common/iterators.hh" #ifndef CCOORD_OPERATIONS_H #define CCOORD_OPERATIONS_H namespace muSpectre { namespace CcoordOps { namespace internal { template constexpr T ret(T val, size_t /*dummy*/) {return val;} template constexpr std::array cube_fun(T val, std::index_sequence) { return std::array{ret(val, I)...}; } template constexpr Ccoord_t herm(const Ccoord_t & full_sizes, std::index_sequence) { return Ccoord_t{full_sizes[I]..., (full_sizes.back()+1)/2}; } template constexpr Dim_t stride(const Ccoord_t & sizes, const size_t index) { static_assert(Dim > 0, "only for positive numbers of dimensions"); auto const diff{Dim - 1 - Dim_t(index)}; Dim_t ret_val{1}; for (Dim_t i{0}; i < diff; ++i) { ret_val *= sizes[Dim-1-i]; } return ret_val; } template constexpr Ccoord_t compute_strides(const Ccoord_t & sizes, std::index_sequence) { return Ccoord_t{stride(sizes, I)...}; } } // internal //----------------------------------------------------------------------------// template constexpr std::array get_cube(T size) { return internal::cube_fun(size, std::make_index_sequence{}); } /* ---------------------------------------------------------------------- */ template constexpr Ccoord_t get_hermitian_sizes(Ccoord_t full_sizes) { return internal::herm(full_sizes, std::make_index_sequence{}); } /* ---------------------------------------------------------------------- */ template Eigen::Matrix get_vector(const Ccoord_t & ccoord, Real pix_size = 1.) { Eigen::Matrix retval; for (size_t i = 0; i < dim; ++i) { retval[i] = pix_size * ccoord[i]; } return retval; } /* ---------------------------------------------------------------------- */ template Eigen::Matrix get_vector(const Ccoord_t & ccoord, Eigen::Matrix pix_size) { Eigen::Matrix retval = pix_size; for (size_t i = 0; i < dim; ++i) { retval[i] *= ccoord[i]; } return retval; } /* ---------------------------------------------------------------------- */ template Eigen::Matrix get_vector(const Ccoord_t & ccoord, const std::array& pix_size) { Eigen::Matrix retval{}; for (size_t i = 0; i < dim; ++i) { retval[i] = pix_size[i]*ccoord[i]; } return retval; } /* ---------------------------------------------------------------------- */ template constexpr Ccoord_t get_default_strides(const Ccoord_t & sizes) { return internal::compute_strides(sizes, std::make_index_sequence{}); } //----------------------------------------------------------------------------// template constexpr Ccoord_t get_ccoord(const Ccoord_t & sizes, Dim_t index) { Ccoord_t retval{{0}}; Dim_t factor{1}; for (Dim_t i = dim-1; i >=0; --i) { retval[i] = index/factor%sizes[i]; if (i != 0 ) { factor *= sizes[i]; } } return retval; } //----------------------------------------------------------------------------// template constexpr Dim_t get_index(const Ccoord_t & sizes, const Ccoord_t & ccoord) { Dim_t retval{0}; Dim_t factor{1}; for (Dim_t i = dim-1; i >=0; --i) { retval += ccoord[i]*factor; if (i != 0) { factor *= sizes[i]; } } return retval; } //----------------------------------------------------------------------------// template constexpr Dim_t get_index_from_strides(const Ccoord_t & strides, const Ccoord_t & ccoord) { Dim_t retval{0}; for (const auto & tup: akantu::zip(strides, ccoord)) { const auto & stride = std::get<0>(tup); const auto & ccord_ = std::get<1>(tup); retval += stride * ccord_; } return retval; } //----------------------------------------------------------------------------// template constexpr size_t get_size(const Ccoord_t& sizes) { Dim_t retval{1}; for (size_t i = 0; i < dim; ++i) { retval *= sizes[i]; } return retval; } //----------------------------------------------------------------------------// template constexpr size_t get_size_from_strides(const Ccoord_t& sizes, const Ccoord_t& strides) { return sizes[0]*strides[0]; } /* ---------------------------------------------------------------------- */ template class Pixels { public: Pixels(const Ccoord_t & sizes=Ccoord_t{}):sizes(sizes){}; Pixels(const Pixels & other) = default; Pixels & operator=(const Pixels & other) = default; virtual ~Pixels() = default; class iterator { public: using value_type = Ccoord_t; using const_value_type = const value_type; using pointer = value_type*; using difference_type = std::ptrdiff_t; using iterator_category = std::forward_iterator_tag; using reference = value_type; iterator(const Pixels & pixels, bool begin=true); virtual ~iterator() = default; inline value_type operator*() const; inline iterator & operator++(); inline bool operator!=(const iterator & other) const; inline bool operator==(const iterator & other) const; protected: const Pixels& pixels; size_t index; }; inline iterator begin() const {return iterator(*this);} inline iterator end() const {return iterator(*this, false);} inline size_t size() const {return get_size(this->sizes);} protected: Ccoord_t sizes; }; /* ---------------------------------------------------------------------- */ template Pixels::iterator::iterator(const Pixels & pixels, bool begin) :pixels{pixels}, index{begin? 0: get_size(pixels.sizes)} {} /* ---------------------------------------------------------------------- */ template typename Pixels::iterator::value_type Pixels::iterator::operator*() const { return get_ccoord(pixels.sizes, this->index); } /* ---------------------------------------------------------------------- */ template bool Pixels::iterator::operator!=(const iterator &other) const { return (this->index != other.index) || (&this->pixels != &other.pixels); } /* ---------------------------------------------------------------------- */ template bool Pixels::iterator::operator==(const iterator &other) const { return !(*this!= other); } /* ---------------------------------------------------------------------- */ template typename Pixels::iterator& Pixels::iterator::operator++() { ++this->index; return *this; } } // CcoordOps } // muSpectre #endif /* CCOORD_OPERATIONS_H */ diff --git a/src/common/common.cc b/src/common/common.cc index 2759b7d..89f3fcb 100644 --- a/src/common/common.cc +++ b/src/common/common.cc @@ -1,85 +1,85 @@ /** * file common.cc * * @author Till Junge * * @date 15 Nov 2017 * * @brief Implementation for common functions * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "common/common.hh" #include namespace muSpectre { /* ---------------------------------------------------------------------- */ std::ostream & operator<<(std::ostream & os, Formulation f) { switch (f) { case Formulation::small_strain: {os << "small_strain"; break;} case Formulation::finite_strain: {os << "finite_strain"; break;} default: throw std::runtime_error ("unknown formulation."); break; } return os; } /* ---------------------------------------------------------------------- */ std::ostream & operator<<(std::ostream & os, StressMeasure s) { switch (s) { case StressMeasure::Cauchy: {os << "Cauchy"; break;} case StressMeasure::PK1: {os << "PK1"; break;} case StressMeasure::PK2: {os << "PK2"; break;} case StressMeasure::Kirchhoff: {os << "Kirchhoff"; break;} case StressMeasure::Biot: {os << "Biot"; break;} case StressMeasure::Mandel: {os << "Mandel"; break;} default: throw std::runtime_error ("a stress measure must be missing"); break; } return os; } /* ---------------------------------------------------------------------- */ std::ostream & operator<<(std::ostream & os, StrainMeasure s) { switch (s) { case StrainMeasure::Gradient: {os << "Gradient"; break;} case StrainMeasure::Infinitesimal: {os << "Infinitesimal"; break;} case StrainMeasure::GreenLagrange: {os << "Green-Lagrange"; break;} case StrainMeasure::Biot: {os << "Biot"; break;} case StrainMeasure::Log: {os << "Logarithmic"; break;} case StrainMeasure::Almansi: {os << "Almansi"; break;} case StrainMeasure::RCauchyGreen: {os << "Right Cauchy-Green"; break;} case StrainMeasure::LCauchyGreen: {os << "Left Cauchy-Green"; break;} default: throw std::runtime_error ("a strain measure must be missing"); } return os; } } // muSpectre diff --git a/src/common/common.hh b/src/common/common.hh index 62f0c19..0057ed0 100644 --- a/src/common/common.hh +++ b/src/common/common.hh @@ -1,194 +1,194 @@ /** * file common.hh * * @author Till Junge * * @date 01 May 2017 * * @brief Small definitions of commonly used types througout µSpectre * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #ifndef COMMON_H #define COMMON_H namespace muSpectre { //! Eigen uses signed integers for dimensions. For consistency, µSpectre uses //! them througout the code using Dim_t = int;// needs to represent -1 for eigen constexpr Dim_t oneD{1}; constexpr Dim_t twoD{2}; constexpr Dim_t threeD{3}; constexpr Dim_t firstOrder{1}; constexpr Dim_t secondOrder{2}; constexpr Dim_t fourthOrder{4}; //! Scalar types used for mathematical calculations using Uint = unsigned int; using Int = int; using Real = double; using Complex = std::complex; //! Ccoord_t are cell coordinates, i.e. integer coordinates template using Ccoord_t = std::array; //! Real space coordinates template using Rcoord_t = std::array; template std::ostream & operator << (std::ostream & os, const std::array & index) { os << "("; for (size_t i = 0; i < dim-1; ++i) { os << index[i] << ", "; } os << index.back() << ")"; return os; } template Rcoord_t operator/(const Rcoord_t & a, const Rcoord_t & b) { Rcoord_t retval{a}; for (size_t i = 0; i < dim; ++i) { retval[i]/=b[i]; } return retval; } template Rcoord_t operator/(const Rcoord_t & a, const Ccoord_t & b) { Rcoord_t retval{a}; for (size_t i = 0; i < dim; ++i) { retval[i]/=b[i]; } return retval; } //! convenience definitions constexpr Real pi{3.1415926535897932384626433}; //! compile-time potentiation required for field-size computations template constexpr R ipow(R base, I exponent) { static_assert(std::is_integral::value, "Type must be integer"); R retval{1}; for (I i = 0; i < exponent; ++i) { retval *= base; } return retval; } //! continuum mechanics flags enum class Formulation{finite_strain, small_strain}; std::ostream & operator<<(std::ostream & os, Formulation f); /* ---------------------------------------------------------------------- */ //! Material laws can declare which type of stress measure they provide, //! and µSpectre will handle conversions enum class StressMeasure { Cauchy, PK1, PK2, Kirchhoff, Biot, Mandel, __nostress__}; std::ostream & operator<<(std::ostream & os, StressMeasure s); /* ---------------------------------------------------------------------- */ //! Material laws can declare which type of strain measure they require and //! µSpectre will provide it enum class StrainMeasure { Gradient, Infinitesimal, GreenLagrange, Biot, Log, Almansi, RCauchyGreen, LCauchyGreen, __nostrain__}; std::ostream & operator<<(std::ostream & os, StrainMeasure s); /* ---------------------------------------------------------------------- */ /** Compile-time functions to set the stress and strain measures stored by mu_spectre depending on the formulation **/ constexpr StrainMeasure get_stored_strain_type(Formulation form) { switch (form) { case Formulation::finite_strain: { return StrainMeasure::Gradient; break; } case Formulation::small_strain: { return StrainMeasure::Infinitesimal; break; } default: return StrainMeasure::__nostrain__; break; } } constexpr StressMeasure get_stored_stress_type(Formulation form) { switch (form) { case Formulation::finite_strain: { return StressMeasure::PK1; break; } case Formulation::small_strain: { return StressMeasure::Cauchy; break; } default: return StressMeasure::__nostress__; break; } } /* ---------------------------------------------------------------------- */ /** Compile-time functions to get the stress and strain measures after they may have been modified by choosing a formulation. For instance, a law that expecs a Green-Lagrange strain as input will get the infinitesimal strain tensor instead in a small strain computation **/ constexpr StrainMeasure get_formulation_strain_type(Formulation form, StrainMeasure expected) { switch (form) { case Formulation::finite_strain: { return expected; break; } case Formulation::small_strain: { return get_stored_strain_type(form); break; } default: return StrainMeasure::__nostrain__; break; } } } // muSpectre #ifndef EXPLICITLY_TURNED_ON_CXX17 #include "common/utilities.hh" #endif #endif /* COMMON_H */ diff --git a/src/common/eigen_tools.hh b/src/common/eigen_tools.hh index b7bb3c3..f587e19 100644 --- a/src/common/eigen_tools.hh +++ b/src/common/eigen_tools.hh @@ -1,166 +1,166 @@ /** * file eigen_tools.hh * * @author Till Junge * * @date 20 Sep 2017 * * @brief small tools to be used with Eigen * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef EIGEN_TOOLS_H #define EIGEN_TOOLS_H #include "common/common.hh" #include #include #include namespace muSpectre { /* ---------------------------------------------------------------------- */ //! Creates a Eigen::Sizes type for a Tensor defined by an order and dim namespace internal { template struct SizesByOrderHelper { using Sizes = typename SizesByOrderHelper::Sizes; }; template struct SizesByOrderHelper<0, dim, dims...> { using Sizes = Eigen::Sizes; }; } // internal template struct SizesByOrder { static_assert(order > 0, "works only for order greater than zero"); using Sizes = typename internal::SizesByOrderHelper::Sizes; }; /* ---------------------------------------------------------------------- */ //! Call a passed lambda with the unpacked sizes as arguments namespace internal { /* ---------------------------------------------------------------------- */ template struct CallSizesHelper { static decltype(auto) call(Fun_t && fun) { static_assert(order > 0, "can't handle empty sizes b)"); return CallSizesHelper::call (fun); } }; /* ---------------------------------------------------------------------- */ template struct CallSizesHelper<0, Fun_t, dim, args...> { static decltype(auto) call(Fun_t && fun) { return fun(args...); } }; } // internal template inline decltype(auto) call_sizes(Fun_t && fun) { static_assert(order > 1, "can't handle empty sizes"); return internal::CallSizesHelper:: call(std::forward(fun)); } //compile-time square root static constexpr Dim_t ct_sqrt(Dim_t res, Dim_t l, Dim_t r){ if(l == r){ return r; } else { const auto mid = (r + l) / 2; if(mid * mid >= res){ return ct_sqrt(res, l, mid); } else { return ct_sqrt(res, mid + 1, r); } } } static constexpr Dim_t ct_sqrt(Dim_t res){ return ct_sqrt(res, 1, res); } /** * Structure to determine whether an expression can be evaluated into a Matrix, Array, etc. and which helps determine compile-time size */ namespace EigenCheck { template struct is_matrix { using T = std::remove_reference_t; constexpr static bool value{std::is_same::XprKind, Eigen::MatrixXpr>::value}; }; template struct is_fixed { using T = std::remove_reference_t; constexpr static bool value{T::SizeAtCompileTime != Eigen::Dynamic}; }; template struct is_square { using T = std::remove_reference_t; constexpr static bool value{ (T::RowsAtCompileTime == T::ColsAtCompileTime) && is_fixed::value}; }; template struct tensor_dim { using T = std::remove_reference_t; static_assert(is_matrix::value, "The type of t is not understood as an Eigen::Matrix"); static_assert(is_square::value, "t's matrix isn't square"); constexpr static Dim_t value{T::RowsAtCompileTime}; }; template struct tensor_4_dim { using T = std::remove_reference_t; static_assert(is_matrix::value, "The type of t is not understood as an Eigen::Matrix"); static_assert(is_square::value, "t's matrix isn't square"); constexpr static Dim_t value{ct_sqrt(T::RowsAtCompileTime)}; static_assert(value*value == T::RowsAtCompileTime, "This is not a fourth-order tensor mapped on a square " "matrix"); }; }; } // muSpectre #endif /* EIGEN_TOOLS_H */ diff --git a/src/common/field.hh b/src/common/field.hh index d2f4701..1ef3565 100644 --- a/src/common/field.hh +++ b/src/common/field.hh @@ -1,728 +1,728 @@ /** * file field.hh * * @author Till Junge * * @date 07 Sep 2017 * * @brief header-only implementation of a field for field collections * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_H #define FIELD_H #include "common/T4_map_proxy.hh" #include #include #include #include #include #include #include #include #include #include namespace muSpectre { /* ---------------------------------------------------------------------- */ class FieldCollectionError: public std::runtime_error { public: explicit FieldCollectionError(const std::string& what) :std::runtime_error(what){} explicit FieldCollectionError(const char * what) :std::runtime_error(what){} }; class FieldError: public FieldCollectionError { using Parent = FieldCollectionError; public: explicit FieldError(const std::string& what) :Parent(what){} explicit FieldError(const char * what) :Parent(what){} }; class FieldInterpretationError: public FieldError { public: explicit FieldInterpretationError(const std::string & what) :FieldError(what){} explicit FieldInterpretationError(const char * what) :FieldError(what){} }; namespace internal { /* ---------------------------------------------------------------------- */ template class FieldBase { protected: //! constructor //! unique name (whithin Collection) //! number of components //! collection to which this field belongs (eg, material, system) FieldBase(std::string unique_name, size_t nb_components, FieldCollection & collection); public: using collection_t = FieldCollection; //! Copy constructor FieldBase(const FieldBase &other) = delete; //! Move constructor FieldBase(FieldBase &&other) noexcept = delete; //! Destructor virtual ~FieldBase() noexcept = default; //! Copy assignment operator FieldBase& operator=(const FieldBase &other) = delete; //! Move assignment operator FieldBase& operator=(FieldBase &&other) noexcept = delete; /* ---------------------------------------------------------------------- */ //!Identifying accessors //! return field name inline const std::string & get_name() const; //! return field type //inline const Field_t & get_type() const; //! return my collection (for iterating) inline const FieldCollection & get_collection() const; //! return my collection (for iterating) inline const size_t & get_nb_components() const; //! return type_id of stored type virtual const std::type_info & get_stored_typeid() const = 0; virtual size_t size() const = 0; //! initialise field to zero (do more complicated initialisations through //! fully typed maps) virtual void set_zero() = 0; //! give access to collections friend FieldCollection; friend typename FieldCollection::Parent; protected: /* ---------------------------------------------------------------------- */ //! allocate memory etc virtual void resize(size_t size) = 0; const std::string name; const size_t nb_components; const FieldCollection & collection; private: }; /* ---------------------------------------------------------------------- */ //! declaraton for friending template class FieldMap; /* ---------------------------------------------------------------------- */ template class TypedFieldBase: public FieldBase { friend class FieldMap; friend class FieldMap; public: constexpr static auto nb_components{NbComponents}; using Parent = FieldBase; using collection_t = typename Parent::collection_t; using Scalar = T; using Base = Parent; //using storage_type = Eigen::Array; using StoredType = Eigen::Array; using StorageType = std::conditional_t >, std::vector>>; using EigenRep = Eigen::Array; using EigenMap = std::conditional_t< ArrayStore, Eigen::Map>, Eigen::Map>; using ConstEigenMap = std::conditional_t< ArrayStore, Eigen::Map>, Eigen::Map>; TypedFieldBase(std::string unique_name, FieldCollection& collection); virtual ~TypedFieldBase() = default; //! return type_id of stored type virtual const std::type_info & get_stored_typeid() const override final; //! initialise field to zero (do more complicated initialisations through //! fully typed maps) inline void set_zero() override final; template inline void push_back(const std::enable_if_t & value); template inline std::enable_if_t push_back(const StoredType & value); //! Number of stored arrays (i.e. total number of stored //! scalars/NbComponents) size_t size() const override final; static TypedFieldBase & check_ref(Parent & other); static const TypedFieldBase & check_ref(const Base & parent); inline T* data() {return this->get_ptr_to_entry(0);} inline const T* data() const {return this->get_ptr_to_entry(0);} inline EigenMap eigen(); inline ConstEigenMap eigen() const; template inline Real inner_product(const TypedFieldBase & other) const; protected: template inline std::enable_if_t get_ptr_to_entry(const size_t&& index); template inline std::enable_if_t get_ptr_to_entry(const size_t&& index) const; template inline T* get_ptr_to_entry(std::enable_if_t index); template inline const T* get_ptr_to_entry(std::enable_if_t index) const; inline virtual void resize(size_t size) override final; StorageType values{}; }; } // internal /* ---------------------------------------------------------------------- */ template class TensorField: public internal::TypedFieldBase { public: using Parent = internal::TypedFieldBase; using Base = typename Parent::Base; using Field_p = typename FieldCollection::Field_p; using component_type = T; using Scalar = typename Parent::Scalar; //! Copy constructor TensorField(const TensorField &other) = delete; //! Move constructor TensorField(TensorField &&other) noexcept = delete; //! Destructor virtual ~TensorField() noexcept = default; //! Copy assignment operator TensorField& operator=(const TensorField &other) = delete; //! Move assignment operator TensorField& operator=(TensorField &&other) noexcept = delete; //! accessors inline Dim_t get_order() const; inline Dim_t get_dim() const; //! factory function template friend FieldType& make_field(std::string unique_name, CollectionType & collection, Args&&... args); static TensorField & check_ref(Base & other) { return static_cast(Parent::check_ref(other));} static const TensorField & check_ref(const Base & other) { return static_cast(Parent::check_ref(other));} /** * Pure convenience functions to get a MatrixFieldMap of * appropriate dimensions mapped to this field. You can also * create other types of maps, as long as they have the right * fundamental type (T) and the correct size (nbComponents). */ decltype(auto) get_map(); decltype(auto) get_map() const; protected: //! constructor protected! TensorField(std::string unique_name, FieldCollection & collection); private: }; /* ---------------------------------------------------------------------- */ template class MatrixField: public internal::TypedFieldBase { public: using Parent = internal::TypedFieldBase; using Base = typename Parent::Base; using Field_p = std::unique_ptr>; using component_type = T; //! Copy constructor MatrixField(const MatrixField &other) = delete; //! Move constructor MatrixField(MatrixField &&other) noexcept = delete; //! Destructor virtual ~MatrixField() noexcept = default; //! Copy assignment operator MatrixField& operator=(const MatrixField &other) = delete; //! Move assignment operator MatrixField& operator=(MatrixField &&other) noexcept = delete; //! accessors inline Dim_t get_nb_row() const; inline Dim_t get_nb_col() const; //! factory function template friend FieldType& make_field(std::string unique_name, CollectionType & collection, Args&&... args); static MatrixField & check_ref(Base & other) { return static_cast(Parent::check_ref(other));} static const MatrixField & check_ref(const Base & other) { return static_cast(Parent::check_ref(other));} decltype(auto) get_map(); decltype(auto) get_map() const; protected: //! constructor protected! MatrixField(std::string unique_name, FieldCollection & collection); private: }; /* ---------------------------------------------------------------------- */ //! convenience alias ( template using ScalarField = MatrixField; /* ---------------------------------------------------------------------- */ // Implementations namespace internal { /* ---------------------------------------------------------------------- */ template FieldBase::FieldBase(std::string unique_name, size_t nb_components_, FieldCollection & collection_) :name(unique_name), nb_components(nb_components_), collection(collection_) {} /* ---------------------------------------------------------------------- */ template inline const std::string & FieldBase::get_name() const { return this->name; } /* ---------------------------------------------------------------------- */ template inline const FieldCollection & FieldBase:: get_collection() const { return this->collection; } /* ---------------------------------------------------------------------- */ template inline const size_t & FieldBase:: get_nb_components() const { return this->nb_components; } /* ---------------------------------------------------------------------- */ template TypedFieldBase:: TypedFieldBase(std::string unique_name, FieldCollection & collection) :FieldBase(unique_name, NbComponents, collection){ static_assert ((std::is_arithmetic::value || std::is_same::value), "Use TypedFieldBase for integer, real or complex scalars for T"); static_assert(NbComponents > 0, "Only fields with more than 0 components"); } /* ---------------------------------------------------------------------- */ //! return type_id of stored type template const std::type_info & TypedFieldBase:: get_stored_typeid() const { return typeid(T); } /* ---------------------------------------------------------------------- */ template void TypedFieldBase:: set_zero() { std::fill(this->values.begin(), this->values.end(), T{}); } /* ---------------------------------------------------------------------- */ template size_t TypedFieldBase:: size() const { if (ArrayStore) { return this->values.size(); } else { return this->values.size()/NbComponents; } } /* ---------------------------------------------------------------------- */ template TypedFieldBase & TypedFieldBase:: check_ref(Base & other) { if (typeid(T).hash_code() != other.get_stored_typeid().hash_code()) { std::string err ="Cannot create a Reference of requested type " +( "for field '" + other.get_name() + "' of type '" + other.get_stored_typeid().name() + "'"); throw std::runtime_error (err); } //check size compatibility if (NbComponents != other.get_nb_components()) { throw std::runtime_error ("Cannot create a Reference to a field with " + std::to_string(NbComponents) + " components " + "for field '" + other.get_name() + "' with " + std::to_string(other.get_nb_components()) + " components"); } return static_cast(other); } /* ---------------------------------------------------------------------- */ template const TypedFieldBase & TypedFieldBase:: check_ref(const Base & other) { if (typeid(T).hash_code() != other.get_stored_typeid().hash_code()) { std::stringstream err_str{}; err_str << "Cannot create a Reference of requested type " << "for field '" << other.get_name() << "' of type '" << other.get_stored_typeid().name() << "'"; throw std::runtime_error (err_str.str()); } //check size compatibility if (NbComponents != other.get_nb_components()) { throw std::runtime_error ("Cannot create a Reference to a field with " + std::to_string(NbComponents) + " components " + "for field '" + other.get_name() + "' with " + std::to_string(other.get_nb_components()) + " components"); } return static_cast(other); } /* ---------------------------------------------------------------------- */ template typename TypedFieldBase::EigenMap TypedFieldBase:: eigen() { return EigenMap(this->data(), NbComponents, this->size()); } /* ---------------------------------------------------------------------- */ template typename TypedFieldBase::ConstEigenMap TypedFieldBase:: eigen() const { return ConstEigenMap(this->data(), NbComponents, this->size()); } /* ---------------------------------------------------------------------- */ template template Real TypedFieldBase:: inner_product(const TypedFieldBase & other) const { return (this->eigen() * other.eigen()).sum(); } /* ---------------------------------------------------------------------- */ template template std::enable_if_t TypedFieldBase:: get_ptr_to_entry(const size_t&& index) { static_assert (isArray == ArrayStore, "SFINAE"); return &this->values[std::move(index)](0, 0); } /* ---------------------------------------------------------------------- */ template template T* TypedFieldBase:: get_ptr_to_entry(std::enable_if_t index) { static_assert (noArray != ArrayStore, "SFINAE"); return &this->values[NbComponents*std::move(index)]; } /* ---------------------------------------------------------------------- */ template template std::enable_if_t TypedFieldBase:: get_ptr_to_entry(const size_t&& index) const { static_assert (isArray == ArrayStore, "SFINAE"); return &this->values[std::move(index)](0, 0); } /* ---------------------------------------------------------------------- */ template template const T* TypedFieldBase:: get_ptr_to_entry(std::enable_if_t index) const { static_assert (noArray != ArrayStore, "SFINAE"); return &this->values[NbComponents*std::move(index)]; } /* ---------------------------------------------------------------------- */ template void TypedFieldBase:: resize(size_t size) { if (ArrayStore) { this->values.resize(size); } else { this->values.resize(size*NbComponents); } } /* ---------------------------------------------------------------------- */ template template void TypedFieldBase:: push_back(const std::enable_if_t & value) { static_assert(isArrayStore == ArrayStore, "SFINAE"); this->values.push_back(value); } /* ---------------------------------------------------------------------- */ template template std::enable_if_t TypedFieldBase:: push_back(const StoredType & value) { static_assert(componentStore != ArrayStore, "SFINAE"); for (Dim_t i = 0; i < NbComponents; ++i) { this->values.push_back(value(i)); } } } // internal /* ---------------------------------------------------------------------- */ //! Factory function, guarantees that only fields get created that are //! properly registered and linked to a collection. template FieldType & make_field(std::string unique_name, FieldCollection & collection, Args&&... args) { auto ptr = std::unique_ptr{ new FieldType(unique_name, collection, args...)}; auto& retref = *ptr; collection.register_field(std::move(ptr)); return retref; } /* ---------------------------------------------------------------------- */ template TensorField:: TensorField(std::string unique_name, FieldCollection & collection) :Parent(unique_name, collection) {} /* ---------------------------------------------------------------------- */ template Dim_t TensorField:: get_order() const { return order; } /* ---------------------------------------------------------------------- */ template Dim_t TensorField:: get_dim() const { return dim; } /* ---------------------------------------------------------------------- */ template MatrixField:: MatrixField(std::string unique_name, FieldCollection & collection) :Parent(unique_name, collection) {} /* ---------------------------------------------------------------------- */ template Dim_t MatrixField:: get_nb_col() const { return NbCol; } /* ---------------------------------------------------------------------- */ template Dim_t MatrixField:: get_nb_row() const { return NbRow; } } // muSpectre #include "common/field_map.hh" namespace muSpectre { namespace internal { /* ---------------------------------------------------------------------- */ template struct tensor_map_type { }; template struct tensor_map_type { using type = MatrixFieldMap; }; template struct tensor_map_type { using type = MatrixFieldMap; }; template struct tensor_map_type { using type = T4MatrixFieldMap; }; /* ---------------------------------------------------------------------- */ template struct matrix_map_type { using type = MatrixFieldMap; }; template struct matrix_map_type { using type = ScalarFieldMap; }; } // internal /* ---------------------------------------------------------------------- */ template decltype(auto) TensorField:: get_map() { constexpr bool map_constness{false}; using RawMap_t = typename internal::tensor_map_type::type; return RawMap_t(*this); } /* ---------------------------------------------------------------------- */ template decltype(auto) TensorField:: get_map() const { constexpr bool map_constness{true}; using RawMap_t = typename internal::tensor_map_type::type; return RawMap_t(*this); } /* ---------------------------------------------------------------------- */ template decltype(auto) MatrixField:: get_map() { constexpr bool map_constness{false}; using RawMap_t = typename internal::matrix_map_type::type; return RawMap_t(*this); } /* ---------------------------------------------------------------------- */ template decltype(auto) MatrixField:: get_map() const { constexpr bool map_constness{true}; using RawMap_t = typename internal::matrix_map_type::type; return RawMap_t(*this); } } // muSpectre #endif /* FIELD_H */ diff --git a/src/common/field_collection.hh b/src/common/field_collection.hh index 8842f73..f9680ac 100644 --- a/src/common/field_collection.hh +++ b/src/common/field_collection.hh @@ -1,48 +1,48 @@ /** * file field_collection.hh * * @author Till Junge * * @date 07 Sep 2017 * * @brief Provides pixel-iterable containers for scalar and tensorial fields, * addressable by field name * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_COLLECTION_H #define FIELD_COLLECTION_H #include "common/field_collection_global.hh" #include "common/field_collection_local.hh" namespace muSpectre { template using FieldCollection = std::conditional_t< Global, GlobalFieldCollection, LocalFieldCollection>; } // muSpectre #endif /* FIELD_COLLECTION_H */ diff --git a/src/common/field_collection_base.hh b/src/common/field_collection_base.hh index d78d2b4..35295c5 100644 --- a/src/common/field_collection_base.hh +++ b/src/common/field_collection_base.hh @@ -1,162 +1,162 @@ /** * file field_collection_base.hh * * @author Till Junge * * @date 05 Nov 2017 * * @brief Base class for field collections * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_COLLECTION_BASE_H #define FIELD_COLLECTION_BASE_H #include "common/common.hh" #include "common/field.hh" #include #include namespace muSpectre { /* ---------------------------------------------------------------------- */ //! DimS spatial dimension (dimension of problem) //! DimM material_dimension (dimension of constitutive law) template class FieldCollectionBase { public: using Field = internal::FieldBase; using Field_p = std::unique_ptr; using Ccoord = Ccoord_t; //! Default constructor FieldCollectionBase(); //! Copy constructor FieldCollectionBase(const FieldCollectionBase &other) = delete; //! Move constructor FieldCollectionBase(FieldCollectionBase &&other) noexcept = default; //! Destructor virtual ~FieldCollectionBase() noexcept = default; //! Copy assignment operator FieldCollectionBase& operator=(const FieldCollectionBase &other) = delete; //! Move assignment operator FieldCollectionBase& operator=(FieldCollectionBase &&other) noexcept = default; //! Register a new field (fields need to be in heap, so I want to keep them //! as shared pointers void register_field(Field_p&& field); //! for return values of iterators constexpr inline static Dim_t spatial_dim(); //! for return values of iterators inline Dim_t get_spatial_dim() const; //! retrieve field by unique_name inline Field& operator[](std::string unique_name); //! retrieve field by unique_name with bounds checking inline Field& at(std::string unique_name); //! returns size of collection, this refers to the number of pixels handled //! by the collection, not the number of fields inline size_t size() const {return this->size_;} protected: std::map fields{}; bool is_initialised{false}; const Uint id; static Uint counter; size_t size_{0}; private: }; /* ---------------------------------------------------------------------- */ template Uint FieldCollectionBase::counter{0}; /* ---------------------------------------------------------------------- */ template FieldCollectionBase::FieldCollectionBase() :id(counter++){} /* ---------------------------------------------------------------------- */ template void FieldCollectionBase::register_field(Field_p &&field) { auto&& search_it = this->fields.find(field->get_name()); auto&& does_exist = search_it != this->fields.end(); if (does_exist) { std::stringstream err_str; err_str << "a field named " << field->get_name() << "is already registered in this field collection. " << "Currently registered fields: "; for (const auto& name_field_pair: this->fields) { err_str << ", " << name_field_pair.first; } throw FieldCollectionError(err_str.str()); } if (this->is_initialised) { field->resize(this->size()); } this->fields[field->get_name()] = std::move(field); } /* ---------------------------------------------------------------------- */ template constexpr Dim_t FieldCollectionBase:: spatial_dim() { return DimS; } /* ---------------------------------------------------------------------- */ template Dim_t FieldCollectionBase:: get_spatial_dim() const { return DimS; } /* ---------------------------------------------------------------------- */ template typename FieldCollectionBase::Field& FieldCollectionBase:: operator[](std::string unique_name) { return *(this->fields[unique_name]); } /* ---------------------------------------------------------------------- */ template typename FieldCollectionBase::Field& FieldCollectionBase:: at(std::string unique_name) { return *(this->fields.at(unique_name)); } } // muSpectre #endif /* FIELD_COLLECTION_BASE_H */ diff --git a/src/common/field_collection_global.hh b/src/common/field_collection_global.hh index 63e4b85..57fe34a 100644 --- a/src/common/field_collection_global.hh +++ b/src/common/field_collection_global.hh @@ -1,192 +1,192 @@ /** * file field_collection_global.hh * * @author Till Junge * * @date 05 Nov 2017 * * @brief FieldCollection base-class for global fields * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_COLLECTION_GLOBAL_H #define FIELD_COLLECTION_GLOBAL_H #include "common/field_collection_base.hh" #include "common/ccoord_operations.hh" namespace muSpectre { /* ---------------------------------------------------------------------- */ //! DimS spatial dimension (dimension of problem) //! DimM material_dimension (dimension of constitutive law) template class GlobalFieldCollection: public FieldCollectionBase> { public: using Parent = FieldCollectionBase >; using Ccoord = typename Parent::Ccoord; using Field_p = typename Parent::Field_p; using iterator = typename CcoordOps::Pixels::iterator; //! Default constructor GlobalFieldCollection(); //! Copy constructor GlobalFieldCollection(const GlobalFieldCollection &other) = delete; //! Move constructor GlobalFieldCollection (GlobalFieldCollection &&other) noexcept = default; //! Destructor virtual ~GlobalFieldCollection() noexcept = default; //! Copy assignment operator GlobalFieldCollection& operator=(const GlobalFieldCollection &other) = delete; //! Move assignment operator GlobalFieldCollection& operator=(GlobalFieldCollection &&other) = default; /** allocate memory, etc. At this point, the collection is informed aboud the size and shape of the domain (through the sizes parameter). The job of initialise is to make sure that all fields are either of size 0, in which case they need to be allocated, or are of the same size as the product of 'sizes' (if standard strides apply) any field of a different size is wrong. TODO: check whether it makes sense to put a runtime check here **/ inline void initialise(Ccoord sizes); //! return the pixel sizes inline const Ccoord & get_sizes() const; //! returns the linear index corresponding to cell coordinates template inline size_t get_index(CcoordRef && ccoord) const; //! returns the cell coordinates corresponding to a linear index inline Ccoord get_ccoord(size_t index) const; inline iterator begin(); inline iterator end(); static constexpr inline Dim_t spatial_dim() {return DimS;} static constexpr inline Dim_t material_dim() {return DimM;} protected: //! number of discretisation cells in each of the DimS spatial directions Ccoord sizes{}; Ccoord strides{}; CcoordOps::Pixels pixels{}; private: }; /* ---------------------------------------------------------------------- */ template GlobalFieldCollection::GlobalFieldCollection() :Parent() {} /* ---------------------------------------------------------------------- */ template void GlobalFieldCollection:: initialise(Ccoord sizes) { if (this->is_initialised) { throw std::runtime_error("double initialisation"); } this->pixels = CcoordOps::Pixels(sizes); this->size_ = CcoordOps::get_size(sizes); this->sizes = sizes; std::for_each(std::begin(this->fields), std::end(this->fields), [this](auto && item) { auto && field = *item.second; const auto field_size = field.size(); if (field_size == 0) { field.resize(this->size()); } else if (field_size != this->size()) { std::stringstream err_stream; err_stream << "Field '" << field.get_name() << "' contains " << field_size << " entries, but the field collection " << "has " << this->size() << " pixels"; throw FieldCollectionError(err_stream.str()); } }); this->is_initialised = true; } //----------------------------------------------------------------------------// //! return the pixel sizes template const typename GlobalFieldCollection::Ccoord & GlobalFieldCollection::get_sizes() const { return this->sizes; } //----------------------------------------------------------------------------// //! returns the cell coordinates corresponding to a linear index template typename GlobalFieldCollection::Ccoord GlobalFieldCollection::get_ccoord(size_t index) const { return CcoordOps::get_ccoord(this->get_sizes(), std::move(index)); } /* ---------------------------------------------------------------------- */ template typename GlobalFieldCollection::iterator GlobalFieldCollection::begin() { return this->pixels.begin(); } /* ---------------------------------------------------------------------- */ template typename GlobalFieldCollection::iterator GlobalFieldCollection::end() { return this->pixels.end(); } //----------------------------------------------------------------------------// //! returns the linear index corresponding to cell coordinates template template size_t GlobalFieldCollection::get_index(CcoordRef && ccoord) const { static_assert(std::is_same< Ccoord, std::remove_const_t< std::remove_reference_t>>::value, "can only be called with values or references of Ccoord"); return CcoordOps::get_index(this->get_sizes(), std::forward(ccoord)); } } // muSpectre #endif /* FIELD_COLLECTION_GLOBAL_H */ diff --git a/src/common/field_collection_local.hh b/src/common/field_collection_local.hh index a8ff2ad..a4b15bf 100644 --- a/src/common/field_collection_local.hh +++ b/src/common/field_collection_local.hh @@ -1,174 +1,174 @@ /** * file field_collection_local.hh * * @author Till Junge * * @date 05 Nov 2017 * * @brief FieldCollection base-class for local fields * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_COLLECTION_LOCAL_H #define FIELD_COLLECTION_LOCAL_H #include "common/field_collection_base.hh" namespace muSpectre { /* ---------------------------------------------------------------------- */ //! DimS spatial dimension (dimension of problem) //! DimM material_dimension (dimension of constitutive law) template class LocalFieldCollection: public FieldCollectionBase> { public: using Parent = FieldCollectionBase>; using Ccoord = typename Parent::Ccoord; using Field_p = typename Parent::Field_p; using ccoords_container = std::vector; using iterator = typename ccoords_container::iterator; //! Default constructor LocalFieldCollection(); //! Copy constructor LocalFieldCollection(const LocalFieldCollection &other) = delete; //! Move constructor LocalFieldCollection(LocalFieldCollection &&other) noexcept = delete; //! Destructor virtual ~LocalFieldCollection() noexcept = default; //! Copy assignment operator LocalFieldCollection& operator=(const LocalFieldCollection &other) = delete; //! Move assignment operator LocalFieldCollection& operator=(LocalFieldCollection &&other) noexcept = delete; //! add a pixel/voxel to the field collection inline void add_pixel(const Ccoord & local_ccoord); /** allocate memory, etc. at this point, the field collection knows how many entries it should have from the size of the coords containes (which grows by one every time add_pixel is called. The job of initialise is to make sure that all fields are either of size 0, in which case they need to be allocated, or are of the same size as the product of 'sizes' any field of a different size is wrong TODO: check whether it makes sense to put a runtime check here **/ inline void initialise(); //! returns the linear index corresponding to cell coordinates template inline size_t get_index(CcoordRef && ccoord) const; //! returns the cell coordinates corresponding to a linear index inline Ccoord get_ccoord(size_t index) const; inline iterator begin() {return this->ccoords.begin();} inline iterator end() {return this->ccoords.end();} protected: //! container of pixel coords for non-global collections ccoords_container ccoords{}; //! container of indices for non-global collections (slow!) std::map indices{}; private: }; /* ---------------------------------------------------------------------- */ template LocalFieldCollection::LocalFieldCollection() :Parent(){} /* ---------------------------------------------------------------------- */ template void LocalFieldCollection:: add_pixel(const Ccoord & local_ccoord) { if (this->is_initialised) { throw FieldCollectionError ("once a field collection has been initialised, you can't add new " "pixels."); } this->indices[local_ccoord] = this->ccoords.size(); this->ccoords.push_back(local_ccoord); } /* ---------------------------------------------------------------------- */ template void LocalFieldCollection:: initialise() { if (this->is_initialised) { throw std::runtime_error("double initialisation"); } this->size_ = this->ccoords.size(); std::for_each(std::begin(this->fields), std::end(this->fields), [this](auto && item) { auto && field = *item.second; const auto field_size = field.size(); if (field_size == 0) { field.resize(this->size()); } else if (field_size != this->size()) { std::stringstream err_stream; err_stream << "Field '" << field.get_name() << "' contains " << field_size << " entries, but the field collection " << "has " << this->size() << " pixels"; throw FieldCollectionError(err_stream.str()); } }); this->is_initialised = true; } //----------------------------------------------------------------------------// //! returns the linear index corresponding to cell coordinates template template size_t LocalFieldCollection::get_index(CcoordRef && ccoord) const { static_assert(std::is_same< Ccoord, std::remove_const_t< std::remove_reference_t>>::value, "can only be called with values or references of Ccoord"); return this->indices.at(std::forward(ccoord)); } //----------------------------------------------------------------------------// //! returns the cell coordinates corresponding to a linear index template typename LocalFieldCollection::Ccoord LocalFieldCollection::get_ccoord(size_t index) const { return this->ccoords[std::move(index)]; } } // muSpectre #endif /* FIELD_COLLECTION_LOCAL_H */ diff --git a/src/common/field_map.hh b/src/common/field_map.hh index 7d29c10..48a092c 100644 --- a/src/common/field_map.hh +++ b/src/common/field_map.hh @@ -1,33 +1,33 @@ /** * file field_map.hh * * @author Till Junge * * @date 26 Sep 2017 * * @brief just and indirection to include all iterables defined for fields * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "common/field_map_tensor.hh" #include "common/field_map_matrixlike.hh" #include "common/field_map_scalar.hh" diff --git a/src/common/field_map_base.hh b/src/common/field_map_base.hh index af8c16b..f2686b6 100644 --- a/src/common/field_map_base.hh +++ b/src/common/field_map_base.hh @@ -1,614 +1,614 @@ /** * file field_map.hh * * @author Till Junge * * @date 12 Sep 2017 * * @brief Defined a strongly defines proxy that iterates efficiently over a field * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_MAP_H #define FIELD_MAP_H #include "common/field.hh" #include "field_collection_base.hh" #include "common/common.hh" #include #include #include #include #include namespace muSpectre { namespace internal { //----------------------------------------------------------------------------// //! little helper to automate creation of const maps without duplication template struct const_corrector { using type = typename T::reference; }; template struct const_corrector { using type = typename T::const_reference; }; template using const_corrector_t = typename const_corrector::type; //----------------------------------------------------------------------------// template class FieldMap { public: constexpr static auto nb_components{NbComponents}; using TypedField_nc = TypedFieldBase ; using TypedField = std::conditional_t; using Field = typename TypedField::Parent; using size_type = std::size_t; using pointer = std::conditional_t; //! Default constructor FieldMap() = delete; template FieldMap(std::enable_if_t field); template FieldMap(std::enable_if_t field); template FieldMap(TypedFieldBase & field); //! Copy constructor FieldMap(const FieldMap &other) = default; //! Move constructor FieldMap(FieldMap &&other) noexcept = default; //! Destructor virtual ~FieldMap() noexcept = default; //! Copy assignment operator FieldMap& operator=(const FieldMap &other) = delete; //! Move assignment operator FieldMap& operator=(FieldMap &&other) noexcept = delete; //! give human-readable field map type virtual std::string info_string() const = 0; //! return field name inline const std::string & get_name() const; //! return my collection (for iterating) inline const FieldCollection & get_collection() const; //! member access needs to be implemented by inheriting classes //inline value_type operator[](size_t index); //inline value_type operator[](Ccoord ccord); //! check compatibility (must be called by all inheriting classes at the //! end of their constructors inline void check_compatibility(); //! convenience call to collection's size method inline size_t size() const; //! compile-time compatibility check template struct is_compatible; template class iterator { static_assert(!((ConstIter==false) && (ConstField==true)), "You can't have a non-const iterator over a const " "field"); public: using value_type = const_corrector_t; using const_value_type = const_corrector_t; using pointer = typename FullyTypedFieldMap::pointer; using difference_type = std::ptrdiff_t; using iterator_category = std::random_access_iterator_tag; using Ccoord = typename FieldCollection::Ccoord; using reference = typename FullyTypedFieldMap::reference; using TypedRef = std::conditional_t; //! Default constructor iterator() = delete; //! constructor inline iterator(TypedRef fieldmap, bool begin=true); //! constructor for random access inline iterator(TypedRef fieldmap, size_t index); //! Copy constructor iterator(const iterator &other)= default; //! Move constructor iterator(iterator &&other) noexcept = default; //! Destructor virtual ~iterator() noexcept = default; //! Copy assignment operator iterator& operator=(const iterator &other) = default; //! Move assignment operator iterator& operator=(iterator &&other) noexcept = default; //! pre-increment inline iterator & operator++(); //! post-increment inline iterator operator++(int); //! dereference inline value_type operator*(); //! dereference inline const_value_type operator*() const; //! member of pointer inline pointer operator->(); //! pre-decrement inline iterator & operator--(); //! post-decrement inline iterator operator--(int); //! access subscripting inline value_type operator[](difference_type diff); //! access subscripting inline const_value_type operator[](const difference_type diff) const; //! equality inline bool operator==(const iterator & other) const; //! inequality inline bool operator!=(const iterator & other) const; //! div. comparisons inline bool operator<(const iterator & other) const; inline bool operator<=(const iterator & other) const; inline bool operator>(const iterator & other) const; inline bool operator>=(const iterator & other) const; //! additions, subtractions and corresponding assignments inline iterator operator+(difference_type diff) const; inline iterator operator-(difference_type diff) const; inline iterator& operator+=(difference_type diff); inline iterator& operator-=(difference_type diff); //! get pixel coordinates inline Ccoord get_ccoord() const; //! ostream operator (mainly for debug friend std::ostream & operator<<(std::ostream & os, const iterator& it) { if (ConstIter) { os << "const "; } os << "iterator on field '" << it.fieldmap.get_name() << "', entry " << it.index; return os; } protected: const FieldCollection & collection; TypedRef fieldmap; size_t index; private: }; protected: inline pointer get_ptr_to_entry(size_t index); inline const T* get_ptr_to_entry(size_t index) const; const FieldCollection & collection; TypedField & field; private: }; } // internal namespace internal { /* ---------------------------------------------------------------------- */ template template FieldMap:: FieldMap(std::enable_if_t field) :collection(field.get_collection()), field(static_cast(field)) { static_assert(NbComponents>0, "Only fields with more than 0 components allowed"); } /* ---------------------------------------------------------------------- */ template template FieldMap:: FieldMap(std::enable_if_t field) :collection(field.get_collection()), field(static_cast(field)) { static_assert(NbComponents>0, "Only fields with more than 0 components allowed"); } /* ---------------------------------------------------------------------- */ template template FieldMap:: FieldMap(TypedFieldBase & field) :collection(field.get_collection()), field(static_cast(field)) { static_assert(std::is_same::value, "The field does not have the expected FieldCollection type"); static_assert(std::is_same::value, "The field does not have the expected Scalar type"); static_assert((NbC == NbComponents), "The field does not have the expected number of components"); } /* ---------------------------------------------------------------------- */ template void FieldMap:: check_compatibility() { if (typeid(T).hash_code() != this->field.get_stored_typeid().hash_code()) { std::string err{"Cannot create a Map of type '" + this->info_string() + "' for field '" + this->field.get_name() + "' of type '" + this->field.get_stored_typeid().name() + "'"}; throw FieldInterpretationError (err); } //check size compatibility if (NbComponents != this->field.get_nb_components()) { throw FieldInterpretationError ("Cannot create a Map of type '" + this->info_string() + "' for field '" + this->field.get_name() + "' with " + std::to_string(this->field.get_nb_components()) + " components"); } } /* ---------------------------------------------------------------------- */ template size_t FieldMap:: size() const { return this->collection.size(); } /* ---------------------------------------------------------------------- */ template template struct FieldMap::is_compatible { constexpr static bool explain() { static_assert (std::is_same::value, "The field does not have the expected FieldCollection type"); static_assert (std::is_same::value, "The // field does not have the expected Scalar type"); static_assert((TypedField::nb_components == NbComponents), "The field does not have the expected number of components"); //The static asserts wouldn't pass in the incompatible case, so this is it return true; } constexpr static bool value{std::is_base_of::value}; }; /* ---------------------------------------------------------------------- */ template const std::string & FieldMap:: get_name() const { return this->field.get_name(); } /* ---------------------------------------------------------------------- */ template const FieldCollection & FieldMap:: get_collection() const { return this->collection; } /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ // Iterator implementations //! constructor template template FieldMap::iterator :: iterator(TypedRef fieldmap, bool begin) :collection(fieldmap.get_collection()), fieldmap(fieldmap), index(begin ? 0 : fieldmap.field.size()) {} /* ---------------------------------------------------------------------- */ //! constructor for random access template template FieldMap::iterator:: iterator(TypedRef fieldmap, size_t index) :collection(fieldmap.collection), fieldmap(fieldmap), index(index) {} /* ---------------------------------------------------------------------- */ //! pre-increment template template typename FieldMap::template iterator & FieldMap::iterator:: operator++() { this->index++; return *this; } /* ---------------------------------------------------------------------- */ //! post-increment template template typename FieldMap::template iterator FieldMap::iterator:: operator++(int) { iterator current = *this; this->index++; return current; } /* ---------------------------------------------------------------------- */ //! dereference template template typename FieldMap:: template iterator::value_type FieldMap:: iterator:: operator*() { return this->fieldmap.operator[](this->index); } /* ---------------------------------------------------------------------- */ //! dereference template template typename FieldMap:: template iterator::const_value_type FieldMap:: iterator:: operator*() const { return this->fieldmap.operator[](this->index); } /* ---------------------------------------------------------------------- */ //! member of pointer template template typename FullyTypedFieldMap::pointer FieldMap:: iterator:: operator->() { return this->fieldmap.ptr_to_val_t(this->index); } /* ---------------------------------------------------------------------- */ //! pre-decrement template template typename FieldMap::template iterator & FieldMap:: iterator:: operator--() { this->index--; return *this; } /* ---------------------------------------------------------------------- */ //! post-decrement template template typename FieldMap::template iterator FieldMap:: iterator:: operator--(int) { iterator current = *this; this->index--; return current; } /* ---------------------------------------------------------------------- */ //! Access subscripting template template typename FieldMap:: template iterator::value_type FieldMap:: iterator:: operator[](difference_type diff) { return this->fieldmap[this->index+diff]; } /* ---------------------------------------------------------------------- */ //! Access subscripting template template typename FieldMap::template iterator::const_value_type FieldMap:: iterator:: operator[](const difference_type diff) const { return this->fieldmap[this->index+diff]; } /* ---------------------------------------------------------------------- */ //! equality template template bool FieldMap:: iterator:: operator==(const iterator & other) const { return (this->index == other.index); } /* ---------------------------------------------------------------------- */ //! inquality template template bool FieldMap:: iterator:: operator!=(const iterator & other) const { return !(*this == other); } /* ---------------------------------------------------------------------- */ //! div. comparisons template template bool FieldMap:: iterator:: operator<(const iterator & other) const { return (this->index < other.index); } template template bool FieldMap:: iterator:: operator<=(const iterator & other) const { return (this->index <= other.index); } template template bool FieldMap:: iterator:: operator>(const iterator & other) const { return (this->index > other.index); } template template bool FieldMap:: iterator:: operator>=(const iterator & other) const { return (this->index >= other.index); } /* ---------------------------------------------------------------------- */ //! additions, subtractions and corresponding assignments template template typename FieldMap::template iterator FieldMap:: iterator:: operator+(difference_type diff) const { return iterator(this->fieldmap, this->index + diff); } template template typename FieldMap::template iterator FieldMap:: iterator:: operator-(difference_type diff) const { return iterator(this->fieldmap, this->index - diff); } template template typename FieldMap::template iterator & FieldMap:: iterator:: operator+=(difference_type diff) { this->index += diff; return *this; } template template typename FieldMap::template iterator & FieldMap:: iterator:: operator-=(difference_type diff) { this->index -= diff; return *this; } /* ---------------------------------------------------------------------- */ //! get pixel coordinates template template typename FieldCollection::Ccoord FieldMap:: iterator:: get_ccoord() const { return this->collection.get_ccoord(this->index); } ////----------------------------------------------------------------------------// //template //std::ostream & operator << //(std::ostream &os, // const typename FieldMap:: // template iterator & it) { // os << "iterator on field '" // << it.field.get_name() // << "', entry " << it.index; // return os; //} /* ---------------------------------------------------------------------- */ template typename FieldMap::pointer FieldMap:: get_ptr_to_entry(size_t index) { return this->field.get_ptr_to_entry(std::move(index)); } /* ---------------------------------------------------------------------- */ template const T* FieldMap:: get_ptr_to_entry(size_t index) const { return this->field.get_ptr_to_entry(std::move(index)); } } // internal } // muSpectre #endif /* FIELD_MAP_H */ diff --git a/src/common/field_map_matrixlike.hh b/src/common/field_map_matrixlike.hh index 7b1b97e..9d21a04 100644 --- a/src/common/field_map_matrixlike.hh +++ b/src/common/field_map_matrixlike.hh @@ -1,358 +1,358 @@ /** * file field_map_matrixlike.hh * * @author Till Junge * * @date 26 Sep 2017 * * @brief Eigen-Matrix and -Array maps over strongly typed fields * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_MAP_MATRIXLIKE_H #define FIELD_MAP_MATRIXLIKE_H #include "common/field_map_base.hh" #include "common/T4_map_proxy.hh" #include #include namespace muSpectre { namespace internal { /* ---------------------------------------------------------------------- */ enum class Map_t{Matrix, Array, T4Matrix}; template struct NameWrapper { }; template<> struct NameWrapper { static std::string field_info_root() {return "Array";} }; template<> struct NameWrapper { static std::string field_info_root() {return "Matrix";} }; template<> struct NameWrapper { static std::string field_info_root() {return "T4Matrix";} }; /* ---------------------------------------------------------------------- */ template class MatrixLikeFieldMap: public FieldMap { public: using Parent = FieldMap; using T_t = EigenPlain; using Ccoord = Ccoord_t; using value_type = EigenArray; using const_reference = EigenConstArray; using reference = std::conditional_t; // since it's a resource handle using size_type = typename Parent::size_type; using pointer = std::unique_ptr; using TypedField = typename Parent::TypedField; using Field = typename TypedField::Parent; using const_iterator= typename Parent::template iterator; using iterator = std::conditional_t< ConstField, const_iterator, typename Parent::template iterator>; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; friend iterator; //! Default constructor MatrixLikeFieldMap() = delete; /** * Constructor using a (non-typed) field. Compatibility is enforced at * runtime. This should not be a performance concern, as this constructor * will not be called in anny inner loops (if used as intended). */ template MatrixLikeFieldMap(std::enable_if_t field); template MatrixLikeFieldMap(std::enable_if_t field); /** * Constructor using a typed field. Compatibility is enforced * statically. It is not always possible to call this constructor, as the * type of the field might not be known at compile time. */ template MatrixLikeFieldMap(TypedFieldBase & field); //! Copy constructor MatrixLikeFieldMap(const MatrixLikeFieldMap &other) = default; //! Move constructor MatrixLikeFieldMap(MatrixLikeFieldMap &&other) noexcept = default; //! Destructor virtual ~MatrixLikeFieldMap() noexcept = default; //! Copy assignment operator MatrixLikeFieldMap& operator=(const MatrixLikeFieldMap &other) = delete; //! Move assignment operator MatrixLikeFieldMap& operator=(MatrixLikeFieldMap &&other) noexcept = delete; //! Assign a matrixlike value to every entry template inline MatrixLikeFieldMap & operator=(const Eigen::EigenBase & val); //! give human-readable field map type inline std::string info_string() const override final; //! member access inline reference operator[](size_type index); inline reference operator[](const Ccoord& ccoord); inline const_reference operator[](size_type index) const; inline const_reference operator[](const Ccoord& ccoord) const; //! return an iterator to head of field for ranges inline iterator begin(){return iterator(*this);} inline const_iterator cbegin() const {return const_iterator(*this);} inline const_iterator begin() const {return this->cbegin();} //! return an iterator to tail of field for ranges inline iterator end(){return iterator(*this, false);}; inline const_iterator cend() const {return const_iterator(*this, false);} inline const_iterator end() const {return this->cend();} inline T_t mean() const; protected: //! for sad, legacy iterator use inline pointer ptr_to_val_t(size_type index); const static std::string field_info_root; private: }; /* ---------------------------------------------------------------------- */ template const std::string MatrixLikeFieldMap:: field_info_root{NameWrapper::field_info_root()}; /* ---------------------------------------------------------------------- */ template template MatrixLikeFieldMap:: MatrixLikeFieldMap(std::enable_if_t field) :Parent(field) { static_assert((isntConst != ConstField), "let the compiler deduce isntConst, this is a SFINAE " "parameter"); this->check_compatibility(); } /* ---------------------------------------------------------------------- */ template template MatrixLikeFieldMap:: MatrixLikeFieldMap(std::enable_if_t field) :Parent(field) { static_assert((isConst == ConstField), "let the compiler deduce isntConst, this is a SFINAE " "parameter"); this->check_compatibility(); } /* ---------------------------------------------------------------------- */ template template MatrixLikeFieldMap:: MatrixLikeFieldMap(TypedFieldBase & field) :Parent(field) { } /* ---------------------------------------------------------------------- */ //! human-readable field map type template std::string MatrixLikeFieldMap:: info_string() const { std::stringstream info; info << field_info_root << "(" << typeid(typename EigenArray::value_type).name() << ", " << EigenArray::RowsAtCompileTime << "x" << EigenArray::ColsAtCompileTime << ")"; return info.str(); } /* ---------------------------------------------------------------------- */ //! member access template typename MatrixLikeFieldMap::reference MatrixLikeFieldMap:: operator[](size_type index) { return reference(this->get_ptr_to_entry(index)); } template typename MatrixLikeFieldMap::reference MatrixLikeFieldMap:: operator[](const Ccoord & ccoord) { size_t index{}; index = this->collection.get_index(ccoord); return reference(this->get_ptr_to_entry(std::move(index))); } /* ---------------------------------------------------------------------- */ //! member access template typename MatrixLikeFieldMap::const_reference MatrixLikeFieldMap:: operator[](size_type index) const { return const_reference(this->get_ptr_to_entry(index)); } template typename MatrixLikeFieldMap::const_reference MatrixLikeFieldMap:: operator[](const Ccoord & ccoord) const{ size_t index{}; index = this->collection.get_index(ccoord); return const_reference(this->get_ptr_to_entry(std::move(index))); } //----------------------------------------------------------------------------// template template MatrixLikeFieldMap & MatrixLikeFieldMap:: operator=(const Eigen::EigenBase & val) { for (auto && entry: *this) { entry = val; } return *this; } /* ---------------------------------------------------------------------- */ template typename MatrixLikeFieldMap::T_t MatrixLikeFieldMap:: mean() const { T_t mean{T_t::Zero()}; for (auto && val: *this) { mean += val; } mean *= 1./Real(this->size()); return mean; } /* ---------------------------------------------------------------------- */ template typename MatrixLikeFieldMap::pointer MatrixLikeFieldMap:: ptr_to_val_t(size_type index) { return std::make_unique (this->get_ptr_to_entry(std::move(index))); } } // internal /* ---------------------------------------------------------------------- */ //! short-hand for an Eigen matrix map as iterate template using MatrixFieldMap = internal::MatrixLikeFieldMap >, Eigen::Map>>, Eigen::Map>, Eigen::Matrix, internal::Map_t::Matrix, ConstField>; /* ---------------------------------------------------------------------- */ //! short-hand for an Eigen matrix map as iterate template using T4MatrixFieldMap = internal::MatrixLikeFieldMap , T4MatMap, T4Mat, internal::Map_t::T4Matrix, MapConst>; /* ---------------------------------------------------------------------- */ //! short-hand for an Eigen array map as iterate template using ArrayFieldMap = internal::MatrixLikeFieldMap >, Eigen::Map>>, Eigen::Map>, Eigen::Array, internal::Map_t::Array, ConstField>; } // muSpectre #endif /* FIELD_MAP_MATRIXLIKE_H */ diff --git a/src/common/field_map_scalar.hh b/src/common/field_map_scalar.hh index 1253a4b..52707bb 100644 --- a/src/common/field_map_scalar.hh +++ b/src/common/field_map_scalar.hh @@ -1,217 +1,217 @@ /** * file field_map_scalar.hh * * @author Till Junge * * @date 26 Sep 2017 * * @brief maps over scalar fields * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_MAP_SCALAR_H #define FIELD_MAP_SCALAR_H #include "common/field_map_base.hh" namespace muSpectre { template class ScalarFieldMap : public internal::FieldMap { public: using parent = internal::FieldMap; using Ccoord = Ccoord_t; using value_type = T; using const_reference = const value_type &; using reference = std::conditional_t; using size_type = typename parent::size_type; using pointer = T*; using Field = typename parent::Field; using const_iterator= typename parent::template iterator; using iterator = std::conditional_t >; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; friend iterator; //! Default constructor ScalarFieldMap() = delete; template ScalarFieldMap(std::enable_if_t field); template ScalarFieldMap(std::enable_if_t field); //! Copy constructor ScalarFieldMap(const ScalarFieldMap &other) = default; //! Move constructor ScalarFieldMap(ScalarFieldMap &&other) noexcept = default; //! Destructor virtual ~ScalarFieldMap() noexcept = default; //! Copy assignment operator ScalarFieldMap& operator=(const ScalarFieldMap &other) = delete; //! Move assignment operator ScalarFieldMap& operator=(ScalarFieldMap &&other) noexcept = delete; //! Assign a value to every entry ScalarFieldMap& operator=(T val); //! give human-readable field map type inline std::string info_string() const override final; //! member access inline reference operator[](size_type index); inline reference operator[](const Ccoord& ccoord); inline const_reference operator[] (size_type index) const; inline const_reference operator[] (const Ccoord& ccoord) const; //! return an iterator to head of field for ranges inline iterator begin(){return iterator(*this);} inline const_iterator cbegin() const {return const_iterator(*this);} inline const_iterator begin() const {return this->cbegin();} //! return an iterator to tail of field for ranges inline iterator end(){return iterator(*this, false);} inline const_iterator cend() const {return const_iterator(*this, false);} inline const_iterator end() const {return this->cend();} inline T mean() const; protected: //! for sad, legacy iterator use inline pointer ptr_to_val_t(size_type index); const static std::string field_info_root; private: }; /* ---------------------------------------------------------------------- */ template template ScalarFieldMap:: ScalarFieldMap(std::enable_if_t field) :parent(field) { static_assert((isntConst != ConstField), "let the compiler deduce isntConst, this is a SFINAE " "parameter"); this->check_compatibility(); } /* ---------------------------------------------------------------------- */ template template ScalarFieldMap:: ScalarFieldMap(std::enable_if_t field) :parent(field) { static_assert((isConst == ConstField), "let the compiler deduce isntConst, this is a SFINAE " "parameter"); this->check_compatibility(); } /* ---------------------------------------------------------------------- */ //! human-readable field map type template std::string ScalarFieldMap::info_string() const { std::stringstream info; info << "Scalar(" << typeid(T).name() << ")"; return info.str(); } /* ---------------------------------------------------------------------- */ template const std::string ScalarFieldMap::field_info_root{ "Scalar"}; /* ---------------------------------------------------------------------- */ //! member access template typename ScalarFieldMap::reference ScalarFieldMap::operator[](size_type index) { return this->get_ptr_to_entry(std::move(index))[0]; } /* ---------------------------------------------------------------------- */ //! member access template typename ScalarFieldMap::reference ScalarFieldMap::operator[](const Ccoord& ccoord) { auto && index = this->collection.get_index(std::move(ccoord)); return this->get_ptr_to_entry(std::move(index))[0]; } /* ---------------------------------------------------------------------- */ //! member access template typename ScalarFieldMap::const_reference ScalarFieldMap:: operator[](size_type index) const { return this->get_ptr_to_entry(std::move(index))[0]; } /* ---------------------------------------------------------------------- */ //! member access template typename ScalarFieldMap::const_reference ScalarFieldMap:: operator[](const Ccoord& ccoord) const { auto && index = this->collection.get_index(std::move(ccoord)); return this->get_ptr_to_entry(std::move(index))[0]; } /* ---------------------------------------------------------------------- */ //! Assign a value to every entry template ScalarFieldMap & ScalarFieldMap::operator=(T val) { for (auto & scalar:*this) { scalar = val; } return *this; } /* ---------------------------------------------------------------------- */ template T ScalarFieldMap:: mean() const { T mean{0}; for (auto && val: *this) { mean += val; } mean /= Real(this->size()); return mean; } } // muSpectre #endif /* FIELD_MAP_SCALAR_H */ diff --git a/src/common/field_map_tensor.hh b/src/common/field_map_tensor.hh index c36b0d0..95d1b2b 100644 --- a/src/common/field_map_tensor.hh +++ b/src/common/field_map_tensor.hh @@ -1,264 +1,264 @@ /** * file field_map_tensor.hh * * @author Till Junge * * @date 26 Sep 2017 * * @brief Defines an Eigen-Tensor map over strongly typed fields * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FIELD_MAP_TENSOR_H #define FIELD_MAP_TENSOR_H #include "common/eigen_tools.hh" #include "common/field_map_base.hh" #include #include namespace muSpectre { /* ---------------------------------------------------------------------- */ template class TensorFieldMap: public internal::FieldMap::Sizes::total_size, ConstField> { public: using Parent = internal::FieldMap; using Ccoord = Ccoord_t; using Sizes = typename SizesByOrder::Sizes; using T_t = Eigen::TensorFixedSize; using value_type = Eigen::TensorMap; using const_reference = Eigen::TensorMap; using reference = std::conditional_t; // since it's a resource handle using size_type = typename Parent::size_type; using pointer = std::unique_ptr; using TypedField = typename Parent::TypedField; using Field = typename TypedField::Parent; using const_iterator = typename Parent::template iterator; using iterator = std::conditional_t< ConstField, const_iterator, typename Parent::template iterator>; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; friend iterator; //! Default constructor TensorFieldMap() = delete; template TensorFieldMap(std::enable_if_t field); template TensorFieldMap(std::enable_if_t field); //! Copy constructor TensorFieldMap(const TensorFieldMap &other) = default; //! Move constructor TensorFieldMap(TensorFieldMap &&other) noexcept = default; //! Destructor virtual ~TensorFieldMap() noexcept = default; //! Copy assignment operator TensorFieldMap& operator=(const TensorFieldMap &other) = delete; //! Assign a matrixlike value to every entry inline TensorFieldMap & operator=(const T_t & val); //! Move assignment operator TensorFieldMap& operator=(TensorFieldMap &&other) noexcept = delete; //! give human-readable field map type inline std::string info_string() const override final; //! member access inline reference operator[](size_type index); inline reference operator[](const Ccoord & ccoord); inline const_reference operator[](size_type index) const; inline const_reference operator[](const Ccoord& ccoord) const; //! return an iterator to head of field for ranges inline iterator begin(){return iterator(*this);} inline const_iterator cbegin() const {return const_iterator(*this);} inline const_iterator begin() const {return this->cbegin();} //! return an iterator to tail of field for ranges inline iterator end(){return iterator(*this, false);} inline const_iterator cend() const {return const_iterator(*this, false);} inline const_iterator end() const {return this->cend();} inline T_t mean() const; protected: //! for sad, legacy iterator use inline pointer ptr_to_val_t(size_type index); private: }; /* ---------------------------------------------------------------------- */ template template TensorFieldMap:: TensorFieldMap(std::enable_if_t field) :Parent(field) { static_assert((isntConst != ConstField), "let the compiler deduce isntConst, this is a SFINAE " "parameter"); this->check_compatibility(); } /* ---------------------------------------------------------------------- */ template template TensorFieldMap:: TensorFieldMap(std::enable_if_t field) :Parent(field) { static_assert((isConst == ConstField), "let the compiler deduce isntConst, this is a SFINAE " "parameter"); this->check_compatibility(); } /* ---------------------------------------------------------------------- */ //! human-readable field map type template std::string TensorFieldMap::info_string() const { std::stringstream info; info << "Tensor(" << typeid(T).name() << ", " << order << "_o, " << dim << "_d)"; return info.str(); } /* ---------------------------------------------------------------------- */ //! member access template typename TensorFieldMap::reference TensorFieldMap:: operator[](size_type index) { auto && lambda = [this, &index](auto&&...tens_sizes) { return reference(this->get_ptr_to_entry(index), tens_sizes...); }; return call_sizes(lambda); } template typename TensorFieldMap::reference TensorFieldMap:: operator[](const Ccoord & ccoord) { auto && index = this->collection.get_index(ccoord); auto && lambda = [this, &index](auto&&...sizes) { return reference(this->get_ptr_to_entry(index), sizes...); }; return call_sizes(lambda); } template typename TensorFieldMap:: const_reference TensorFieldMap:: operator[](size_type index) const { // Warning: due to a inconsistency in Eigen's API, tensor maps // cannot be constructed from a const ptr, hence this nasty const // cast :( auto && lambda = [this, &index](auto&&...tens_sizes) { return const_reference(const_cast(this->get_ptr_to_entry(index)), tens_sizes...); }; return call_sizes(lambda); } template typename TensorFieldMap:: const_reference TensorFieldMap:: operator[](const Ccoord & ccoord) const { auto && index = this->collection.get_index(ccoord); auto && lambda = [this, &index](auto&&...sizes) { return const_reference(const_cast(this->get_ptr_to_entry(index)), sizes...); }; return call_sizes(lambda); } /* ---------------------------------------------------------------------- */ template TensorFieldMap & TensorFieldMap:: operator=(const T_t & val) { for (auto && tens: *this) { tens = val; } return *this; } /* ---------------------------------------------------------------------- */ template typename TensorFieldMap::T_t TensorFieldMap:: mean() const { T_t mean{T_t::Zero()}; for (auto && val: *this) { mean += val; } mean *= 1./Real(this->size()); return mean; } /* ---------------------------------------------------------------------- */ //! for sad, legacy iterator use. Don't use unless you have to. template typename TensorFieldMap::pointer TensorFieldMap:: ptr_to_val_t(size_type index) { auto && lambda = [this, &index](auto&&... tens_sizes) { return std::make_unique(this->get_ptr_to_entry(index), tens_sizes...); }; return call_sizes(lambda); } } // muSpectre #endif /* FIELD_MAP_TENSOR_H */ diff --git a/src/common/tensor_algebra.hh b/src/common/tensor_algebra.hh index 0b12019..7617dde 100644 --- a/src/common/tensor_algebra.hh +++ b/src/common/tensor_algebra.hh @@ -1,279 +1,279 @@ /** * file tensor_algebra.hh * * @author Till Junge * * @date 05 Nov 2017 * * @brief collection of compile-time quantities and algrebraic functions for * tensor operations * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef TENSOR_ALGEBRA_H #define TENSOR_ALGEBRA_H #include "common/T4_map_proxy.hh" #include "common/common.hh" #include "common/eigen_tools.hh" #include #include #include namespace muSpectre { namespace Tensors { template using Tens2_t = Eigen::TensorFixedSize>; template using Tens4_t = Eigen::TensorFixedSize>; //----------------------------------------------------------------------------// //! compile-time second-order identity template constexpr inline Tens2_t I2() { Tens2_t T; using Mat_t = Eigen::Matrix; Eigen::Map(&T(0, 0)) = Mat_t::Identity(); return T; } /* ---------------------------------------------------------------------- */ //! Check whether a given expression represents a Tensor specified order template struct is_tensor { constexpr static bool value = (std::is_convertible >::value || std::is_convertible >::value || std::is_convertible >::value); }; /* ---------------------------------------------------------------------- */ /** compile-time outer tensor product as defined by Curnier * R_ijkl = A_ij.B_klxx * 0123 01 23 */ template constexpr inline decltype(auto) outer(T1 && A, T2 && B) { // Just make sure that the right type of parameters have been given constexpr Dim_t order{2}; static_assert(is_tensor::value, "T1 needs to be convertible to a second order Tensor"); static_assert(is_tensor::value, "T2 needs to be convertible to a second order Tensor"); // actual function std::array, 0> dims{}; return A.contract(B, dims); } /* ---------------------------------------------------------------------- */ /** compile-time underlined outer tensor product as defined by Curnier * R_ijkl = A_ik.B_jlxx * 0123 02 13 * 0213 01 23 <- this defines the shuffle order */ template constexpr inline decltype(auto) outer_under(T1 && A, T2 && B) { constexpr size_t order{4}; return outer(A, B).shuffle(std::array{{0, 2, 1, 3}}); } /* ---------------------------------------------------------------------- */ /** compile-time overlined outer tensor product as defined by Curnier * R_ijkl = A_il.B_jkxx * 0123 03 12 * 0231 01 23 <- this defines the shuffle order */ template constexpr inline decltype(auto) outer_over(T1 && A, T2 && B) { constexpr size_t order{4}; return outer(A, B).shuffle(std::array{{0, 2, 3, 1}}); } //! compile-time fourth-order symmetrising identity template constexpr inline Tens4_t I4S() { auto I = I2(); return 0.5*(outer_under(I, I) + outer_over(I, I)); } } // Tensors namespace Matrices { template using Tens2_t = Eigen::Matrix; template using Tens4_t = T4Mat; //----------------------------------------------------------------------------// //! compile-time second-order identity template constexpr inline Tens2_t I2() { return Tens2_t::Identity(); } /* ---------------------------------------------------------------------- */ /** compile-time outer tensor product as defined by Curnier * R_ijkl = A_ij.B_klxx * 0123 01 23 */ template constexpr inline decltype(auto) outer(T1 && A, T2 && B) { // Just make sure that the right type of parameters have been given constexpr Dim_t dim{EigenCheck::tensor_dim::value}; static_assert((dim == EigenCheck::tensor_dim::value), "A and B do not have the same dimension"); Tens4_t product; for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t k = 0; k < dim; ++k) { for (Dim_t l = 0; l < dim; ++l) { get(product, i, j, k, l) = A(i, j) * B(k, l); } } } } return product; } /* ---------------------------------------------------------------------- */ /** compile-time underlined outer tensor product as defined by Curnier * R_ijkl = A_ik.B_jlxx * 0123 02 13 * 0213 01 23 <- this defines the shuffle order */ template constexpr inline decltype(auto) outer_under(T1 && A, T2 && B) { // Just make sure that the right type of parameters have been given constexpr Dim_t dim{EigenCheck::tensor_dim::value}; static_assert((dim == EigenCheck::tensor_dim::value), "A and B do not have the same dimension"); Tens4_t product; for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t k = 0; k < dim; ++k) { for (Dim_t l = 0; l < dim; ++l) { get(product, i, j, k, l) = A(i, k) * B(j, l); } } } } return product; } /* ---------------------------------------------------------------------- */ /** compile-time overlined outer tensor product as defined by Curnier * R_ijkl = A_il.B_jkxx * 0123 03 12 * 0231 01 23 <- this defines the shuffle order */ template constexpr inline decltype(auto) outer_over(T1 && A, T2 && B) { // Just make sure that the right type of parameters have been given constexpr Dim_t dim{EigenCheck::tensor_dim::value}; static_assert((dim == EigenCheck::tensor_dim::value), "A and B do not have the same dimension"); Tens4_t product; for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t k = 0; k < dim; ++k) { for (Dim_t l = 0; l < dim; ++l) { get(product, i, j, k, l) = A(i, l) * B(j, k); } } } } return product; } /** * Standart tensor multiplication */ template constexpr inline decltype(auto) tensmult(T4 && A, T2 && B) { constexpr Dim_t dim{EigenCheck::tensor_4_dim::value}; static_assert((dim == EigenCheck::tensor_dim::value), "Dimensionality check failed. Expects A to be a fourth-" "order tensor of dimension dim and B to be a second-order " "Tensor of same dimension"); Tens2_t result; result.setZero(); for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t k = 0; k < dim; ++k) { for (Dim_t l = 0; l < dim; ++l) { result(i,j) +=get(A, i, j, k, l) * B(k, l); } } } } return result; } //! compile-time fourth-order tracer template constexpr inline Tens4_t Itrac() { auto I = I2(); return outer(I,I); } //! compile-time fourth-order identity template constexpr inline Tens4_t Iiden() { auto I = I2(); return outer_under(I,I); } //! compile-time fourth-order transposer template constexpr inline Tens4_t Itrns() { auto I = I2(); return outer_over(I,I); } //! compile-time fourth-order symmetriser template constexpr inline Tens4_t Isymm() { auto I = I2(); return 0.5*(outer_under(I, I) + outer_over(I, I)); } } // Matrices } // muSpectre #endif /* TENSOR_ALGEBRA_H */ diff --git a/src/common/test_goodies.hh b/src/common/test_goodies.hh index df83222..a4b9965 100644 --- a/src/common/test_goodies.hh +++ b/src/common/test_goodies.hh @@ -1,135 +1,135 @@ /** * file test_goodies.hh * * @author Till Junge * * @date 27 Sep 2017 * * @brief helpers for testing * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef TEST_GOODIES_H #define TEST_GOODIES_H #include "common/tensor_algebra.hh" #include #include #include namespace muSpectre { namespace testGoodies { template struct dimFixture{ constexpr static Dim_t dim{Dim}; }; using dimlist = boost::mpl::list, dimFixture, dimFixture>; /* ---------------------------------------------------------------------- */ template class RandRange { public: RandRange(): rd(), gen(rd()) {} template std::enable_if_t::value, dummyT> randval(T&& lower, T&& upper) { static_assert(std::is_same::value, "SFINAE"); auto distro = std::uniform_real_distribution(lower, upper); return distro(this->gen); } template std::enable_if_t::value, dummyT> randval(T&& lower, T&& upper) { static_assert(std::is_same::value, "SFINAE"); auto distro = std::uniform_int_distribution(lower, upper); return distro(this->gen); } private: std::random_device rd; std::default_random_engine gen; }; /** * explicit computation of linearisation of PK1 stress for an * objective Hooke's law. This implementation is not meant to be * efficient, but te reflect exactly the formulation in Curnier * 2000, "Méthodes numériques en mécanique des solides" for * reference and testing */ template decltype(auto) objective_hooke_explicit(Real lambda, Real mu, const Matrices::Tens2_t& F) { using namespace Matrices; using T2 = Tens2_t; using T4 = Tens4_t; T2 P; T2 I = P.Identity(); T4 K; // See Curnier, 2000, "Méthodes numériques en mécanique des // solides", p 252, (6.95b) Real Fjrjr = (F.array()*F.array()).sum(); T2 Fjrjm = F.transpose()*F; P.setZero(); for (Dim_t i = 0; i < Dim; ++i) { for (Dim_t m = 0; m < Dim; ++m) { P(i,m) += lambda/2*(Fjrjr-Dim)*F(i,m); for (Dim_t r = 0; r < Dim; ++r) { P(i,m) += mu*F(i,r)*(Fjrjm(r,m) - I(r,m)); } } } // See Curnier, 2000, "Méthodes numériques en mécanique des solides", p 252 Real Fkrkr = (F.array()*F.array()).sum(); T2 Fkmkn = F.transpose()*F; T2 Fisjs = F*F.transpose(); K.setZero(); for (Dim_t i = 0; i < Dim; ++i) { for (Dim_t j = 0; j < Dim; ++j) { for (Dim_t m = 0; m < Dim; ++m) { for (Dim_t n = 0; n < Dim; ++n) { get(K, i, m, j, n) = (lambda*((Fkrkr-Dim)/2 * I(i,j)*I(m,n) + F(i,m)*F(j,n)) + mu * (I(i,j)*Fkmkn(m,n) + Fisjs(i,j)*I(m,n) - I(i,j) *I(m,n) + F(i,n)*F(j,m))); } } } } return std::make_tuple(P,K); } } // testGoodies } // muSpectre #endif /* TEST_GOODIES_H */ diff --git a/src/common/utilities.hh b/src/common/utilities.hh index e6b5246..fa2b43b 100644 --- a/src/common/utilities.hh +++ b/src/common/utilities.hh @@ -1,172 +1,172 @@ /** * file utilities.hh * * @author Till Junge * * @date 17 Nov 2017 * * @brief additions to the standard name space to anticipate C++17 features * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef UTILITIES_H #define UTILITIES_H #include #include #include namespace std_replacement { namespace detail { template struct is_reference_wrapper : std::false_type {}; template struct is_reference_wrapper> : std::true_type {}; template constexpr bool is_reference_wrapper_v = is_reference_wrapper::value; template auto INVOKE(T Base::*pmf, Derived&& ref, Args&&... args) noexcept(noexcept((std::forward(ref).*pmf)(std::forward(args)...))) -> std::enable_if_t::value && std::is_base_of>::value, decltype((std::forward(ref).*pmf)(std::forward(args)...))> { return (std::forward(ref).*pmf)(std::forward(args)...); } template auto INVOKE(T Base::*pmf, RefWrap&& ref, Args&&... args) noexcept(noexcept((ref.get().*pmf)(std::forward(args)...))) -> std::enable_if_t::value && is_reference_wrapper_v>, decltype((ref.get().*pmf)(std::forward(args)...))> { return (ref.get().*pmf)(std::forward(args)...); } template auto INVOKE(T Base::*pmf, Pointer&& ptr, Args&&... args) noexcept(noexcept(((*std::forward(ptr)).*pmf)(std::forward(args)...))) -> std::enable_if_t::value && !is_reference_wrapper_v> && !std::is_base_of>::value, decltype(((*std::forward(ptr)).*pmf)(std::forward(args)...))> { return ((*std::forward(ptr)).*pmf)(std::forward(args)...); } template auto INVOKE(T Base::*pmd, Derived&& ref) noexcept(noexcept(std::forward(ref).*pmd)) -> std::enable_if_t::value && std::is_base_of>::value, decltype(std::forward(ref).*pmd)> { return std::forward(ref).*pmd; } template auto INVOKE(T Base::*pmd, RefWrap&& ref) noexcept(noexcept(ref.get().*pmd)) -> std::enable_if_t::value && is_reference_wrapper_v>, decltype(ref.get().*pmd)> { return ref.get().*pmd; } template auto INVOKE(T Base::*pmd, Pointer&& ptr) noexcept(noexcept((*std::forward(ptr)).*pmd)) -> std::enable_if_t::value && !is_reference_wrapper_v> && !std::is_base_of>::value, decltype((*std::forward(ptr)).*pmd)> { return (*std::forward(ptr)).*pmd; } template auto INVOKE(F&& f, Args&&... args) noexcept(noexcept(std::forward(f)(std::forward(args)...))) -> std::enable_if_t>::value, decltype(std::forward(f)(std::forward(args)...))> { return std::forward(f)(std::forward(args)...); } } // namespace detail template< class F, class... ArgTypes > auto invoke(F&& f, ArgTypes&&... args) // exception specification for QoI noexcept(noexcept(detail::INVOKE(std::forward(f), std::forward(args)...))) -> decltype(detail::INVOKE(std::forward(f), std::forward(args)...)) { return detail::INVOKE(std::forward(f), std::forward(args)...); } namespace detail { template constexpr decltype(auto) apply_impl(F &&f, Tuple &&t, std::index_sequence) { return std_replacement::invoke(std::forward(f), std::get(std::forward(t))...); } } // namespace detail template constexpr decltype(auto) apply(F &&f, Tuple &&t) { return detail::apply_impl (std::forward(f), std::forward(t), std::make_index_sequence>::value>{}); } } //namespace std_replacement namespace muSpectre { using std_replacement::apply; template using optional = typename std::experimental::optional; /* ---------------------------------------------------------------------- */ template auto asStdTuple(BoostTuple&& boostTuple, std::index_sequence) { return std::tuple>::type...> (boost::get(std::forward(boostTuple))...); } template auto asStdTuple(BoostTuple&& boostTuple) { return asStdTuple(std::forward(boostTuple), std::make_index_sequence>::value>()); } } // muSpectre #endif /* UTILITIES_H */ diff --git a/src/common/voigt_conversion.cc b/src/common/voigt_conversion.cc index 7baae07..69f5165 100644 --- a/src/common/voigt_conversion.cc +++ b/src/common/voigt_conversion.cc @@ -1,79 +1,79 @@ /** * file voigt_conversion.cc * * @author Till Junge * * @date 04 May 2017 * * @brief specializations for static members of voigt converter * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "common/voigt_conversion.hh" namespace muSpectre { template<> const Eigen::Matrix VoigtConversion<1>::mat = (Eigen::Matrix()<< 0).finished(); template<> const Eigen::Matrix VoigtConversion<2>::mat = (Eigen::Matrix()<< 0, 2, 3, 1).finished(); template<> const Eigen::Matrix VoigtConversion<3>::mat = (Eigen::Matrix()<< 0, 5, 4, 8, 1, 3, 7, 6, 2).finished(); template<> const Eigen::Matrix VoigtConversion<1>::sym_mat = (Eigen::Matrix()<< 0).finished(); template<> const Eigen::Matrix VoigtConversion<2>::sym_mat = (Eigen::Matrix()<< 0, 2, 2, 1).finished(); template<> const Eigen::Matrix VoigtConversion<3>::sym_mat = (Eigen::Matrix()<< 0, 5, 4, 5, 1, 3, 4, 3, 2).finished(); template<> const Eigen::Matrix VoigtConversion<1>::vec = (Eigen::Matrix() << 0, 0).finished(); template<> const Eigen::Matrix VoigtConversion<2>::vec = (Eigen::Matrix() << 0, 0, 1, 1, 0, 1, 1, 0).finished(); template<> const Eigen::Matrix VoigtConversion<3>::vec = (Eigen::Matrix() << 0, 0, 1, 1, 2, 2, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0).finished(); template<> const Eigen::Matrix VoigtConversion<1>::factors = (Eigen::Matrix() << 1).finished(); template<> const Eigen::Matrix VoigtConversion<2>::factors = (Eigen::Matrix() << 1, 1, 2).finished(); template<> const Eigen::Matrix VoigtConversion<3>::factors = (Eigen::Matrix() << 1, 1, 1, 2, 2, 2).finished(); } // muSpectre diff --git a/src/common/voigt_conversion.hh b/src/common/voigt_conversion.hh index 9ebeca2..1c28d7f 100644 --- a/src/common/voigt_conversion.hh +++ b/src/common/voigt_conversion.hh @@ -1,162 +1,162 @@ /** * file voigt_conversion.hh * * @author Till Junge * * @date 02 May 2017 * * @brief utilities to transform vector notation arrays into voigt notation * arrays and vice-versa * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef VOIGT_CONVERSION_H #define VOIGT_CONVERSION_H #include "common/common.hh" #include #include #include namespace muSpectre { template constexpr Dim_t vsize(Dim_t dim) { if (sym) { return (dim * (dim - 1) / 2 + dim); } else { return dim*dim; } } template class VoigtConversion { public: VoigtConversion(); virtual ~VoigtConversion(); template inline static void fourth_to_voigt(const Tens4 & t, Voigt & v); template inline static Eigen::Matrix(dim), vsize(dim)> fourth_to_voigt(const Tens4 & t); template inline static Eigen::Matrix(dim), vsize(dim)> fourth_to_2d(const Tens4 & t) { return fourth_to_voigt(t); } template inline static void second_to_voigt(const Tens2 & t, Voigt & v); template inline static void gradient_to_voigt_strain(const Tens2 & F, Voigt & v); template inline static void gradient_to_voigt_GreenLagrange_strain(const Tens2 & F, Voigt & v); template inline static void stress_from_voigt(const Voigt & v, Tens2 & sigma); public: // matrix of vector index I as function of tensor indices i,j const static Eigen::Matrix mat; // matrix of vector index I as function of tensor indices i,j const static Eigen::Matrix sym_mat; // array of matrix indices ij as function of vector index I const static Eigen::Matrixvec; // factors to multiply the strain by for voigt notation const static Eigen::Matrix factors; }; //----------------------------------------------------------------------------// template template inline void VoigtConversion::fourth_to_voigt(const Tens4 & t, Voigt & v) { // upper case indices for Voigt notation, lower case for standard tensorial for (Dim_t I = 0; I < vsize(dim); ++I) { auto && i = vec(I, 0); auto && j = vec(I, 1); for (Dim_t J = 0; J < vsize(dim); ++J) { auto && k = vec(J, 0); auto && l = vec(J, 1); v(I,J) = t(i,j, k, l); } } } //----------------------------------------------------------------------------// template template inline Eigen::Matrix(dim), vsize(dim)> VoigtConversion::fourth_to_voigt(const Tens4 & t){ using V_t = Eigen::Matrix(dim), vsize(dim)>; V_t temp; fourth_to_voigt(t, temp); return temp; } //----------------------------------------------------------------------------// template template inline void VoigtConversion::second_to_voigt(const Tens2 & F, Voigt & v) { for (Dim_t I = 0; I < vsize(dim); ++I) { auto&& i = vec(I, 0); auto&& j = vec(I, 1); v(I) = F(i, j); } } //----------------------------------------------------------------------------// template template inline void VoigtConversion::gradient_to_voigt_strain(const Tens2 & F, Voigt & v) { for (Dim_t I = 0; I < vsize(dim); ++I) { auto&& i = vec(I, 0); auto&& j = vec(I, 1); v(I) = (F(i, j) + F(j, i))/2 * factors(I); } } //----------------------------------------------------------------------------// template template inline void VoigtConversion:: gradient_to_voigt_GreenLagrange_strain(const Tens2 & F, Voigt & v) { using mat = Eigen::Matrix; mat E = 0.5*(F.transpose()*F - mat::Identity()); for (Dim_t I = 0; I < vsize(dim); ++I) { auto&& i = vec(I, 0); auto&& j = vec(I, 1); v(I) = E(i,j) * factors(I); } } } // muSpectre #endif /* VOIGT_CONVERSION_H */ diff --git a/src/fft/CMakeLists.txt b/src/fft/CMakeLists.txt index 4f1d43d..4ba1880 100644 --- a/src/fft/CMakeLists.txt +++ b/src/fft/CMakeLists.txt @@ -1,13 +1,42 @@ +# ============================================================================= +# file CMakeLists.txt +# +# @author Till Junge +# +# @date 08 Jan 2018 +# +# @brief configuration for fft-related files +# +# @section LICENCE +# +# Copyright © 2018 Till Junge +# +# µSpectre 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, or (at +# your option) any later version. +# +# µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# ============================================================================= + set (fft_engine_SRC ${CMAKE_CURRENT_SOURCE_DIR}/fft_utils.cc ${CMAKE_CURRENT_SOURCE_DIR}/fft_engine_base.cc ${CMAKE_CURRENT_SOURCE_DIR}/fftw_engine.cc ${CMAKE_CURRENT_SOURCE_DIR}/projection_base.cc ${CMAKE_CURRENT_SOURCE_DIR}/projection_finite_strain.cc ${CMAKE_CURRENT_SOURCE_DIR}/projection_finite_strain_fast.cc ) set (muSpectre_SRC ${muSpectre_SRC} ${fft_engine_SRC} PARENT_SCOPE) diff --git a/src/fft/fft_engine_base.cc b/src/fft/fft_engine_base.cc index b869c65..4e7939b 100644 --- a/src/fft/fft_engine_base.cc +++ b/src/fft/fft_engine_base.cc @@ -1,64 +1,64 @@ /** * file fft_engine_base.cc * * @author Till Junge * * @date 03 Dec 2017 * * @brief implementation for FFT engine base class * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "fft/fft_engine_base.hh" namespace muSpectre { /* ---------------------------------------------------------------------- */ template FFT_Engine_base::FFT_Engine_base(Ccoord resolutions, Rcoord lengths) :resolutions{resolutions}, lengths{lengths}, work{make_field("work space", work_space_container)}, norm_factor{1./CcoordOps::get_size(resolutions)} {} /* ---------------------------------------------------------------------- */ template void FFT_Engine_base::initialise(FFT_PlanFlags /*plan_flags*/) { this->work_space_container.initialise(); } /* ---------------------------------------------------------------------- */ template size_t FFT_Engine_base::size() const { return CcoordOps::get_size(this->resolutions); } /* ---------------------------------------------------------------------- */ template size_t FFT_Engine_base::workspace_size() const { return this->work_space_container.size(); } template class FFT_Engine_base; template class FFT_Engine_base; template class FFT_Engine_base; } // muSpectre diff --git a/src/fft/fft_engine_base.hh b/src/fft/fft_engine_base.hh index 3c0882b..99543c8 100644 --- a/src/fft/fft_engine_base.hh +++ b/src/fft/fft_engine_base.hh @@ -1,121 +1,121 @@ /** * file fft_engine_base.hh * * @author Till Junge * * @date 01 Dec 2017 * * @brief Interface for FFT engines * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FFT_ENGINE_BASE_H #define FFT_ENGINE_BASE_H #include "common/common.hh" #include "common/field_collection.hh" namespace muSpectre { enum class FFT_PlanFlags {estimate, measure, patient}; template class FFT_Engine_base { public: constexpr static Dim_t sdim{DimS}; constexpr static Dim_t mdim{DimM}; using Ccoord = Ccoord_t; using Rcoord = std::array; using GFieldCollection_t = FieldCollection; using LFieldCollection_t = FieldCollection; using Field_t = TensorField; using Workspace_t = TensorField; using iterator = typename LFieldCollection_t::iterator; //! Default constructor FFT_Engine_base() = delete; //! Constructor with system resolutions FFT_Engine_base(Ccoord resolutions, Rcoord lengths); //! Copy constructor FFT_Engine_base(const FFT_Engine_base &other) = delete; //! Move constructor FFT_Engine_base(FFT_Engine_base &&other) noexcept = default; //! Destructor virtual ~FFT_Engine_base() noexcept = default; //! Copy assignment operator FFT_Engine_base& operator=(const FFT_Engine_base &other) = delete; //! Move assignment operator FFT_Engine_base& operator=(FFT_Engine_base &&other) noexcept = default; // compute the plan, etc virtual void initialise(FFT_PlanFlags /*plan_flags*/); //! forward transform (dummy for interface) virtual Workspace_t & fft(Field_t & /*field*/) = 0; //! inverse transform (dummy for interface) virtual void ifft(Field_t & /*field*/) const = 0; /** * iterators over only thos pixels that exist in frequency space * (i.e. about half of all pixels, see rfft) */ inline iterator begin() {return this->work_space_container.begin();} inline iterator end() {return this->work_space_container.end();} //! nb of pixels (mostly for debugging) size_t size() const; size_t workspace_size() const; //! const Ccoord & get_resolutions() const {return this->resolutions;} const Rcoord & get_lengths() const {return this->lengths;} LFieldCollection_t & get_field_collection() { return this->work_space_container;} //! factor by which to multiply projection before inverse transform (this is //! typically 1/nb_pixels for so-called unnormalized transforms (see, //! e.g. http://www.fftw.org/fftw3_doc/Multi_002dDimensional-DFTs-of-Real-Data.html#Multi_002dDimensional-DFTs-of-Real-Data //! or https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.fft.html //! . Rather than scaling the inverse transform (which would cost one more //! loop), FFT engines provide this value so it can be used in the //! projection operator (where no additional loop is required) inline Real normalisation() const {return norm_factor;}; protected: LFieldCollection_t work_space_container{}; const Ccoord resolutions; const Rcoord lengths; Workspace_t & work; const Real norm_factor; private: }; } // muSpectre #endif /* FFT_ENGINE_BASE_H */ diff --git a/src/fft/fft_utils.cc b/src/fft/fft_utils.cc index b6aae5b..cceffc2 100644 --- a/src/fft/fft_utils.cc +++ b/src/fft/fft_utils.cc @@ -1,54 +1,54 @@ /** * file fft_utils.cc * * @author Till Junge * * @date 11 Dec 2017 * * @brief implementation of fft utilities * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "fft/fft_utils.hh" namespace muSpectre { /* ---------------------------------------------------------------------- */ std::valarray fft_freqs(size_t nb_samples) { std::valarray retval(nb_samples); Int N = (nb_samples-1)/2 + 1; // needs to be signed int for neg freqs for (Int i = 0; i < N; ++i) { retval[i] = i; } for (Int i = N; i < Int(nb_samples); ++i) { retval[i] = -Int(nb_samples)/2+i-N; } return retval; } /* ---------------------------------------------------------------------- */ std::valarray fft_freqs(size_t nb_samples, Real length) { return fft_freqs(nb_samples)/length; } } // muSpectre diff --git a/src/fft/fft_utils.hh b/src/fft/fft_utils.hh index d770dd1..6832f85 100644 --- a/src/fft/fft_utils.hh +++ b/src/fft/fft_utils.hh @@ -1,125 +1,125 @@ /** * file fft_utils.hh * * @author Till Junge * * @date 06 Dec 2017 * * @brief collection of functions used in the context of spectral operations * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FFT_UTILS_H #define FFT_UTILS_H #include "common/common.hh" #include #include #include namespace muSpectre { /** * compute fft frequencies (in time (or length) units of of sampling * periods), see numpy's fftfreq function for reference */ std::valarray fft_freqs(size_t nb_samples); /** * compute fft frequencies in correct length or time units. Here, * length refers to the total size of the domain over which the fft * is taken (for instance the length of an edge of an RVE) */ std::valarray fft_freqs(size_t nb_samples, Real length); /** * Get fft_freqs for a grid */ template inline std::array, dim> fft_freqs(Ccoord_t sizes, std::array lengths) { std::array, dim> retval{}; for (size_t i = 0; i < dim; ++i) { retval[i] = std::move(fft_freqs(sizes[i], lengths[i])); } return retval; } /** * simple class encapsulating the creation, and retrieval of * wave vectors */ template class FFT_freqs { public: using Vector = Eigen::Matrix; //! Default constructor FFT_freqs() = delete; //! constructor with problem sizes FFT_freqs(Ccoord_t sizes, std::array lengths) : freqs{fft_freqs(sizes, lengths)} {} //! Copy constructor FFT_freqs(const FFT_freqs &other) = delete; //! Move constructor FFT_freqs(FFT_freqs &&other) = default; //! Destructor virtual ~FFT_freqs() noexcept = default; //! Copy assignment operator FFT_freqs& operator=(const FFT_freqs &other) = delete; //! Move assignment operator FFT_freqs& operator=(FFT_freqs &&other) = default; //! get unnormalised wave vector (in sampling units) inline Vector get_xi(const Ccoord_t ccoord) const; //! get normalised wave vector inline Vector get_unit_xi(const Ccoord_t ccoord) const{ auto && xi = this->get_xi(std::move(ccoord)); return xi/xi.norm(); } protected: const std::array, dim> freqs; private: }; template typename FFT_freqs::Vector FFT_freqs::get_xi(const Ccoord_t ccoord) const { Vector retval{}; for (Dim_t i = 0; i < dim; ++i) { retval(i) = this->freqs[i][ccoord[i]]; } return retval; } } // muSpectre #endif /* FFT_UTILS_H */ diff --git a/src/fft/fftw_engine.cc b/src/fft/fftw_engine.cc index 0864258..b1db7bd 100644 --- a/src/fft/fftw_engine.cc +++ b/src/fft/fftw_engine.cc @@ -1,143 +1,143 @@ /** * file fftw_engine.cc * * @author Till Junge * * @date 03 Dec 2017 * * @brief implements the fftw engine * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "common/ccoord_operations.hh" #include "fft/fftw_engine.hh" namespace muSpectre { template FFTW_Engine::FFTW_Engine(Ccoord resolutions, Rcoord lengths) :Parent{resolutions, lengths}, hermitian_resolutions{CcoordOps::get_hermitian_sizes(resolutions)} { for (auto && pixel: CcoordOps::Pixels(this->hermitian_resolutions)) { this->work_space_container.add_pixel(pixel); } } /* ---------------------------------------------------------------------- */ template void FFTW_Engine::initialise(FFT_PlanFlags plan_flags) { Parent::initialise(plan_flags); const int & rank = DimS; std::array narr; const int * const n = &narr[0]; std::copy(this->resolutions.begin(), this->resolutions.end(), narr.begin()); int howmany = Field_t::nb_components; //temporary buffer for plan size_t alloc_size = CcoordOps::get_size(this->resolutions) *howmany; Real * r_work_space = fftw_alloc_real(alloc_size); Real * in = r_work_space; const int * const inembed = nullptr;//nembed are tricky: they refer to physical layout int istride = howmany; int idist = 1; fftw_complex * out = reinterpret_cast(this->work.data()); const int * const onembed = nullptr; int ostride = howmany; int odist = idist; unsigned int flags; switch (plan_flags) { case FFT_PlanFlags::estimate: { flags = FFTW_ESTIMATE; break; } case FFT_PlanFlags::measure: { flags = FFTW_MEASURE; break; } case FFT_PlanFlags::patient: { flags = FFTW_PATIENT; break; } default: throw std::runtime_error("unknown planner flag type"); break; } this->plan_fft = fftw_plan_many_dft_r2c(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, FFTW_PRESERVE_INPUT | flags); if (this->plan_fft == nullptr) { throw std::runtime_error("Plan failed"); } fftw_execute_dft_r2c(this->plan_fft, in, reinterpret_cast(this->work.data())); fftw_complex * i_in = reinterpret_cast(this->work.data()); Real * i_out = r_work_space; this->plan_ifft = fftw_plan_many_dft_c2r(rank, n, howmany, i_in, inembed, istride, idist, i_out, onembed, ostride, odist, flags); if (this->plan_ifft == nullptr) { throw std::runtime_error("Plan failed"); } fftw_free(r_work_space); } /* ---------------------------------------------------------------------- */ template FFTW_Engine::~FFTW_Engine() noexcept { fftw_destroy_plan(this->plan_fft); fftw_destroy_plan(this->plan_ifft); fftw_cleanup(); } /* ---------------------------------------------------------------------- */ template typename FFTW_Engine::Workspace_t & FFTW_Engine::fft (Field_t & field) { fftw_execute_dft_r2c(this->plan_fft, field.data(), reinterpret_cast(this->work.data())); return this->work; } /* ---------------------------------------------------------------------- */ template void FFTW_Engine::ifft (Field_t & field) const { if (field.size() != CcoordOps::get_size(this->resolutions)) { throw std::runtime_error("size mismatch"); } fftw_execute_dft_c2r(this->plan_ifft, reinterpret_cast(this->work.data()), field.data()); } template class FFTW_Engine; template class FFTW_Engine; template class FFTW_Engine; } // muSpectre diff --git a/src/fft/fftw_engine.hh b/src/fft/fftw_engine.hh index f2b699b..0f9a2f5 100644 --- a/src/fft/fftw_engine.hh +++ b/src/fft/fftw_engine.hh @@ -1,87 +1,87 @@ /** * file fftw_engine.hh * * @author Till Junge * * @date 03 Dec 2017 * * @brief FFT engine using FFTW * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef FFTW_ENGINE_H #define FFTW_ENGINE_H #include "fft/fft_engine_base.hh" #include namespace muSpectre { template class FFTW_Engine: public FFT_Engine_base { public: using Parent = FFT_Engine_base; using Ccoord = typename Parent::Ccoord; using Rcoord = typename Parent::Rcoord; using Workspace_t = typename Parent::Workspace_t; using Field_t = typename Parent::Field_t; //! Default constructor FFTW_Engine() = delete; //! Constructor with system resolutions FFTW_Engine(Ccoord resolutions, Rcoord lengths); //! Copy constructor FFTW_Engine(const FFTW_Engine &other) = delete; //! Move constructor FFTW_Engine(FFTW_Engine &&other) = default; //! Destructor virtual ~FFTW_Engine() noexcept; //! Copy assignment operator FFTW_Engine& operator=(const FFTW_Engine &other) = delete; //! Move assignment operator FFTW_Engine& operator=(FFTW_Engine &&other) = default; // compute the plan, etc virtual void initialise(FFT_PlanFlags plan_flags) override; //! forward transform virtual Workspace_t & fft(Field_t & field) override; //! inverse transform virtual void ifft(Field_t & field) const override; protected: Ccoord hermitian_resolutions; fftw_plan plan_fft{}; fftw_plan plan_ifft{}; private: }; } // muSpectre #endif /* FFTW_ENGINE_H */ diff --git a/src/fft/projection_base.cc b/src/fft/projection_base.cc index d1f02e7..740dfe2 100644 --- a/src/fft/projection_base.cc +++ b/src/fft/projection_base.cc @@ -1,57 +1,57 @@ /** * file projection_base.cc * * @author Till Junge * * @date 06 Dec 2017 * * @brief implementation of base class for projections * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "fft/projection_base.hh" namespace muSpectre { /* ---------------------------------------------------------------------- */ template ProjectionBase::ProjectionBase(FFT_Engine_ptr engine) : fft_engine{std::move(engine)}, projection_container{this->fft_engine->get_field_collection()} { static_assert((DimS == FFT_Engine::sdim), "spatial dimensions are incompatible"); static_assert((DimM == FFT_Engine::mdim), "material dimensions are incompatible"); } /* ---------------------------------------------------------------------- */ template void ProjectionBase:: initialise(FFT_PlanFlags flags) { fft_engine->initialise(flags); } template class ProjectionBase; template class ProjectionBase; template class ProjectionBase; } // muSpectre diff --git a/src/fft/projection_base.hh b/src/fft/projection_base.hh index 8ffc00d..394181c 100644 --- a/src/fft/projection_base.hh +++ b/src/fft/projection_base.hh @@ -1,103 +1,103 @@ /** * file projection_base.hh * * @author Till Junge * * @date 03 Dec 2017 * * @brief Base class for Projection operators * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef PROJECTION_BASE_H #define PROJECTION_BASE_H #include "common/common.hh" #include "common/field_collection.hh" #include "common/field.hh" #include "fft/fft_engine_base.hh" #include namespace muSpectre { template struct Projection_traits { }; template class ProjectionBase { public: using FFT_Engine = FFT_Engine_base; using FFT_Engine_ptr = std::unique_ptr; using Ccoord = typename FFT_Engine::Ccoord; using Rcoord = typename FFT_Engine::Rcoord; using GFieldCollection_t = typename FFT_Engine::GFieldCollection_t; using LFieldCollection_t = typename FFT_Engine::LFieldCollection_t; using Field_t = typename FFT_Engine::Field_t; using iterator = typename FFT_Engine::iterator; //! Default constructor ProjectionBase() = delete; //! Constructor with system sizes ProjectionBase(FFT_Engine_ptr engine); //! Copy constructor ProjectionBase(const ProjectionBase &other) = delete; //! Move constructor ProjectionBase(ProjectionBase &&other) noexcept = default; //! Destructor virtual ~ProjectionBase() noexcept = default; //! Copy assignment operator ProjectionBase& operator=(const ProjectionBase &other) = delete; //! Move assignment operator ProjectionBase& operator=(ProjectionBase &&other) noexcept = default; //! initialises the fft engine (plan the transform) virtual void initialise(FFT_PlanFlags flags = FFT_PlanFlags::estimate); //! apply the projection operator to a field virtual void apply_projection(Field_t & field) = 0; //! const Ccoord & get_resolutions() const { return this->fft_engine->get_resolutions();} const Rcoord & get_lengths() const { return this->fft_engine->get_lengths();} protected: FFT_Engine_ptr fft_engine; LFieldCollection_t & projection_container{}; private: }; } // muSpectre #endif /* PROJECTION_BASE_H */ diff --git a/src/fft/projection_finite_strain.cc b/src/fft/projection_finite_strain.cc index 1d29ebc..80ee24d 100644 --- a/src/fft/projection_finite_strain.cc +++ b/src/fft/projection_finite_strain.cc @@ -1,89 +1,89 @@ /** * file projection_finite_strain.cc * * @author Till Junge * * @date 05 Dec 2017 * * @brief implementation of standard finite strain projection operator * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "fft/projection_finite_strain.hh" #include "fft/fftw_engine.hh" #include "fft/fft_utils.hh" #include "common/field_map.hh" #include "common/tensor_algebra.hh" #include "common/iterators.hh" #include "Eigen/Dense" namespace muSpectre { /* ---------------------------------------------------------------------- */ template ProjectionFiniteStrain:: ProjectionFiniteStrain(FFT_Engine_ptr engine) :Parent{std::move(engine)}, Ghat{make_field("Projection Operator", this->projection_container)} {} /* ---------------------------------------------------------------------- */ template void ProjectionFiniteStrain:: initialise(FFT_PlanFlags flags) { Parent::initialise(flags); FFT_freqs fft_freqs(this->fft_engine->get_resolutions(), this->fft_engine->get_lengths()); for (auto && tup: akantu::zip(*this->fft_engine, this->Ghat)) { const auto & ccoord = std::get<0> (tup); auto & G = std::get<1>(tup); auto xi = fft_freqs.get_unit_xi(ccoord); //! this is simplyfiable usinc Curnier's Méthodes numériques, 6.69(c) G = Matrices::outer_under(Matrices::I2(), xi*xi.transpose()); // for (Dim_t im = 0; im < DimS; ++im) { // for (Dim_t j = 0; j < DimS; ++j) { // for (Dim_t l = 0; l < DimS; ++l) { // get(G, im, j, l, im) = xi(j)*xi(l); // } // } // } } this->Ghat[0].setZero(); } /* ---------------------------------------------------------------------- */ template void ProjectionFiniteStrain::apply_projection(Field_t & field) { Vector_map field_map{this->fft_engine->fft(field)}; Real factor = this->fft_engine->normalisation(); for (auto && tup: akantu::zip(this->Ghat, field_map)) { auto & G{std::get<0>(tup)}; auto & f{std::get<1>(tup)}; f = factor * (G*f).eval(); } this->fft_engine->ifft(field); } template class ProjectionFiniteStrain; template class ProjectionFiniteStrain; } // muSpectre diff --git a/src/fft/projection_finite_strain.hh b/src/fft/projection_finite_strain.hh index be46840..292a7a3 100644 --- a/src/fft/projection_finite_strain.hh +++ b/src/fft/projection_finite_strain.hh @@ -1,90 +1,90 @@ /** * file projection_finite_strain.hh * * @author Till Junge * * @date 05 Dec 2017 * * @brief Class for standard finite-strain gradient projections see de Geus et * al. (https://doi.org/10.1016/j.cma.2016.12.032) for derivation * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef PROJECTION_FINITE_STRAIN_H #define PROJECTION_FINITE_STRAIN_H #include "fft/projection_base.hh" #include "common/common.hh" #include "common/field_collection.hh" #include "common/field_map.hh" namespace muSpectre { template class ProjectionFiniteStrain: public ProjectionBase { public: using Parent = ProjectionBase; using FFT_Engine_ptr = typename Parent::FFT_Engine_ptr; using Ccoord = typename Parent::Ccoord; using GFieldCollection_t = FieldCollection; using LFieldCollection_t = FieldCollection; using Field_t = TensorField; using Proj_t = TensorField; using Proj_map = T4MatrixFieldMap; using Vector_map = MatrixFieldMap; //! Default constructor ProjectionFiniteStrain() = delete; //! Constructor with fft_engine ProjectionFiniteStrain(FFT_Engine_ptr engine); //! Copy constructor ProjectionFiniteStrain(const ProjectionFiniteStrain &other) = delete; //! Move constructor ProjectionFiniteStrain(ProjectionFiniteStrain &&other) = default; //! Destructor virtual ~ProjectionFiniteStrain() noexcept = default; //! Copy assignment operator ProjectionFiniteStrain& operator=(const ProjectionFiniteStrain &other) = delete; //! Move assignment operator ProjectionFiniteStrain& operator=(ProjectionFiniteStrain &&other) = default; //! initialises the fft engine (plan the transform) virtual void initialise(FFT_PlanFlags flags = FFT_PlanFlags::estimate) override final; //! apply the projection operator to a field void apply_projection(Field_t & field) override final; protected: Proj_map Ghat; private: }; } // muSpectre #endif /* PROJECTION_FINITE_STRAIN_H */ diff --git a/src/fft/projection_finite_strain_fast.cc b/src/fft/projection_finite_strain_fast.cc index eabd8a0..a72e0c8 100644 --- a/src/fft/projection_finite_strain_fast.cc +++ b/src/fft/projection_finite_strain_fast.cc @@ -1,77 +1,77 @@ /** * file projection_finite_strain_fast.cc * * @author Till Junge * * @date 12 Dec 2017 * * @brief implementation for fast projection in finite strain * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "fft/projection_finite_strain_fast.hh" #include "fft/fft_utils.hh" #include "common/tensor_algebra.hh" #include "common/iterators.hh" namespace muSpectre { /* ---------------------------------------------------------------------- */ template ProjectionFiniteStrainFast:: ProjectionFiniteStrainFast(FFT_Engine_ptr engine) :Parent{std::move(engine)}, xis{make_field("Projection Operator", this->projection_container)} {} /* ---------------------------------------------------------------------- */ template void ProjectionFiniteStrainFast:: initialise(FFT_PlanFlags flags) { Parent::initialise(flags); FFT_freqs fft_freqs(this->fft_engine->get_resolutions(), this->fft_engine->get_lengths()); for (auto && tup: akantu::zip(*this->fft_engine, this->xis)) { const auto & ccoord = std::get<0> (tup); auto & xi = std::get<1>(tup); xi = fft_freqs.get_unit_xi(ccoord); } this->xis[0].setZero(); } /* ---------------------------------------------------------------------- */ template void ProjectionFiniteStrainFast::apply_projection(Field_t & field) { Grad_map field_map{this->fft_engine->fft(field)}; Real factor = this->fft_engine->normalisation(); for (auto && tup: akantu::zip(this->xis, field_map)) { auto & xi{std::get<0>(tup)}; auto & f{std::get<1>(tup)}; f = factor * ((f*xi).eval()*xi.transpose()); } this->fft_engine->ifft(field); } template class ProjectionFiniteStrainFast; template class ProjectionFiniteStrainFast; } // muSpectre diff --git a/src/fft/projection_finite_strain_fast.hh b/src/fft/projection_finite_strain_fast.hh index 30a75f8..a183343 100644 --- a/src/fft/projection_finite_strain_fast.hh +++ b/src/fft/projection_finite_strain_fast.hh @@ -1,90 +1,90 @@ /** * file projection_finite_strain_fast.hh * * @author Till Junge * * @date 12 Dec 2017 * * @brief Faster alternative to ProjectionFinitestrain * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef PROJECTION_FINITE_STRAIN_FAST_H #define PROJECTION_FINITE_STRAIN_FAST_H #include "fft/projection_base.hh" #include "common/common.hh" #include "common/field_collection.hh" #include "common/field_map.hh" namespace muSpectre { template class ProjectionFiniteStrainFast: public ProjectionBase { public: using Parent = ProjectionBase; using FFT_Engine_ptr = typename Parent::FFT_Engine_ptr; using Ccoord = typename Parent::Ccoord; using GFieldCollection_t = FieldCollection; using LFieldCollection_t = FieldCollection; using Field_t = TensorField; using Proj_t = TensorField; using Proj_map = MatrixFieldMap; using Grad_map = MatrixFieldMap; //! Default constructor ProjectionFiniteStrainFast() = delete; //! Constructor with fft_engine ProjectionFiniteStrainFast(FFT_Engine_ptr engine); //! Copy constructor ProjectionFiniteStrainFast(const ProjectionFiniteStrainFast &other) = delete; //! Move constructor ProjectionFiniteStrainFast(ProjectionFiniteStrainFast &&other) noexcept = default; //! Destructor virtual ~ProjectionFiniteStrainFast() noexcept = default; //! Copy assignment operator ProjectionFiniteStrainFast& operator=(const ProjectionFiniteStrainFast &other) = delete; //! Move assignment operator ProjectionFiniteStrainFast& operator=(ProjectionFiniteStrainFast &&other) = default; //! initialises the fft engine (plan the transform) virtual void initialise(FFT_PlanFlags flags = FFT_PlanFlags::estimate) override final; //! apply the projection operator to a field void apply_projection(Field_t & field) override final; protected: Proj_map xis; private: }; } // muSpectre #endif /* PROJECTION_FINITE_STRAIN_FAST_H */ diff --git a/src/materials/CMakeLists.txt b/src/materials/CMakeLists.txt index 530750a..c207bd7 100644 --- a/src/materials/CMakeLists.txt +++ b/src/materials/CMakeLists.txt @@ -1,12 +1,41 @@ +# ============================================================================= +# file CMakeLists.txt +# +# @author Till Junge +# +# @date 08 Jan 2018 +# +# @brief configuration for material laws +# +# @section LICENCE +# +# Copyright © 2018 Till Junge +# +# µSpectre 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, or (at +# your option) any later version. +# +# µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# ============================================================================= + set (materials_SRC ${CMAKE_CURRENT_SOURCE_DIR}/material_base.cc ${CMAKE_CURRENT_SOURCE_DIR}/material_hyper_elastic1.cc #${CMAKE_CURRENT_SOURCE_DIR}/material_linear_elastic.cc ) set (muSpectre_SRC ${muSpectre_SRC} ${materials_SRC} PARENT_SCOPE) diff --git a/src/materials/material_base.cc b/src/materials/material_base.cc index f793b36..8a2d815 100644 --- a/src/materials/material_base.cc +++ b/src/materials/material_base.cc @@ -1,81 +1,81 @@ /** * file material_base.cc * * @author Till Junge * * @date 01 Nov 2017 * * @brief implementation of materi * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "materials/material_base.hh" namespace muSpectre { //----------------------------------------------------------------------------// template MaterialBase::MaterialBase(std::string name) :name(name) { static_assert((DimM == oneD)|| (DimM == twoD)|| (DimM == threeD), "only 1, 2, or threeD supported"); } /* ---------------------------------------------------------------------- */ template const std::string & MaterialBase::get_name() const { return this->name; } /* ---------------------------------------------------------------------- */ template void MaterialBase::add_pixel(const Ccoord &ccoord) { this->internal_fields.add_pixel(ccoord); } /* ---------------------------------------------------------------------- */ template void MaterialBase::compute_stresses(const Field_t & F, Field_t & P, Formulation form) { this->compute_stresses(StrainField_t::check_ref(F), StressField_t::check_ref(P), form); } /* ---------------------------------------------------------------------- */ template void MaterialBase::compute_stresses_tangent(const Field_t & F, Field_t & P, Field_t & K, Formulation form) { this->compute_stresses_tangent(StrainField_t::check_ref(F), StressField_t::check_ref(P), TangentField_t::check_ref(K), form); } template class MaterialBase<2, 2>; template class MaterialBase<2, 3>; template class MaterialBase<3, 3>; } // muSpectre diff --git a/src/materials/material_base.hh b/src/materials/material_base.hh index ec58141..ff29b20 100644 --- a/src/materials/material_base.hh +++ b/src/materials/material_base.hh @@ -1,142 +1,142 @@ /** * file material_base.hh * * @author Till Junge * * @date 25 Oct 2017 * * @brief Base class for materials (constitutive models) * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef MATERIAL_BASE_H #define MATERIAL_BASE_H #include "common/common.hh" #include "common/field.hh" #include "common/field_collection.hh" #include namespace muSpectre { //! DimS spatial dimension (dimension of problem //! DimM material_dimension (dimension of constitutive law) template class MaterialBase { public: //! typedefs for data handled by this interface //! global field collection for system-wide fields, like stress, strain, etc using GFieldCollection_t = FieldCollection; //! field collection for internal variables, such as eigen-strains, //! plastic strains, damage variables, etc, but also for managing which //! pixels the material is responsible for using MFieldCollection_t = FieldCollection; using iterator = typename MFieldCollection_t::iterator; using Field_t = internal::FieldBase; using StressField_t = TensorField; using StrainField_t = StressField_t; using TangentField_t = TensorField; using Ccoord = Ccoord_t; //! Default constructor MaterialBase() = delete; //! Construct by name MaterialBase(std::string name); //! Copy constructor MaterialBase(const MaterialBase &other) = delete; //! Move constructor MaterialBase(MaterialBase &&other) noexcept = delete; //! Destructor virtual ~MaterialBase() noexcept = default; //! Copy assignment operator MaterialBase& operator=(const MaterialBase &other) = delete; //! Move assignment operator MaterialBase& operator=(MaterialBase &&other) noexcept = delete; /** * take responsibility for a pixel identified by its cell coordinates * WARNING: this won't work for materials with additional info per pixel * (as, e.g. for eigenstrain), we need to pass more parameters. Materials * of this tye need to overload add_pixel */ void add_pixel(const Ccoord & ccooord); //! allocate memory, etc, but also: wipe history variables! virtual void initialise(bool stiffness = false) = 0; //! return the materil's name const std::string & get_name() const; //! for static inheritance stuff constexpr static Dim_t sdim() {return DimS;} constexpr static Dim_t mdim() {return DimM;} //! computes stress virtual void compute_stresses(const StrainField_t & F, StressField_t & P, Formulation form) = 0; /** * Convenience function to compute stresses, mostly for debugging and * testing. Has runtime-cost associated with compatibility-checking and * conversion of the Field_t arguments that can be avoided by using the * version with strongly typed field references */ void compute_stresses(const Field_t & F, Field_t & P, Formulation form); //! computes stress and tangent moduli virtual void compute_stresses_tangent(const StrainField_t & F, StressField_t & P, TangentField_t & K, Formulation form) = 0; /** * Convenience function to compute stresses and tangent moduli, mostly for * debugging and testing. Has runtime-cost associated with * compatibility-checking and conversion of the Field_t arguments that can * be avoided by using the version with strongly typed field references */ void compute_stresses_tangent(const Field_t & F, Field_t & P, Field_t & K, Formulation form); inline iterator begin() {return this->internal_fields.begin();} inline iterator end() {return this->internal_fields.end();} protected: //! members const std::string name; MFieldCollection_t internal_fields{}; private: }; } // muSpectre #endif /* MATERIAL_BASE_H */ diff --git a/src/materials/material_hyper_elastic1.cc b/src/materials/material_hyper_elastic1.cc index 81c4b71..d74b58e 100644 --- a/src/materials/material_hyper_elastic1.cc +++ b/src/materials/material_hyper_elastic1.cc @@ -1,53 +1,53 @@ /** * file material_hyper_elastic1.cc * * @author Till Junge * * @date 14 Nov 2017 * * @brief Implementation for materialhyperelastic1 * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "materials/material_hyper_elastic1.hh" #include "common/tensor_algebra.hh" #include namespace muSpectre { /* ---------------------------------------------------------------------- */ template MaterialHyperElastic1::MaterialHyperElastic1(std::string name, Real young, Real poisson) :Parent(name), young{young}, poisson{poisson}, lambda{young*poisson/((1+poisson)*(1-2*poisson))}, mu{young/(2*(1+poisson))}, C{lambda*Tensors::outer(Tensors::I2(),Tensors::I2()) + 2*mu*Tensors::I4S()} {} template class MaterialHyperElastic1; template class MaterialHyperElastic1; template class MaterialHyperElastic1; } // muSpectre diff --git a/src/materials/material_hyper_elastic1.hh b/src/materials/material_hyper_elastic1.hh index f9b5f22..2fe91f2 100644 --- a/src/materials/material_hyper_elastic1.hh +++ b/src/materials/material_hyper_elastic1.hh @@ -1,133 +1,133 @@ /** * file material_hyper_elastic1.hh * * @author Till Junge * * @date 13 Nov 2017 * * @brief Implementation for hyperelastic reference material like in de Geus * 2017. This follows the simplest and likely not most efficient * implementation (with exception of the Python law) * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef MATERIAL_HYPER_ELASTIC1_H #define MATERIAL_HYPER_ELASTIC1_H #include "common/common.hh" #include "materials/material_muSpectre_base.hh" namespace muSpectre { template class MaterialHyperElastic1; template struct MaterialMuSpectre_traits>: public MaterialMuSpectre_traits { using Parent = MaterialMuSpectre_traits; using InternalVariables = typename Parent::DefaultInternalVariables; }; //! DimS spatial dimension (dimension of problem //! DimM material_dimension (dimension of constitutive law) template class MaterialHyperElastic1: public MaterialMuSpectre, DimS, DimM> { public: using Parent = MaterialMuSpectre; using NeedTangent = typename Parent::NeedTangent; using GFieldCollection_t = typename Parent::GFieldCollection_t; // declare what type of strain measure your law takes as input constexpr static auto strain_measure{StrainMeasure::GreenLagrange}; // declare what type of stress measure your law yields as output constexpr static auto stress_measure{StressMeasure::PK2}; // declare whether the derivative of stress with respect to strain is uniform constexpr static bool uniform_stiffness = true; // declare the type in which you wish to receive your strain measure using StrainMap_t = MatrixFieldMap; using StressMap_t = MatrixFieldMap; using TangentMap_t = T4MatrixFieldMap; using Strain_t = typename StrainMap_t::const_reference; using Stress_t = typename StressMap_t::reference; using Tangent_t = typename TangentMap_t::reference; using Stiffness_t = Eigen::TensorFixedSize >; using InternalVariables = typename Parent::DefaultInternalVariables; //! Default constructor MaterialHyperElastic1() = delete; //! Copy constructor MaterialHyperElastic1(const MaterialHyperElastic1 &other) = delete; //! Construct by name, Young's modulus and Poisson's ratio MaterialHyperElastic1(std::string name, Real young, Real poisson); //! Move constructor MaterialHyperElastic1(MaterialHyperElastic1 &&other) noexcept = delete; //! Destructor virtual ~MaterialHyperElastic1() noexcept = default; //! Copy assignment operator MaterialHyperElastic1& operator=(const MaterialHyperElastic1 &other) = delete; //! Move assignment operator MaterialHyperElastic1& operator=(MaterialHyperElastic1 &&other) noexcept = delete; template inline decltype(auto) evaluate_stress(s_t && E); template inline decltype(auto) evaluate_stress_tangent(s_t && E); const Tangent_t & get_stiffness() const; protected: const Real young, poisson, lambda, mu; const Stiffness_t C; private: }; /* ---------------------------------------------------------------------- */ template template decltype(auto) MaterialHyperElastic1::evaluate_stress(s_t && E) { return E.trace()*lambda * Strain_t::Identity() + 2*mu*E; } /* ---------------------------------------------------------------------- */ template template decltype(auto) MaterialHyperElastic1::evaluate_stress_tangent(s_t && E) { return std::make_tuple(std::move(this->evaluate_stress(std::move(E))), std::move(Tangent_t(const_cast(this->C.data())))); } } // muSpectre #endif /* MATERIAL_HYPER_ELASTIC1_H */ diff --git a/src/materials/material_muSpectre_base.hh b/src/materials/material_muSpectre_base.hh index b6cc61a..07fec49 100644 --- a/src/materials/material_muSpectre_base.hh +++ b/src/materials/material_muSpectre_base.hh @@ -1,630 +1,630 @@ /** * file material_muSpectre_base.hh * * @author Till Junge * * @date 25 Oct 2017 * * @brief Base class for materials written for µSpectre specifically. These * can take full advantage of the configuration-change utilities of * µSpectre. The user can inherit from them to define new constitutive * laws and is merely required to provide the methods for computing the * second Piola-Kirchhoff stress and Tangent. This class uses the * "curiously recurring template parameter" to avoid virtual calls. * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef MATERIAL_MUSPECTRE_BASE_H #define MATERIAL_MUSPECTRE_BASE_H #include "common/common.hh" #include "materials/material_base.hh" #include "materials/materials_toolbox.hh" #include "common/field_collection.hh" #include "common/field.hh" #include "common//utilities.hh" #include #include #include #include namespace muSpectre { template struct MaterialMuSpectre_traits { }; template class MaterialMuSpectre; template <> struct MaterialMuSpectre_traits { using DefaultInternalVariables = std::tuple<>; }; //! 'Material' is a CRTP template class MaterialMuSpectre: public MaterialBase { public: using NeedTangent = MatTB::NeedTangent; using Parent = MaterialBase; using GFieldCollection_t = typename Parent::GFieldCollection_t; using MFieldCollection_t = typename Parent::MFieldCollection_t; using StressField_t = typename Parent::StressField_t; using StrainField_t = typename Parent::StrainField_t; using TangentField_t = typename Parent::TangentField_t; using DefaultInternalVariables = std::tuple<>; using traits = MaterialMuSpectre_traits; //! Default constructor MaterialMuSpectre() = delete; //! Construct by name MaterialMuSpectre(std::string name); //! Copy constructor MaterialMuSpectre(const MaterialMuSpectre &other) = delete; //! Move constructor MaterialMuSpectre(MaterialMuSpectre &&other) noexcept = delete; //! Destructor virtual ~MaterialMuSpectre() noexcept = default; //! Copy assignment operator MaterialMuSpectre& operator=(const MaterialMuSpectre &other) = delete; //! Move assignment operator MaterialMuSpectre& operator=(MaterialMuSpectre &&other) noexcept = delete; //* allocate memory, etc virtual void initialise(bool stiffness = false) override final; using Parent::compute_stresses; using Parent::compute_stresses_tangent; //! computes stress virtual void compute_stresses(const StrainField_t & F, StressField_t & P, Formulation form) override final; //! computes stress and tangent modulus virtual void compute_stresses_tangent(const StrainField_t & F, StressField_t & P, TangentField_t & K, Formulation form) override final; protected: //! computes stress with the formulation available at compile time template inline void compute_stresses_worker(const StrainField_t & F, StressField_t & P); //! computes stress with the formulation available at compile time template inline void compute_stresses_worker(const StrainField_t & F, StressField_t & P, TangentField_t & K); //! this iterable class is a default for simple laws that just take a strain //! the iterable is just a templated wrapper to provide a range to iterate over //! that does or does not include tangent moduli template class iterable_proxy; /** * inheriting classes with internal variables need to overload this function */ decltype(auto) get_internals() { // the default material has no internal variables return typename Material::InternalVariables{};} decltype(auto) get_internals() const { // the default material has no internal variables return typename Material::InternalVariables{};} typename traits::InternalVariables internal_variables{}; bool is_initialised{false}; private: }; /* ---------------------------------------------------------------------- */ template MaterialMuSpectre:: MaterialMuSpectre(std::string name) :Parent(name) { using stress_compatible = typename Material::StressMap_t:: template is_compatible; using strain_compatible = typename Material::StrainMap_t:: template is_compatible; using tangent_compatible = typename Material::TangentMap_t:: template is_compatible; static_assert((stress_compatible::value && stress_compatible::explain()), "The material's declared stress map is not compatible " "with the stress field. More info in previously shown " "assert."); static_assert((strain_compatible::value && strain_compatible::explain()), "The material's declared strain map is not compatible " "with the strain field. More info in previously shown " "assert."); static_assert((tangent_compatible::value && tangent_compatible::explain()), "The material's declared tangent map is not compatible " "with the tangent field. More info in previously shown " "assert."); } /* ---------------------------------------------------------------------- */ template void MaterialMuSpectre:: initialise(bool /*stiffness*/) { if (!this->is_initialised) { this->internal_fields.initialise(); this->is_initialised = true; } } /* ---------------------------------------------------------------------- */ template void MaterialMuSpectre:: compute_stresses(const StrainField_t &F, StressField_t &P, Formulation form) { switch (form) { case Formulation::finite_strain: { this->template compute_stresses_worker(F, P); break; } case Formulation::small_strain: { this->template compute_stresses_worker(F, P); break; } default: throw std::runtime_error("Unknown formulation"); break; } } /* ---------------------------------------------------------------------- */ template void MaterialMuSpectre:: compute_stresses_tangent(const StrainField_t & F, StressField_t & P, TangentField_t & K, Formulation form) { switch (form) { case Formulation::finite_strain: { this->template compute_stresses_worker(F, P, K); break; } case Formulation::small_strain: { this->template compute_stresses_worker(F, P, K); break; } default: throw std::runtime_error("Unknown formulation"); break; } } /* ---------------------------------------------------------------------- */ template template void MaterialMuSpectre:: compute_stresses_worker(const StrainField_t & F, StressField_t & P, TangentField_t & K){ /* These lambdas are executed for every integration point. F contains the transformation gradient for finite strain calculations and the infinitesimal strain tensor in small strain problems The internal_variables tuple contains whatever internal variables Material declared (e.g., eigenstrain, strain rate, etc.) */ using Strains_t = std::tuple; using Stresses_t = std::tuple; auto constitutive_law_small_strain = [this] (Strains_t Strains, Stresses_t Stresses, auto && internal_variables) { constexpr StrainMeasure stored_strain_m{get_stored_strain_type(Form)}; constexpr StrainMeasure expected_strain_m{ get_formulation_strain_type(Form, Material::strain_measure)}; auto & this_mat = static_cast(*this); // Transformation gradient is first in the strains tuple auto && F = std::get<0>(Strains); auto && strain = MatTB::convert_strain(F); // return value contains a tuple of rvalue_refs to both stress and tangent moduli Stresses = apply([&strain, &this_mat] (auto && ... internals) { return this_mat.evaluate_stress_tangent(std::move(strain), internals...);}, internal_variables); }; auto constitutive_law_finite_strain = [this] (Strains_t Strains, Stresses_t Stresses, auto && internal_variables) { constexpr StrainMeasure stored_strain_m{get_stored_strain_type(Form)}; constexpr StrainMeasure expected_strain_m{ get_formulation_strain_type(Form, Material::strain_measure)}; auto & this_mat = static_cast(*this); // Transformation gradient is first in the strains tuple auto && F = std::get<0>(Strains); auto && strain = MatTB::convert_strain(F); // TODO: Figure this out: I can't std::move(internals...), // because if there are no internals, compilation fails with "no // matching function for call to ‘move()’'. These are tuples of // lvalue references, so it shouldn't be too bad, but still // irksome. // return value contains a tuple of rvalue_refs to both stress // and tangent moduli auto stress_tgt = apply([&strain, &this_mat] (auto && ... internals) { return this_mat.evaluate_stress_tangent(std::move(strain), internals...);}, internal_variables); auto && stress = std::get<0>(stress_tgt); auto && tangent = std::get<1>(stress_tgt); Stresses = MatTB::PK1_stress (std::move(F), std::move(stress), std::move(tangent)); }; iterable_proxy fields{*this, F, P, K}; for (auto && arglist: fields) { /** * arglist is a tuple of three tuples containing only Lvalue * references (see value_tye in the class definition of * iterable_proxy::iterator). Tuples contain strains, stresses * and internal variables, respectively, */ //auto && stress_tgt = std::get<0>(tuples); //auto && inputs = std::get<1>(tuples);TODO:clean this static_assert(std::is_same(std::get<0>(arglist)))>>::value, "Type mismatch for strain reference, check iterator " "value_type"); static_assert(std::is_same(std::get<1>(arglist)))>>::value, "Type mismatch for stress reference, check iterator" "value_type"); static_assert(std::is_same(std::get<1>(arglist)))>>::value, "Type mismatch for tangent reference, check iterator" "value_type"); switch (Form) { case Formulation::small_strain: { apply(constitutive_law_small_strain, std::move(arglist)); break; } case Formulation::finite_strain: { apply(constitutive_law_finite_strain, std::move(arglist)); break; } } } } /* ---------------------------------------------------------------------- */ template template void MaterialMuSpectre:: compute_stresses_worker(const StrainField_t & F, StressField_t & P){ /* These lambdas are executed for every integration point. F contains the transformation gradient for finite strain calculations and the infinitesimal strain tensor in small strain problems The internal_variables tuple contains whatever internal variables Material declared (e.g., eigenstrain, strain rate, etc.) */ using Strains_t = std::tuple; using Stresses_t = std::tuple; auto constitutive_law_small_strain = [this] (Strains_t Strains, Stresses_t Stresses, auto && internal_variables) { constexpr StrainMeasure stored_strain_m{get_stored_strain_type(Form)}; constexpr StrainMeasure expected_strain_m{ get_formulation_strain_type(Form, Material::strain_measure)}; auto & this_mat = static_cast(*this); // Transformation gradient is first in the strains tuple auto && F = std::get<0>(Strains); auto && strain = MatTB::convert_strain(F); // return value contains a tuple of rvalue_refs to both stress and tangent moduli auto && sigma = std::get<0>(Stresses); sigma = apply([&strain, &this_mat] (auto && ... internals) { return this_mat.evaluate_stress(std::move(strain), internals...);}, internal_variables); }; auto constitutive_law_finite_strain = [this] (Strains_t Strains, Stresses_t && Stresses, auto && internal_variables) { constexpr StrainMeasure stored_strain_m{get_stored_strain_type(Form)}; constexpr StrainMeasure expected_strain_m{ get_formulation_strain_type(Form, Material::strain_measure)}; auto & this_mat = static_cast(*this); // Transformation gradient is first in the strains tuple auto && F = std::get<0>(Strains); auto && strain = MatTB::convert_strain(F); // TODO: Figure this out: I can't std::move(internals...), // because if there are no internals, compilation fails with "no // matching function for call to ‘move()’'. These are tuples of // lvalue references, so it shouldn't be too bad, but still // irksome. // return value contains a tuple of rvalue_refs to both stress // and tangent moduli auto && stress = apply([&strain, &this_mat] (auto && ... internals) { return this_mat.evaluate_stress(std::move(strain), internals...);}, internal_variables); auto && P = get<0>(Stresses); P = MatTB::PK1_stress (F, stress); }; iterable_proxy fields{*this, F, P}; for (auto && arglist: fields) { /** * arglist is a tuple of three tuples containing only Lvalue * references (see value_tye in the class definition of * iterable_proxy::iterator). Tuples contain strains, stresses * and internal variables, respectively, */ //auto && stress_tgt = std::get<0>(tuples); //auto && inputs = std::get<1>(tuples);TODO:clean this static_assert(std::is_same(std::get<0>(arglist)))>>::value, "Type mismatch for strain reference, check iterator " "value_type"); static_assert(std::is_same(std::get<1>(arglist)))>>::value, "Type mismatch for stress reference, check iterator" "value_type"); switch (Form) { case Formulation::small_strain: { apply(constitutive_law_small_strain, std::move(arglist)); break; } case Formulation::finite_strain: { apply(constitutive_law_finite_strain, std::move(arglist)); break; } } } } /* ---------------------------------------------------------------------- */ //! this iterator class is a default for simple laws that just take a strain template template class MaterialMuSpectre::iterable_proxy { public: //! Default constructor iterable_proxy() = delete; using NeedTangent = typename MaterialMuSpectre::NeedTangent; /** Iterator uses the material's internal variables field collection to iterate selectively over the global fields (such as the transformation gradient F and first Piola-Kirchhoff stress P. **/ template iterable_proxy(const MaterialMuSpectre & mat, const StrainField_t & F, StressField_t & P, std::enable_if_t & K) :material(mat), strain_field(F), stress_tup{P,K}, internals(material.internal_variables){}; template iterable_proxy(const MaterialMuSpectre & mat, const StrainField_t & F, std::enable_if_t & P) :material(mat), strain_field(F), stress_tup{P}, internals(material.internal_variables){}; using StrainMap_t = typename Material::StrainMap_t; using StressMap_t = typename Material::StressMap_t; using TangentMap_t = typename Material::TangentMap_t; using Strain_t = typename Material::Strain_t; using Stress_t = typename Material::Stress_t; using Tangent_t = typename Material::Tangent_t; using InternalVariables = typename Material::InternalVariables; using StressFieldTup = std::conditional_t <(NeedTgt == NeedTangent::yes), std::tuple, std::tuple>; using StressMapTup = std::conditional_t <(NeedTgt == NeedTangent::yes), std::tuple, std::tuple>; using Stress_tTup = std::conditional_t<(NeedTgt == NeedTangent::yes), std::tuple, std::tuple>; //! Copy constructor iterable_proxy(const iterable_proxy &other) = default; //! Move constructor iterable_proxy(iterable_proxy &&other) noexcept = default; //! Destructor virtual ~iterable_proxy() noexcept = default; //! Copy assignment operator iterable_proxy& operator=(const iterable_proxy &other) = default; //! Move assignment operator iterable_proxy& operator=(iterable_proxy &&other) = default; class iterator { public: using InternalReferences = MatTB::ReferenceTuple_t; using value_type = std::tuple, Stress_tTup, InternalReferences>; using iterator_category = std::forward_iterator_tag; //! Default constructor iterator() = delete; /** Iterator uses the material's internal variables field collection to iterate selectively over the global fields (such as the transformation gradient F and first Piola-Kirchhoff stress P. **/ iterator(const iterable_proxy & it, bool begin = true) : it{it}, strain_map{it.strain_field}, stress_map {it.stress_tup}, index{begin ? 0:it.material.internal_fields.size()}{} //! Copy constructor iterator(const iterator &other) = default; //! Move constructor iterator(iterator &&other) noexcept = default; //! Destructor virtual ~iterator() noexcept = default; //! Copy assignment operator iterator& operator=(const iterator &other) = default; //! Move assignment operator iterator& operator=(iterator &&other) = default; //! pre-increment inline iterator & operator++(); //! dereference inline value_type operator*(); //! inequality inline bool operator!=(const iterator & other) const; protected: const iterable_proxy & it; StrainMap_t strain_map; StressMapTup stress_map; size_t index; private: }; iterator begin() {return std::move(iterator(*this));} iterator end() {return std::move(iterator(*this, false));} protected: const MaterialMuSpectre & material; const StrainField_t & strain_field; StressFieldTup stress_tup; const InternalVariables & internals; private: }; /* ---------------------------------------------------------------------- */ template template bool MaterialMuSpectre::iterable_proxy::iterator:: operator!=(const iterator & other) const { return (this->index != other.index); } /* ---------------------------------------------------------------------- */ template template typename MaterialMuSpectre:: template iterable_proxy:: iterator & MaterialMuSpectre::iterable_proxy::iterator:: operator++() { this->index++; return *this; } /* ---------------------------------------------------------------------- */ template template typename MaterialMuSpectre:: template iterable_proxy::iterator:: value_type MaterialMuSpectre::iterable_proxy::iterator:: operator*() { const Ccoord_t pixel{ this->it.material.internal_fields.get_ccoord(this->index)}; auto && strain = std::make_tuple(this->strain_map[pixel]); auto && stresses = apply([&pixel] (auto && ... stress_tgt) { return std::make_tuple(stress_tgt[pixel]...);}, this->stress_map); const auto & internal = this->it.material.get_internals(); const auto id{index}; auto && internals = apply([id] (auto && ... internals) { return std::make_tuple(internals[id]...);}, internal); return std::make_tuple(std::move(strain), std::move(stresses), std::move(internals)); } } // muSpectre #endif /* MATERIAL_MUSPECTRE_BASE_H */ diff --git a/src/materials/materials_toolbox.hh b/src/materials/materials_toolbox.hh index 6de396b..3efea0d 100644 --- a/src/materials/materials_toolbox.hh +++ b/src/materials/materials_toolbox.hh @@ -1,327 +1,327 @@ /** * file materials_toolbox.hh * * @author Till Junge * * @date 02 Nov 2017 * * @brief collection of common continuum mechanics tools * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef MATERIALS_TOOLBOX_H #define MATERIALS_TOOLBOX_H #include "common/common.hh" #include "common/tensor_algebra.hh" #include "common/eigen_tools.hh" #include "common/T4_map_proxy.hh" #include #include #include #include #include #include namespace muSpectre { namespace MatTB { class MaterialsToolboxError:public std::runtime_error{ public: explicit MaterialsToolboxError(const std::string& what) :std::runtime_error(what){} explicit MaterialsToolboxError(const char * what) :std::runtime_error(what){} }; /* ---------------------------------------------------------------------- */ /** * Flag used to designate whether the material should compute both stress * and tangent moduli or only stress */ enum class NeedTangent { yes, // compute both stress and tangent moduli no}; // compute only stress /** * Struct with a single variadic function only used to determine the * tuple type to store in the various sub-iterators or to return */ template struct StoredTuple { template decltype(auto) operator()(Args && ... args) { return std::tie(args ... ); } }; /** * struct used to determine the exact type of a tuple of references obtained * when a bunch of iterators over fiel_maps are dereferenced and their * results are concatenated into a tuple */ template struct ReferenceTuple { using type = std::tuple; }; /** * specialisation for tuples */ //template <> template struct ReferenceTuple> { using type = typename ReferenceTuple::type; }; /** * helper type for ReferenceTuple */ template using ReferenceTuple_t = typename ReferenceTuple::type; /* ---------------------------------------------------------------------- */ /** Structure for functions returning one strain measure as a function of another **/ namespace internal { template struct ConvertStrain { static_assert((In == StrainMeasure::Gradient) || (In == StrainMeasure::Infinitesimal), "This situation makes me suspect that you are not using " "MatTb as intended. Disable this assert only if you are " "sure about what you are doing."); template inline static decltype(auto) compute(Strain_t&& input) { // transparent case, in which no conversion is required: // just a perfect forwarding static_assert ((In == Out), "This particular strain conversion is not implemented"); return std::forward(input); } }; /* ---------------------------------------------------------------------- */ /** Specialisation for getting Green-Lagrange strain from the transformation gradient **/ template <> struct ConvertStrain { template inline static decltype(auto) compute(Strain_t&& F) { return .5*(F.transpose()*F - Strain_t::PlainObject::Identity()); } }; } // internal /* ---------------------------------------------------------------------- */ //! set of functions returning one strain measure as a function of //! another template decltype(auto) convert_strain(Strain_t && strain) { return internal::ConvertStrain::compute(std::move(strain)); }; /* ---------------------------------------------------------------------- */ /** Structure for functions returning PK1 stress from other stress measures **/ namespace internal { template struct PK1_stress { template inline static decltype(auto) compute(Strain_t && /*strain*/, Stress_t && /*stress*/) { // the following test always fails to generate a compile-time error static_assert((StressM == StressMeasure::Cauchy) && (StressM == StressMeasure::PK1), "The requested Stress conversion is not implemented. " "You either made a programming mistake or need to " "implement it as a specialisation of this function. " "See PK2stress for an example."); } template inline static decltype(auto) compute(Strain_t && /*strain*/, Stress_t && /*stress*/, Tangent_t && /*stiffness*/) { // the following test always fails to generate a compile-time error static_assert((StressM == StressMeasure::Cauchy) && (StressM == StressMeasure::PK1), "The requested Stress conversion is not implemented. " "You either made a programming mistake or need to " "implement it as a specialisation of this function. " "See PK2stress for an example."); } }; /* ---------------------------------------------------------------------- */ /** Specialisation for the transparent case, where we already have PK1 stress **/ template struct PK1_stress: public PK1_stress { template inline static decltype(auto) compute(Strain_t && /*dummy*/, Stress_t && P) { return std::forward(P); } }; /* ---------------------------------------------------------------------- */ /** Specialisation for the transparent case, where we already have PK1 stress *and* stiffness is given with respect to the transformation gradient **/ template struct PK1_stress: public PK1_stress { using Parent = PK1_stress; using Parent::compute; template inline static decltype(auto) compute(Strain_t && /*dummy*/, Stress_t && P, Tangent_t && K) { return std::make_tuple(std::forward(P), std::forward(K)); } }; /* ---------------------------------------------------------------------- */ /** * Specialisation for the case where we get material stress (PK2) */ template struct PK1_stress: public PK1_stress { template inline static decltype(auto) compute(Strain_t && F, Stress_t && S) { return F*S; } }; /* ---------------------------------------------------------------------- */ /** * Specialisation for the case where we get material stress (PK2) derived * with respect to Green-Lagrange strain */ template struct PK1_stress: public PK1_stress { using Parent = PK1_stress; using Parent::compute; template inline static decltype(auto) compute(Strain_t && F, Stress_t && S, Tangent_t && C) { using T4 = typename std::remove_reference_t::PlainObject; using Tmap = T4MatMap; T4 K; Tmap Kmap{K.data()}; K.setZero(); for (int i = 0; i < Dim; ++i) { for (int m = 0; m < Dim; ++m) { for (int n = 0; n < Dim; ++n) { get(Kmap,i,m,i,n) += S(m,n); for (int j = 0; j < Dim; ++j) { for (int r = 0; r < Dim; ++r) { for (int s = 0; s < Dim; ++s) { get(Kmap,i,m,j,n) += F(i,r)*get(C,r,m,n,s)*(F(j,s)); } } } } } } auto && P = compute(std::forward(F), std::forward(S)); return std::make_tuple(std::move(P), std::move(K)); } }; } // internal /* ---------------------------------------------------------------------- */ //! set of functions returning an expression for PK2 stress based on template decltype(auto) PK1_stress(Strain_t && strain, Stress_t && stress) { constexpr Dim_t dim{EigenCheck::tensor_dim::value}; static_assert((dim == EigenCheck::tensor_dim::value), "Stress and strain tensors have differing dimensions"); return internal::PK1_stress::compute (std::forward(strain), std::forward(stress)); }; /* ---------------------------------------------------------------------- */ //! set of functions returning an expression for PK2 stress based on template decltype(auto) PK1_stress(Strain_t && strain, Stress_t && stress, Tangent_t && tangent) { constexpr Dim_t dim{EigenCheck::tensor_dim::value}; static_assert((dim == EigenCheck::tensor_dim::value), "Stress and strain tensors have differing dimensions"); static_assert((dim== EigenCheck::tensor_4_dim::value), "Stress and tangent tensors have differing dimensions"); return internal::PK1_stress::compute (std::forward(strain), std::forward(stress), std::forward(tangent)); }; } // MatTB } // muSpectre #endif /* MATERIALS_TOOLBOX_H */ diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 61dd575..f27ea67 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -1,10 +1,39 @@ +# ============================================================================= +# file CMakeLists.txt +# +# @author Till Junge +# +# @date 08 Jan 2018 +# +# @brief configuration for solvers +# +# @section LICENCE +# +# Copyright © 2018 Till Junge +# +# µSpectre 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, or (at +# your option) any later version. +# +# µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# ============================================================================= + set (solvers_SRC ${CMAKE_CURRENT_SOURCE_DIR}/solver_base.cc ${CMAKE_CURRENT_SOURCE_DIR}/solver_cg.cc ${CMAKE_CURRENT_SOURCE_DIR}/solvers.cc ) set (muSpectre_SRC ${muSpectre_SRC} ${solvers_SRC} PARENT_SCOPE) diff --git a/src/solver/solver_base.cc b/src/solver/solver_base.cc index da03281..28a64eb 100644 --- a/src/solver/solver_base.cc +++ b/src/solver/solver_base.cc @@ -1,40 +1,40 @@ /** * file solver_base.cc * * @author Till Junge * * @date 18 Dec 2017 * * @brief definitions for solvers * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "solver/solver_base.hh" #include "solver/solver_cg.hh" #include "common/field.hh" #include "common/iterators.hh" #include #include namespace muSpectre { } // muSpectre diff --git a/src/solver/solver_base.hh b/src/solver/solver_base.hh index af0b355..f4ee868 100644 --- a/src/solver/solver_base.hh +++ b/src/solver/solver_base.hh @@ -1,98 +1,98 @@ /** * file solver_base.hh * * @author Till Junge * * @date 18 Dec 2017 * * @brief Base class for solvers * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef SOLVER_BASE_H #define SOLVER_BASE_H #include "solver/solver_error.hh" #include "common/common.hh" #include "system/system_base.hh" #include "common/tensor_algebra.hh" #include #include namespace muSpectre { /* ---------------------------------------------------------------------- */ template class SolverBase { public: enum class TangentRequirement{NoNeed, NeedEffect, NeedTangents}; using Ccoord = Ccoord_t; using Collection_t = GlobalFieldCollection; //! Default constructor SolverBase() = delete; //! Constructor with domain resolutions SolverBase(Ccoord resolutions): resolutions{resolutions} {} //! Copy constructor SolverBase(const SolverBase &other) = delete; //! Move constructor SolverBase(SolverBase &&other) = default; //! Destructor virtual ~SolverBase() noexcept = default; //! Copy assignment operator SolverBase& operator=(const SolverBase &other) = delete; //! Move assignment operator SolverBase& operator=(SolverBase &&other) = default; //! Allocate fields used during the solution void initialise() {this->collection.initialise(resolutions);} bool need_tangents() const { return (this->get_tangent_req() == TangentRequirement::NeedTangents);} bool need_effect() const { return (this->get_tangent_req() == TangentRequirement::NeedEffect);} bool no_need_tangent() const { return (this->get_tangent_req() == TangentRequirement::NoNeed);} bool has_converged() const {return this->converged;} protected: virtual TangentRequirement get_tangent_req() const = 0; Ccoord resolutions; //! storage for internal fields to avoid reallocations between calls Collection_t collection{}; bool converged{false}; private: }; } // muSpectre #endif /* SOLVER_BASE_H */ diff --git a/src/solver/solver_cg.cc b/src/solver/solver_cg.cc index 512a8fb..9fc2200 100644 --- a/src/solver/solver_cg.cc +++ b/src/solver/solver_cg.cc @@ -1,113 +1,113 @@ /** * file solver_cg.cc * * @author Till Junge * * @date 20 Dec 2017 * * @brief Implementation of cg solver * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "solver/solver_cg.hh" #include "solver/solver_error.hh" #include #include namespace muSpectre { /* ---------------------------------------------------------------------- */ template SolverCG::SolverCG(Ccoord resolutions, Real tol, Uint maxiter, bool verbose) :Parent(resolutions), r_k{make_field("residual r_k", this->collection)}, p_k{make_field("search direction r_k", this->collection)}, Ap_k{make_field("Effect of tangent A*p_k", this->collection)}, tol{tol}, maxiter{maxiter}, verbose{verbose} {} /* ---------------------------------------------------------------------- */ template void SolverCG::solve(const Fun_t& tangent_effect, const Field_t & rhs, Field_t & x_f) { // Following implementation of algorithm 5.2 in Nocedal's Numerical Optimization (p. 112) auto r = this->r_k.eigen(); auto p = this->p_k.eigen(); auto Ap = this->Ap_k.eigen(); auto x = x_f.eigen(); // initialisation of algo tangent_effect(x_f, this->r_k); r -= rhs.eigen(); p = -r; this->converged = false; Real rdr = (r*r).sum(); Real tol2 = ipow(this->tol,2); size_t count_width{}; // for output formatting in verbose case if (this->verbose) { count_width = size_t(std::log10(this->maxiter))+1; } for (Uint i = 0; i < this->maxiter && rdr > tol2; ++i) { tangent_effect(this->p_k, this->Ap_k); Real alpha = rdr/(p*Ap).sum(); x += alpha * p; r += alpha * Ap; Real new_rdr = (r*r).sum(); Real beta = new_rdr/rdr; rdr = new_rdr; if (this->verbose) { std::cout << " at CG step " << std::setw(count_width) << i << ": |r| = " << std::setw(17) << std::sqrt(rdr) << ", cg_tol = " << this->tol << std::endl; } p = -r+beta*p; } if (rdr < tol2) { this->converged=true; } else { throw ConvergenceError("Conjugate gradient has not converged"); } } /* ---------------------------------------------------------------------- */ template typename SolverCG::Tg_req_t SolverCG::get_tangent_req() const { return tangent_requirement; } template class SolverCG; //template class SolverCG; template class SolverCG; } // muSpectre diff --git a/src/solver/solver_cg.hh b/src/solver/solver_cg.hh index 23f0619..7af6578 100644 --- a/src/solver/solver_cg.hh +++ b/src/solver/solver_cg.hh @@ -1,96 +1,96 @@ /** * file solver_cg.hh * * @author Till Junge * * @date 20 Dec 2017 * * @brief class for a simple implementation of a conjugate gradient * solver. This follows algorithm 5.2 in Nocedal's Numerical * Optimization (p 112) * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef SOLVER_CG_H #define SOLVER_CG_H #include "solver/solver_base.hh" #include "common/field.hh" #include namespace muSpectre { template class SolverCG: public SolverBase { public: using Parent = SolverBase; using Ccoord = typename Parent::Ccoord; using Tg_req_t = typename Parent::TangentRequirement; // cg only needs to handle fields that look like strain and stress using Field_t = TensorField< typename Parent::Collection_t, Real, secondOrder, DimM>; using Fun_t = std::function; constexpr static Tg_req_t tangent_requirement{Tg_req_t::NeedEffect}; //! Default constructor SolverCG() = delete; //! Constructor with domain resolutions, etc, SolverCG(Ccoord resolutions, Real tol, Uint maxiter=0, bool verbose =false); //! Copy constructor SolverCG(const SolverCG &other) = delete; //! Move constructor SolverCG(SolverCG &&other) noexcept = default; //! Destructor virtual ~SolverCG() noexcept = default; //! Copy assignment operator SolverCG& operator=(const SolverCG &other) = delete; //! Move assignment operator SolverCG& operator=(SolverCG &&other) = default; //! actual solver void solve(const Fun_t & tangent_effect, const Field_t & rhs, Field_t & x); protected: Tg_req_t get_tangent_req() const override final; Field_t & r_k; // residual Field_t & p_k; // search direction Field_t & Ap_k; // effect of tangent on search direction const Real tol; const Uint maxiter; const bool verbose; private: }; } // muSpectre #endif /* SOLVER_CG_H */ diff --git a/src/solver/solver_error.hh b/src/solver/solver_error.hh index 84be5bd..76a5c9d 100644 --- a/src/solver/solver_error.hh +++ b/src/solver/solver_error.hh @@ -1,48 +1,48 @@ /** * file solver_error.hh * * @author Till Junge * * @date 28 Dec 2017 * * @brief Errors raised by solvers * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef SOLVER_ERROR_H #define SOLVER_ERROR_H #include namespace muSpectre { class SolverError: public std::runtime_error { using runtime_error::runtime_error; }; class ConvergenceError: public SolverError { using SolverError::SolverError; }; } // muSpectre #endif /* SOLVER_ERROR_H */ diff --git a/src/solver/solvers.cc b/src/solver/solvers.cc index b355061..51c96a1 100644 --- a/src/solver/solvers.cc +++ b/src/solver/solvers.cc @@ -1,301 +1,301 @@ /** * file solvers.cc * * @author Till Junge * * @date 20 Dec 2017 * * @brief implementation of solver functions * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "solver/solvers.hh" #include "solver/solver_cg.hh" #include "common/iterators.hh" #include #include namespace muSpectre { template typename SystemBase::StrainField_t & de_geus (SystemBase & sys, const GradIncrements & delFs, Formulation form, const Real cg_tol, const Real newton_tol, Uint maxiter, Dim_t verbose) { using Field_t = typename MaterialBase::StrainField_t; auto solver_fields{std::make_unique>()}; solver_fields->initialise(sys.get_resolutions()); // Corresponds to symbol δF or δε auto & incrF{make_field("δF", *solver_fields)}; // Corresponds to symbol ΔF or Δε auto & DeltaF{make_field("ΔF", *solver_fields)}; // field to store the rhs for cg calculations auto & rhs{make_field("rhs", *solver_fields)}; SolverCG cg(sys.get_resolutions(), cg_tol, maxiter, verbose-1>0); cg.initialise(); if (maxiter == 0) { maxiter = sys.size()*DimM*DimM*10; } size_t count_width{}; if (verbose > 0) { //setup of algorithm 5.2 in Nocedal, Numerical Optimization (p. 111) std::cout << "Algo 5.2 with newton_tol = " << newton_tol << ", cg_tol = " << cg_tol << " maxiter = " << maxiter << " and ΔF =" <(tup)}; auto && grad{std::get<1>(tup)}; std::cout << "Step " << counter + 1 << ":" << std::endl << grad << std::endl; } count_width = size_t(std::log10(maxiter))+1; } // initialise F = I or ε = 0 auto & F{sys.get_strain()}; switch (form) { case Formulation::finite_strain: { F.get_map() = Matrices::I2(); break; } case Formulation::small_strain: { F.get_map() = Matrices::I2().Zero(); break; } default: throw SolverError("Unknown formulation"); break; } // initialise materials constexpr bool need_tangent{true}; sys.initialise_materials(need_tangent); Grad_t previous_grad{Grad_t::Zero()}; for (const auto & delF: delFs) { //incremental loop Real incrNorm{2*newton_tol}, gradNorm{1}; for (Uint newt_iter{0}; (newt_iter < maxiter) && ((incrNorm/gradNorm > newton_tol) || (newt_iter==1)); ++newt_iter) { // obtain material response auto res_tup{sys.evaluate_stress_tangent(F)}; auto & P{std::get<0>(res_tup)}; auto & K{std::get<1>(res_tup)}; auto tangent_effect = [&sys, &K] (const Field_t & delF, Field_t & delP) { sys.directional_stiffness(K, delF, delP); }; if (newt_iter == 0) { DeltaF.get_map() = -(delF-previous_grad); // neg sign because rhs tangent_effect(DeltaF, rhs); cg.solve(tangent_effect, rhs, incrF); F.eigen() -= DeltaF.eigen(); } else { rhs.eigen() = -P.eigen(); sys.project(rhs); cg.solve(tangent_effect, rhs, incrF); } F.eigen() += incrF.eigen(); incrNorm = incrF.eigen().matrix().norm(); gradNorm = F.eigen().matrix().norm(); if (verbose>0) { std::cout << "at Newton step " << std::setw(count_width) << newt_iter << ", |δF|/|ΔF| = " << std::setw(17) << incrNorm/gradNorm << ", tol = " << newton_tol << std::endl; if (verbose>1) { std::cout << " =" << std::endl << F.get_map().mean() << std::endl; } } } // update previous gradient previous_grad = delF; //store history variables here } return F; } template typename SystemBase::StrainField_t & de_geus (SystemBase & sys, const GradIncrements& delF0, Formulation form, const Real cg_tol, const Real newton_tol, Uint maxiter, Dim_t verbose); // template typename SystemBase::StrainField_t & // de_geus (SystemBase & sys, const GradIncrements& delF0, // const Real cg_tol, const Real newton_tol, Uint maxiter, // Dim_t verbose); template typename SystemBase::StrainField_t & de_geus (SystemBase & sys, const GradIncrements& delF0, Formulation form, const Real cg_tol, const Real newton_tol, Uint maxiter, Dim_t verbose); /* ---------------------------------------------------------------------- */ template typename SystemBase::StrainField_t & newton_cg (SystemBase & sys, const GradIncrements & delFs, Formulation form, const Real cg_tol, const Real newton_tol, Uint maxiter, Dim_t verbose) { using Field_t = typename MaterialBase::StrainField_t; auto solver_fields{std::make_unique>()}; solver_fields->initialise(sys.get_resolutions()); // Corresponds to symbol δF or δε auto & incrF{make_field("δF", *solver_fields)}; // field to store the rhs for cg calculations auto & rhs{make_field("rhs", *solver_fields)}; SolverCG cg(sys.get_resolutions(), cg_tol, maxiter, verbose-1>0); cg.initialise(); if (maxiter == 0) { maxiter = sys.size()*DimM*DimM*10; } size_t count_width{}; if (verbose > 0) { //setup of algorithm 5.2 in Nocedal, Numerical Optimization (p. 111) std::cout << "Algo 5.2 with newton_tol = " << newton_tol << ", cg_tol = " << cg_tol << " maxiter = " << maxiter << " and ΔF =" <(tup)}; auto && grad{std::get<1>(tup)}; std::cout << "Step " << counter + 1 << ":" << std::endl << grad << std::endl; } count_width = size_t(std::log10(maxiter))+1; } // initialise F = I or ε = 0 auto & F{sys.get_strain()}; switch (form) { case Formulation::finite_strain: { F.get_map() = Matrices::I2(); break; } case Formulation::small_strain: { F.get_map() = Matrices::I2().Zero(); break; } default: throw SolverError("Unknown formulation"); break; } // initialise materials constexpr bool need_tangent{true}; sys.initialise_materials(need_tangent); Grad_t previous_grad{Grad_t::Zero()}; for (const auto & delF: delFs) { //incremental loop // apply macroscopic strain increment for (auto && grad: F.get_map()) { grad += delF - previous_grad; } Real incrNorm{2*newton_tol}, gradNorm{1}; for (Uint newt_iter{0}; newt_iter < maxiter && incrNorm/gradNorm> newton_tol; ++newt_iter) { // obtain material response auto res_tup{sys.evaluate_stress_tangent(F)}; auto & P{std::get<0>(res_tup)}; auto & K{std::get<1>(res_tup)}; auto fun = [&sys, &K] (const Field_t & delF, Field_t & delP) { sys.directional_stiffness(K, delF, delP); }; rhs.eigen() = -P.eigen(); sys.project(rhs); cg.solve(fun, rhs, incrF); F.eigen() += incrF.eigen(); incrNorm = incrF.eigen().matrix().norm(); gradNorm = F.eigen().matrix().norm(); if (verbose > 0) { std::cout << "at Newton step " << std::setw(count_width) << newt_iter << ", |δF|/|ΔF| = " << std::setw(17) << incrNorm/gradNorm << ", tol = " << newton_tol << std::endl; if (verbose>1) { std::cout << " =" << std::endl << F.get_map().mean() << std::endl; } } } // update previous gradient previous_grad = delF; //store history variables here } return F; } template typename SystemBase::StrainField_t & newton_cg (SystemBase & sys, const GradIncrements& delF0, Formulation form, const Real cg_tol, const Real newton_tol, Uint maxiter, Dim_t verbose); // template typename SystemBase::StrainField_t & // newton_cg (SystemBase & sys, const GradIncrements& delF0, // const Real cg_tol, const Real newton_tol, Uint maxiter, // Dim_t verbose); template typename SystemBase::StrainField_t & newton_cg (SystemBase & sys, const GradIncrements& delF0, Formulation form, const Real cg_tol, const Real newton_tol, Uint maxiter, Dim_t verbose); } // muSpectre diff --git a/src/solver/solvers.hh b/src/solver/solvers.hh index 1e3fee0..c08baa2 100644 --- a/src/solver/solvers.hh +++ b/src/solver/solvers.hh @@ -1,85 +1,85 @@ /** * file solvers.hh * * @author Till Junge * * @date 20 Dec 2017 * * @brief Free functions for solving * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef SOLVERS_H #define SOLVERS_H #include "solver/solver_cg.hh" namespace muSpectre { template using Grad_t = Matrices::Tens2_t; template using GradIncrements = std::vector, Eigen::aligned_allocator>>; /* ---------------------------------------------------------------------- */ template typename SystemBase::StrainField_t & newton_cg (SystemBase & sys, const GradIncrements & delF0, Formulation form, const Real cg_tol, const Real newton_tol, const Uint maxiter=0, Dim_t verbose = 0); /* ---------------------------------------------------------------------- */ template inline typename SystemBase::StrainField_t & newton_cg (SystemBase & sys, const Grad_t & delF0, Formulation form, const Real cg_tol, const Real newton_tol, const Uint maxiter=0, Dim_t verbose = 0){ return newton_cg(sys, GradIncrements{delF0}, form, cg_tol, newton_tol, maxiter, verbose); } /* ---------------------------------------------------------------------- */ template typename SystemBase::StrainField_t & de_geus (SystemBase & sys, const GradIncrements & delF0, Formulation form, const Real cg_tol, const Real newton_tol, const Uint maxiter=0, Dim_t verbose = 0); /* ---------------------------------------------------------------------- */ template inline typename SystemBase::StrainField_t & de_geus (SystemBase & sys, const Grad_t & delF0, Formulation form, const Real cg_tol, const Real newton_tol, const Uint maxiter=0, Dim_t verbose = 0){ return de_geus(sys, GradIncrements{delF0}, form, cg_tol, newton_tol, maxiter, verbose); } } // muSpectre #endif /* SOLVERS_H */ diff --git a/src/system/CMakeLists.txt b/src/system/CMakeLists.txt index f5deb17..0666e16 100644 --- a/src/system/CMakeLists.txt +++ b/src/system/CMakeLists.txt @@ -1,8 +1,37 @@ +# ============================================================================= +# file CMakeLists.txt +# +# @author Till Junge +# +# @date 08 Jan 2018 +# +# @brief configuration for system implementations +# +# @section LICENCE +# +# Copyright © 2018 Till Junge +# +# µSpectre 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, or (at +# your option) any later version. +# +# µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# ============================================================================= + set (systems_SRC ${CMAKE_CURRENT_SOURCE_DIR}/system_base.cc ) set (muSpectre_SRC ${muSpectre_SRC} ${systems_SRC} PARENT_SCOPE) diff --git a/src/system/system_base.cc b/src/system/system_base.cc index 97dd2c3..1a8555e 100644 --- a/src/system/system_base.cc +++ b/src/system/system_base.cc @@ -1,202 +1,202 @@ /** * file system_base.cc * * @author Till Junge * * @date 01 Nov 2017 * * @brief Implementation for system base class * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "system/system_base.hh" #include "common/ccoord_operations.hh" #include "common/iterators.hh" #include "common/tensor_algebra.hh" #include #include namespace muSpectre { /* ---------------------------------------------------------------------- */ template SystemBase::SystemBase(Projection_ptr projection_, Formulation form) :resolutions{projection_->get_resolutions()}, pixels(resolutions), lengths{projection_->get_lengths()}, fields{}, F{make_field("Gradient", this->fields)}, P{make_field("Piola-Kirchhoff-1", this->fields)}, projection{std::move(projection_)}, form{form} { } /* ---------------------------------------------------------------------- */ template void SystemBase::add_material(Material_ptr mat) { this->materials.push_back(std::move(mat)); } /* ---------------------------------------------------------------------- */ template typename SystemBase::FullResponse_t SystemBase::evaluate_stress_tangent(StrainField_t & grad) { if (this->is_initialised == false) { this->initialise(); } //! High level compatibility checks if (grad.size() != this->F.size()) { throw std::runtime_error("Size mismatch"); } if (!this->K) { this->K = make_field("Tangent Stiffness", this->fields); } for (auto & mat: this->materials) { mat->compute_stresses_tangent(grad, this->P, this->K.value(), this->form); } return std::tie(this->P, this->K.value()); } /* ---------------------------------------------------------------------- */ template typename SystemBase::StressField_t & SystemBase::directional_stiffness(const TangentField_t &K, const StrainField_t &delF, StressField_t &delP) { for (auto && tup: akantu::zip(K.get_map(), delF.get_map(), delP.get_map())){ auto & k = std::get<0>(tup); auto & df = std::get<1>(tup); auto & dp = std::get<2>(tup); dp = Matrices::tensmult(k, df); } return this->project(delP); } /* ---------------------------------------------------------------------- */ template typename SystemBase::StressField_t & SystemBase::project(StressField_t &field) { this->projection->apply_projection(field); return field; } /* ---------------------------------------------------------------------- */ template typename SystemBase::StrainField_t & SystemBase::get_strain() { if (this->is_initialised == false) { this->initialise(); } return this->F; } /* ---------------------------------------------------------------------- */ template const typename SystemBase::StressField_t & SystemBase::get_stress() const { return this->P; } /* ---------------------------------------------------------------------- */ template void SystemBase::initialise(FFT_PlanFlags flags) { // check that all pixels have been assigned exactly one material this->check_material_coverage(); // resize all global fields (strain, stress, etc) this->fields.initialise(this->resolutions); // initialise the projection and compute the fft plan this->projection->initialise(flags); this->is_initialised = true; } /* ---------------------------------------------------------------------- */ template void SystemBase::initialise_materials(bool stiffness) { for (auto && mat: this->materials) { mat->initialise(stiffness); } } /* ---------------------------------------------------------------------- */ template typename SystemBase::iterator SystemBase::begin() { return this->pixels.begin(); } /* ---------------------------------------------------------------------- */ template typename SystemBase::iterator SystemBase::end() { return this->pixels.end(); } /* ---------------------------------------------------------------------- */ template void SystemBase::check_material_coverage() { auto nb_pixels = CcoordOps::get_size(this->resolutions); std::vector*> assignments(nb_pixels, nullptr); for (auto & mat: this->materials) { for (auto & pixel: *mat) { auto index = CcoordOps::get_index(this->resolutions, pixel); auto& assignment{assignments.at(index)}; if (assignment != nullptr) { std::stringstream err{}; err << "Pixel " << pixel << "is already assigned to material '" << assignment->get_name() << "' and cannot be reassigned to material '" << mat->get_name(); throw std::runtime_error(err.str()); } else { assignments[index] = mat.get(); } } } // find and identify unassigned pixels std::vector unassigned_pixels; for (size_t i = 0; i < assignments.size(); ++i) { if (assignments[i] == nullptr) { unassigned_pixels.push_back(CcoordOps::get_ccoord(this->resolutions, i)); } } if (unassigned_pixels.size() != 0) { std::stringstream err {}; err << "The following pixels have were not assigned a material: "; for (auto & pixel: unassigned_pixels) { err << pixel << ", "; } err << "and that cannot be handled"; throw std::runtime_error(err.str()); } } template class SystemBase; template class SystemBase; } // muSpectre diff --git a/src/system/system_base.hh b/src/system/system_base.hh index 8be827d..c4f09ff 100644 --- a/src/system/system_base.hh +++ b/src/system/system_base.hh @@ -1,160 +1,160 @@ /** * file system_base.hh * * @author Till Junge * * @date 01 Nov 2017 * * @brief Base class representing a unit cell system with single * projection operator * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef SYSTEM_BASE_H #define SYSTEM_BASE_H #include "common/common.hh" #include "common/ccoord_operations.hh" #include "common/field.hh" #include "common/utilities.hh" #include "materials/material_base.hh" #include "fft/projection_base.hh" #include #include #include #include namespace muSpectre { //! DimS spatial dimension (dimension of problem //! DimM material_dimension (dimension of constitutive law) template class SystemBase { public: using Ccoord = Ccoord_t; using Rcoord = Rcoord_t; using FieldCollection_t = FieldCollection; using Material_t = MaterialBase; using Material_ptr = std::unique_ptr; using Projection_ptr = std::unique_ptr>; using StrainField_t = TensorField; using StressField_t = TensorField; using TangentField_t = TensorField; using FullResponse_t = std::tuple; using iterator = typename CcoordOps::Pixels::iterator; //! Default constructor SystemBase() = delete; //! constructor using sizes and resolution SystemBase(Projection_ptr projection, Formulation form=Formulation::finite_strain); //! Copy constructor SystemBase(const SystemBase &other) = delete; //! Move constructor SystemBase(SystemBase &&other) noexcept = default; //! Destructor virtual ~SystemBase() noexcept = default; //! Copy assignment operator SystemBase& operator=(const SystemBase &other) = delete; //! Move assignment operator SystemBase& operator=(SystemBase &&other) = default; /** * Materials can only be moved. This is to assure exclusive * ownership of any material by this system */ void add_material(Material_ptr mat); /** * evaluates all materials */ FullResponse_t evaluate_stress_tangent(StrainField_t & F); /** * evaluate directional stiffness (i.e. G:K:δF) */ StressField_t & directional_stiffness(const TangentField_t & K, const StrainField_t & delF, StressField_t & delP); /** * Convenience function circumventing the neeed to use the * underlying projection */ StressField_t & project(StressField_t & field); StrainField_t & get_strain(); const StressField_t & get_stress() const; /** * general initialisation; initialises the projection and * fft_engine (i.e. infrastructure) but not the materials. These * need to be initialised separately */ void initialise(FFT_PlanFlags flags = FFT_PlanFlags::estimate); /** * initialise materials (including resetting any history variables) */ void initialise_materials(bool stiffness=false); iterator begin(); iterator end(); size_t size() const {return pixels.size();} const Ccoord & get_resolutions() const {return this->resolutions;} const Rcoord & get_lengths() const {return this->lengths;} protected: //! make sure that every pixel is assigned to one and only one material void check_material_coverage(); const Ccoord & resolutions; CcoordOps::Pixels pixels; const Rcoord & lengths; FieldCollection_t fields; StrainField_t & F; StressField_t & P; //! Tangent field might not even be required; so this is an //! optional ref_wrapper instead of a ref optional> K{}; std::vector materials{}; Projection_ptr projection; Formulation form; bool is_initialised{false}; private: }; } // muSpectre #endif /* SYSTEM_BASE_H */ diff --git a/src/system/system_factory.hh b/src/system/system_factory.hh index 46f8e25..cffbc11 100644 --- a/src/system/system_factory.hh +++ b/src/system/system_factory.hh @@ -1,82 +1,82 @@ /** * file system_factory.hh * * @author Till Junge * * @date 15 Dec 2017 * * @brief System factories to help create systems with ease * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef SYSTEM_FACTORY_H #define SYSTEM_FACTORY_H #include "common/common.hh" #include "common/ccoord_operations.hh" #include "system/system_base.hh" #include "fft/projection_finite_strain_fast.hh" #include "fft/projection_finite_strain.hh" #include "fft/fftw_engine.hh" #include namespace muSpectre { /** * Create a unique ptr to a Projection operator (with appropriate * FFT_engine) to be used in a system constructor */ template , typename Projection=ProjectionFiniteStrainFast> inline std::unique_ptr system_input(Ccoord_t resolutions, Rcoord_t lengths=CcoordOps::get_cube(1.)) { auto fft_ptr{std::make_unique(resolutions, lengths)}; return std::make_unique(std::move(fft_ptr)); } /** * convenience function to create a system (avoids having to build * and move the chain of unique_ptrs */ template , typename FFT_Engine=FFTW_Engine, typename Projection=ProjectionFiniteStrainFast> inline System make_system(Ccoord_t resolutions, Rcoord_t lengths=CcoordOps::get_cube(1.), Formulation form=Formulation::finite_strain) { return System{ std::move(system_input (resolutions, lengths)), form}; } } // muSpectre #endif /* SYSTEM_FACTORY_H */ diff --git a/tests/main_test_suite.cc b/tests/main_test_suite.cc index e6e84ca..1013d32 100644 --- a/tests/main_test_suite.cc +++ b/tests/main_test_suite.cc @@ -1,35 +1,35 @@ /** * file main_test_suite.cc * * @author Till Junge * * @date 01 May 2017 * * @brief Main test suite. Running this suite tests all available tests for * µSpectre * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #define BOOST_TEST_MODULE base_test test #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK #include diff --git a/tests/test_base.cc b/tests/test_base.cc index 1f85b13..755c1e2 100644 --- a/tests/test_base.cc +++ b/tests/test_base.cc @@ -1,36 +1,36 @@ /** * file test_base.cc * * @author Till Junge * * @date 01 May 2017 * * @brief Base test (tests only whether the tests compile * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #define BOOST_TEST_DYN_LINK #include BOOST_AUTO_TEST_CASE(base_test) { BOOST_CHECK_EQUAL(1, 2-1); } diff --git a/tests/test_ccoord_operations.cc b/tests/test_ccoord_operations.cc index 54180e8..432bf8e 100644 --- a/tests/test_ccoord_operations.cc +++ b/tests/test_ccoord_operations.cc @@ -1,154 +1,154 @@ /** * file test_ccoord_operations.cc * * @author Till Junge * * @date 03 Dec 2017 * * @brief tests for cell coordinate operations * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "common/common.hh" #include "common/ccoord_operations.hh" #include "common/test_goodies.hh" #include "tests.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(ccoords_operations); BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_cube, Fix, testGoodies::dimlist, Fix) { constexpr auto dim{Fix::dim}; using Ccoord = Ccoord_t; constexpr Dim_t size{5}; constexpr Ccoord cube = CcoordOps::get_cube(size); Ccoord ref_cube; for (Dim_t i = 0; i < dim; ++i) { ref_cube[i] = size; } BOOST_CHECK_EQUAL_COLLECTIONS(ref_cube.begin(), ref_cube.end(), cube.begin(), cube.end()); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_hermitian, Fix, testGoodies::dimlist, Fix) { constexpr auto dim{Fix::dim}; using Ccoord = Ccoord_t; constexpr Dim_t size{5}; constexpr Ccoord cube = CcoordOps::get_cube(size); constexpr Ccoord herm = CcoordOps::get_hermitian_sizes(cube); Ccoord ref_cube = cube; ref_cube.back() = (cube.back() + 1) / 2; BOOST_CHECK_EQUAL_COLLECTIONS(ref_cube.begin(), ref_cube.end(), herm.begin(), herm.end()); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_size, Fix, testGoodies::dimlist, Fix) { constexpr auto dim{Fix::dim}; using Ccoord = Ccoord_t; constexpr Dim_t size{5}; constexpr Ccoord cube = CcoordOps::get_cube(size); BOOST_CHECK_EQUAL(CcoordOps::get_size(cube), ipow(size, dim)); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_stride_size, Fix, testGoodies::dimlist, Fix) { constexpr auto dim{Fix::dim}; using Ccoord = Ccoord_t; constexpr Dim_t size{5}; constexpr Ccoord cube = CcoordOps::get_cube(size); constexpr Ccoord stride = CcoordOps::get_default_strides(cube); BOOST_CHECK_EQUAL(CcoordOps::get_size_from_strides(cube, stride), ipow(size, dim)); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_index, Fix, testGoodies::dimlist, Fix) { constexpr auto dim{Fix::dim}; using Ccoord = Ccoord_t; testGoodies::RandRange rng; Ccoord sizes{}; for (Dim_t i{0}; i < dim; ++i) { sizes[i] = rng.randval(2, 5); } Ccoord stride = CcoordOps::get_default_strides(sizes); const size_t nb_pix{CcoordOps::get_size(sizes)}; for (size_t i {0}; i < nb_pix ; ++i) { BOOST_CHECK_EQUAL(i, CcoordOps::get_index_from_strides (stride, CcoordOps::get_ccoord(sizes, i))); } } BOOST_AUTO_TEST_CASE(vector_test) { constexpr Ccoord_t c3{1, 2, 3}; constexpr Ccoord_t c2{c3[0], c3[1]}; constexpr Rcoord_t s3{1.3, 2.8, 5.7}; constexpr Rcoord_t s2{s3[0], s3[1]}; Eigen::Matrix v2; v2 << s3[0], s3[1]; Eigen::Matrix v3; v3 << s3[0], s3[1], s3[2]; auto vec2{CcoordOps::get_vector(c2, v2(1))}; auto vec3{CcoordOps::get_vector(c3, v3(1))}; for (Dim_t i = 0; i < twoD; ++i) { BOOST_CHECK_EQUAL(c2[i]*v2(1), vec2[i]); } for (Dim_t i = 0; i < threeD; ++i) { BOOST_CHECK_EQUAL(c3[i]*v3(1), vec3[i]); } vec2 = CcoordOps::get_vector(c2, v2); vec3 = CcoordOps::get_vector(c3, v3); for (Dim_t i = 0; i < twoD; ++i) { BOOST_CHECK_EQUAL(c2[i]*v2(i), vec2[i]); BOOST_CHECK_EQUAL(vec2[i], CcoordOps::get_vector(c2, s2)[i]); } for (Dim_t i = 0; i < threeD; ++i) { BOOST_CHECK_EQUAL(c3[i]*v3(i), vec3[i]); BOOST_CHECK_EQUAL(vec3[i], CcoordOps::get_vector(c3, s3)[i]); } } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_fft_utils.cc b/tests/test_fft_utils.cc index e0d3ce6..3030e71 100644 --- a/tests/test_fft_utils.cc +++ b/tests/test_fft_utils.cc @@ -1,83 +1,83 @@ /** * file test_fft_utils.cc * * @author Till Junge * * @date 11 Dec 2017 * * @brief test the small utility functions used by the fft engines and projections * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "boost/range/combine.hpp" #include "tests.hh" #include "fft/fft_utils.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(fft_utils); BOOST_AUTO_TEST_CASE(fft_freqs_test) { //simply comparing to np.fft.fftfreq(12, 1/12.) const std::valarray ref{0., 1., 2., 3., 4., 5., -6., -5., -4., -3., -2., -1.}; auto res{fft_freqs(12)}; Real error = abs(res-ref).sum(); BOOST_CHECK_EQUAL(error, 0.); } BOOST_AUTO_TEST_CASE(fft_freqs_test_length) { //simply comparing to np.fft.fftfreq(10) const std::valarray ref{ 0. , 0.1, 0.2, 0.3, 0.4, -0.5, -0.4, -0.3, -0.2, -0.1}; auto res{fft_freqs(10, 10.)}; Real error = abs(res-ref).sum(); BOOST_CHECK_EQUAL(error, 0.); } BOOST_AUTO_TEST_CASE(wave_vector_computation) { // here, build a FFT_freqs and check it returns the correct xi's constexpr Dim_t dim{twoD}; FFT_freqs freq_struc{{12, 10}, {1., 10.}}; Ccoord_t ccoord1{2, 3}; auto xi{freq_struc.get_xi(ccoord1)}; auto unit_xi{freq_struc.get_unit_xi(ccoord1)}; typename FFT_freqs::Vector ref; ref << 2., .3; // from above tests BOOST_CHECK_LT((xi-ref).norm(), tol); BOOST_CHECK_LT(abs(xi.dot(unit_xi)-xi.norm()), xi.norm()*tol); BOOST_CHECK_LT(abs(unit_xi.norm()-1.), tol); ccoord1={7, 8}; xi = freq_struc.get_xi(ccoord1); unit_xi = freq_struc.get_unit_xi(ccoord1); ref << -5., -.2; BOOST_CHECK_LT((xi-ref).norm(), tol); BOOST_CHECK_LT(abs(xi.dot(unit_xi)-xi.norm()), xi.norm()*tol); BOOST_CHECK_LT(abs(unit_xi.norm()-1.), tol); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_fftw_engine.cc b/tests/test_fftw_engine.cc index f940d6a..85f7d1b 100644 --- a/tests/test_fftw_engine.cc +++ b/tests/test_fftw_engine.cc @@ -1,115 +1,115 @@ /** * file test_fftw_engine.cc * * @author Till Junge * * @date 05 Dec 2017 * * @brief tests for the fftw fft engine implementation * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "tests.hh" #include "fft/fftw_engine.hh" #include "common/ccoord_operations.hh" #include "common/field_collection.hh" #include "common/field_map.hh" #include "common/iterators.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(fftw_engine); /* ---------------------------------------------------------------------- */ template struct FFTW_fixture { constexpr static Dim_t box_resolution{3}; constexpr static Real box_length{4.5}; constexpr static Dim_t sdim{DimS}; constexpr static Dim_t mdim{DimM}; FFTW_fixture() :engine(CcoordOps::get_cube(box_resolution), CcoordOps::get_cube(box_length)){} FFTW_Engine engine; }; using fixlist = boost::mpl::list, FFTW_fixture, FFTW_fixture>; /* ---------------------------------------------------------------------- */ BOOST_FIXTURE_TEST_CASE_TEMPLATE(Constructor_test, Fix, fixlist, Fix) { BOOST_CHECK_NO_THROW(Fix::engine.initialise(FFT_PlanFlags::estimate)); BOOST_CHECK_EQUAL(Fix::engine.size(), ipow(Fix::box_resolution, Fix::sdim)); } /* ---------------------------------------------------------------------- */ BOOST_FIXTURE_TEST_CASE_TEMPLATE(fft_test, Fix, fixlist, Fix) { Fix::engine.initialise(FFT_PlanFlags::estimate); constexpr Dim_t order{2}; using FC_t = FieldCollection; FC_t fc; auto & input{make_field>("input", fc)}; auto & ref {make_field>("reference", fc)}; auto & result{make_field>("result", fc)}; fc.initialise(CcoordOps::get_cube(Fix::box_resolution)); using map_t = MatrixFieldMap; map_t inmap{input}; auto refmap{map_t{ref}}; auto resultmap{map_t{result}}; size_t cntr{0}; for (auto tup: akantu::zip(inmap, refmap)) { cntr++; auto & in_{std::get<0>(tup)}; auto & ref_{std::get<1>(tup)}; in_.setRandom(); ref_ = in_; } auto & complex_field = Fix::engine.fft(input); using cmap_t = MatrixFieldMap, Complex, Fix::mdim, Fix::mdim>; cmap_t complex_map(complex_field); Real error = complex_map[0].imag().norm(); BOOST_CHECK_LT(error, tol); /* make sure, the engine has not modified input (which is unfortunately const-casted internally, hence this test) */ for (auto && tup: akantu::zip(inmap, refmap)) { Real error{(std::get<0>(tup) - std::get<1>(tup)).norm()}; BOOST_CHECK_LT(error, tol); } /* make sure that the ifft of fft returns the original*/ Fix::engine.ifft(result); for (auto && tup: akantu::zip(resultmap, refmap)) { Real error{(std::get<0>(tup)*Fix::engine.normalisation() - std::get<1>(tup)).norm()}; BOOST_CHECK_LT(error, tol); if (error > tol) { std::cout << std::get<0>(tup).array()/std::get<1>(tup).array() << std::endl << std::endl; } } } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_field_collections.cc b/tests/test_field_collections.cc index 857a799..6377ae6 100644 --- a/tests/test_field_collections.cc +++ b/tests/test_field_collections.cc @@ -1,221 +1,221 @@ /** * file test_field_collections.cc * * @author Till Junge * * @date 20 Sep 2017 * * @brief Test the FieldCollection classes which provide fast optimized iterators * over run-time typed fields * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "test_field_collections_header.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(field_collection_tests); BOOST_AUTO_TEST_CASE(simple) { const Dim_t sdim = 2; const Dim_t mdim = 2; using FC_t = FieldCollection; FC_t fc; BOOST_CHECK_EQUAL(FC_t::spatial_dim(), sdim); BOOST_CHECK_EQUAL(fc.get_spatial_dim(), sdim); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(Simple_construction_test, F, test_collections, F) { BOOST_CHECK_EQUAL(F::FC_t::spatial_dim(), F::sdim()); BOOST_CHECK_EQUAL(F::fc.get_spatial_dim(), F::sdim()); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(get_field2_test, F, test_collections, F) { const auto order{2}; using FC_t = typename F::FC_t; using TF_t = TensorField; auto && myfield = make_field("TensorField real 2", F::fc); using TensorMap = TensorFieldMap; using MatrixMap = MatrixFieldMap; using ArrayMap = ArrayFieldMap; TensorMap TFM(myfield); MatrixMap MFM(myfield); ArrayMap AFM(myfield); BOOST_CHECK_EQUAL(TFM.info_string(), "Tensor(d, "+ std::to_string(order) + "_o, " + std::to_string(F::mdim()) + "_d)"); BOOST_CHECK_EQUAL(MFM.info_string(), "Matrix(d, "+ std::to_string(F::mdim()) + "x" + std::to_string(F::mdim()) + ")"); BOOST_CHECK_EQUAL(AFM.info_string(), "Array(d, "+ std::to_string(F::mdim()) + "x" + std::to_string(F::mdim()) + ")"); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(multi_field_test, F, mult_collections, F) { using FC_t = typename F::FC_t; // possible maptypes for Real tensor fields using T_type = Real; using T_TFM1_t = TensorFieldMap; using T_TFM2_t = TensorFieldMap; //! dangerous using T4_Map_t = T4MatrixFieldMap; // impossible maptypes for Real tensor fields using T_SFM_t = ScalarFieldMap; using T_MFM_t = MatrixFieldMap; using T_AFM_t = ArrayFieldMap; using T_MFMw1_t = MatrixFieldMap; using T_MFMw2_t = MatrixFieldMap; using T_MFMw3_t = MatrixFieldMap; const std::string T_name{"Tensorfield Real o4"}; const std::string T_name_w{"TensorField Real o4 wrongname"}; BOOST_CHECK_THROW(T_SFM_t(F::fc.at(T_name)), FieldInterpretationError); BOOST_CHECK_NO_THROW(T_TFM1_t(F::fc.at(T_name))); BOOST_CHECK_NO_THROW(T_TFM2_t(F::fc.at(T_name))); BOOST_CHECK_NO_THROW(T4_Map_t(F::fc.at(T_name))); BOOST_CHECK_THROW(T4_Map_t(F::fc.at(T_name_w)), std::out_of_range); BOOST_CHECK_THROW(T_MFM_t(F::fc.at(T_name)), FieldInterpretationError); BOOST_CHECK_THROW(T_AFM_t(F::fc.at(T_name)), FieldInterpretationError); BOOST_CHECK_THROW(T_MFMw1_t(F::fc.at(T_name)), FieldInterpretationError); BOOST_CHECK_THROW(T_MFMw2_t(F::fc.at(T_name)), FieldInterpretationError); BOOST_CHECK_THROW(T_MFMw2_t(F::fc.at(T_name)), FieldInterpretationError); BOOST_CHECK_THROW(T_MFMw3_t(F::fc.at(T_name)), FieldInterpretationError); BOOST_CHECK_THROW(T_SFM_t(F::fc.at(T_name_w)), std::out_of_range); // possible maptypes for integer scalar fields using S_type = Int; using S_SFM_t = ScalarFieldMap; using S_TFM1_t = TensorFieldMap; using S_TFM2_t = TensorFieldMap; using S_MFM_t = MatrixFieldMap; using S_AFM_t = ArrayFieldMap; using S4_Map_t = T4MatrixFieldMap; // impossible maptypes for integer scalar fields using S_MFMw1_t = MatrixFieldMap; using S_MFMw2_t = MatrixFieldMap; using S_MFMw3_t = MatrixFieldMap; const std::string S_name{"integer Scalar"}; const std::string S_name_w{"integer Scalar wrongname"}; BOOST_CHECK_NO_THROW(S_SFM_t(F::fc.at(S_name))); BOOST_CHECK_NO_THROW(S_TFM1_t(F::fc.at(S_name))); BOOST_CHECK_NO_THROW(S_TFM2_t(F::fc.at(S_name))); BOOST_CHECK_NO_THROW(S_MFM_t(F::fc.at(S_name))); BOOST_CHECK_NO_THROW(S_AFM_t(F::fc.at(S_name))); BOOST_CHECK_NO_THROW(S4_Map_t(F::fc.at(S_name))); BOOST_CHECK_THROW(S_MFMw1_t(F::fc.at(S_name)), FieldInterpretationError); BOOST_CHECK_THROW(T4_Map_t(F::fc.at(S_name)), FieldInterpretationError); BOOST_CHECK_THROW(S_MFMw2_t(F::fc.at(S_name)), FieldInterpretationError); BOOST_CHECK_THROW(S_MFMw2_t(F::fc.at(S_name)), FieldInterpretationError); BOOST_CHECK_THROW(S_MFMw3_t(F::fc.at(S_name)), FieldInterpretationError); BOOST_CHECK_THROW(S_SFM_t(F::fc.at(S_name_w)), std::out_of_range); // possible maptypes for complex matrix fields using M_type = Complex; using M_MFM_t = MatrixFieldMap; using M_AFM_t = ArrayFieldMap; // impossible maptypes for complex matrix fields using M_SFM_t = ScalarFieldMap; using M_MFMw1_t = MatrixFieldMap; using M_MFMw2_t = MatrixFieldMap; using M_MFMw3_t = MatrixFieldMap; const std::string M_name{"Matrixfield Complex sdim x mdim"}; const std::string M_name_w{"Matrixfield Complex sdim x mdim wrongname"}; BOOST_CHECK_THROW(M_SFM_t(F::fc.at(M_name)), FieldInterpretationError); BOOST_CHECK_NO_THROW(M_MFM_t(F::fc.at(M_name))); BOOST_CHECK_NO_THROW(M_AFM_t(F::fc.at(M_name))); BOOST_CHECK_THROW(M_MFMw1_t(F::fc.at(M_name)), FieldInterpretationError); BOOST_CHECK_THROW(M_MFMw2_t(F::fc.at(M_name)), FieldInterpretationError); BOOST_CHECK_THROW(M_MFMw2_t(F::fc.at(M_name)), FieldInterpretationError); BOOST_CHECK_THROW(M_MFMw3_t(F::fc.at(M_name)), FieldInterpretationError); BOOST_CHECK_THROW(M_SFM_t(F::fc.at(M_name_w)), std::out_of_range); } /* ---------------------------------------------------------------------- */ //! Check whether fields can be initialized using mult_collections_t = boost::mpl::list, FC_multi_fixture<2, 3, true>, FC_multi_fixture<3, 3, true>>; using mult_collections_f = boost::mpl::list, FC_multi_fixture<2, 3, false>, FC_multi_fixture<3, 3, false>>; BOOST_FIXTURE_TEST_CASE_TEMPLATE(init_test_glob, F, mult_collections_t, F) { Ccoord_t size; for (auto && s: size) { s = 3; } BOOST_CHECK_NO_THROW(F::fc.initialise(size)); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(init_test_loca, F, mult_collections_f, F) { testGoodies::RandRange rng; for (int i = 0; i < 7; ++i) { Ccoord_t pixel; for (auto && s: pixel) { s = rng.randval(0, 7); } F::fc.add_pixel(pixel); } BOOST_CHECK_NO_THROW(F::fc.initialise()); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(init_test_loca_with_push_back, F, mult_collections_f, F) { constexpr auto mdim = F::mdim(); constexpr int nb_pix = 7; testGoodies::RandRange rng; using ftype = internal::TypedFieldBase; using stype = Eigen::Array; auto & field = reinterpret_cast(F::fc["Tensorfield Real o4"]); field.push_back(stype()); for (int i = 0; i < nb_pix; ++i) { Ccoord_t pixel; for (auto && s: pixel) { s = rng.randval(0, 7); } F::fc.add_pixel(pixel); } BOOST_CHECK_THROW(F::fc.initialise(), FieldCollectionError); for (int i = 0; i < nb_pix-1; ++i) { field.push_back(stype()); } BOOST_CHECK_NO_THROW(F::fc.initialise()); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_field_collections_2.cc b/tests/test_field_collections_2.cc index 2b6c3a5..02e7ac0 100644 --- a/tests/test_field_collections_2.cc +++ b/tests/test_field_collections_2.cc @@ -1,253 +1,253 @@ /** * file test_field_collections_2.cc * * @author Till Junge * * @date 23 Nov 2017 * * @brief Continuation of tests from test_field_collection.cc, split for faster * compilation * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "test_field_collections_header.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(field_collection_tests); BOOST_FIXTURE_TEST_CASE_TEMPLATE(iter_field_test, F, iter_collections, F) { using FC_t = typename F::Parent::FC_t; using Tensor4Map = TensorFieldMap; Tensor4Map T4map{F::fc["Tensorfield Real o4"]}; F::fc["Tensorfield Real o4"].set_zero(); for (auto && tens:T4map) { BOOST_CHECK_EQUAL(Real(Eigen::Tensor(tens.abs().sum().eval())()), 0); } using Tensor2Map = TensorFieldMap; using MSqMap = MatrixFieldMap; using ASqMap = ArrayFieldMap; Tensor2Map T2map{F::fc["Tensorfield Real o2"]}; MSqMap Mmap{F::fc["Tensorfield Real o2"]}; ASqMap Amap{F::fc["Tensorfield Real o2"]}; auto t2_it = T2map.begin(); auto t2_it_end = T2map.end(); auto m_it = Mmap.begin(); auto a_it = Amap.begin(); for (; t2_it != t2_it_end; ++t2_it, ++m_it, ++a_it) { t2_it->setRandom(); auto && m = *m_it; bool comp = (m == a_it->matrix()); BOOST_CHECK(comp); } using ScalarMap = ScalarFieldMap; ScalarMap s_map{F::fc["integer Scalar"]}; for (Uint i = 0; i < s_map.size(); ++i) { s_map[i] = i; } Uint counter{0}; for (const auto& val: s_map) { BOOST_CHECK_EQUAL(counter++, val); } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(ccoord_indexing_test, F, glob_iter_colls, F) { using FC_t = typename F::Parent::FC_t; using ScalarMap = ScalarFieldMap; ScalarMap s_map{F::fc["integer Scalar"]}; for (Uint i = 0; i < s_map.size(); ++i) { s_map[i] = i; } for (size_t i = 0; i < CcoordOps::get_size(F::fc.get_sizes()); ++i) { BOOST_CHECK_EQUAL(CcoordOps::get_index(F::fc.get_sizes(), CcoordOps::get_ccoord(F::fc.get_sizes(), i)), i); } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(iterator_methods_test, F, iter_collections, F) { using FC_t = typename F::Parent::FC_t; using Tensor4Map = TensorFieldMap; Tensor4Map T4map{F::fc["Tensorfield Real o4"]}; using it_t = typename Tensor4Map::iterator; std::ptrdiff_t diff{3}; // arbitrary, as long as it is smaller than the container size // check constructors auto itstart = T4map.begin(); // standard way of obtaining iterator auto itend = T4map.end(); // ditto it_t it1{T4map}; it_t it2{T4map, false}; it_t it3{T4map, size_t(diff)}; BOOST_CHECK(itstart == itstart); BOOST_CHECK(itstart != itend); BOOST_CHECK_EQUAL(itstart, it1); BOOST_CHECK_EQUAL(itend, it2); // check ostream operator std::stringstream response; response << it3; BOOST_CHECK_EQUAL (response.str(), std::string ("iterator on field 'Tensorfield Real o4', entry ") + std::to_string(diff)); // check copy, move, and assigment constructor (and operator+) it_t itcopy = it1; it_t itmove = std::move(T4map.begin()); it_t it4 = it1+diff; it_t it5(it2); it_t tmp(it2); it_t it6(std::move(tmp)); it_t it7 = it4 -diff; BOOST_CHECK_EQUAL(itcopy, it1); BOOST_CHECK_EQUAL(itmove, it1); BOOST_CHECK_EQUAL(it4, it3); BOOST_CHECK_EQUAL(it5, it2); BOOST_CHECK_EQUAL(it6, it5); BOOST_CHECK_EQUAL(it7, it1); // check increments/decrements BOOST_CHECK_EQUAL(it1++, itcopy); // post-increment BOOST_CHECK_EQUAL(it1, itcopy+1); BOOST_CHECK_EQUAL(--it1, itcopy); // pre -decrement BOOST_CHECK_EQUAL(++it1, itcopy+1); // pre -increment BOOST_CHECK_EQUAL(it1--, itcopy+1); // post-decrement BOOST_CHECK_EQUAL(it1, itcopy); // dereference and member-of-pointer check Eigen::Tensor Tens = *it1; Eigen::Tensor Tens2 = *itstart; Eigen::Tensor check = (Tens==Tens2).all(); BOOST_CHECK_EQUAL(bool(check()), true); BOOST_CHECK_NO_THROW(itstart->setZero()); //check access subscripting auto T3a = *it3; auto T3b = itstart[diff]; BOOST_CHECK(bool(Eigen::Tensor((T3a==T3b).all())())); // div. comparisons BOOST_CHECK_LT(itstart, itend); BOOST_CHECK(!(itend < itstart)); BOOST_CHECK(!(itstart < itstart)); BOOST_CHECK_LE(itstart, itend); BOOST_CHECK_LE(itstart, itstart); BOOST_CHECK(!(itend <= itstart)); BOOST_CHECK_GT(itend, itstart); BOOST_CHECK(!(itend>itend)); BOOST_CHECK(!(itstart>itend)); BOOST_CHECK_GE(itend, itstart); BOOST_CHECK_GE(itend, itend); BOOST_CHECK(!(itstart >= itend)); // check assignment increment/decrement BOOST_CHECK_EQUAL(it1+=diff, it3); BOOST_CHECK_EQUAL(it1-=diff, itstart); // check cell coordinates using Ccoord = Ccoord_t; Ccoord a{itstart.get_ccoord()}; Ccoord b{0}; // Weirdly, boost::has_left_shift::value is false for Ccoords, even though the operator is implemented :( //BOOST_CHECK_EQUAL(a, b); bool check2 = (a==b); BOOST_CHECK(check2); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(const_tensor_iter_test, F, iter_collections, F) { using FC_t = typename F::Parent::FC_t; using Tensor4Map = TensorFieldMap; Tensor4Map T4map{F::fc["Tensorfield Real o4"]}; using T_t = typename Tensor4Map::T_t; Eigen::TensorMap Tens2(T4map[0].data(), F::Parent::sdim(), F::Parent::sdim(), F::Parent::sdim(), F::Parent::sdim()); for (auto it = T4map.cbegin(); it != T4map.cend(); ++it) { // maps to const tensors can't be initialised with a const pointer this sucks auto&& tens = *it; auto&& ptr = tens.data(); static_assert(std::is_pointer>::value, "should be getting a pointer"); //static_assert(std::is_const>::value, "should be const"); // If Tensor were written well, above static_assert should pass, and the // following check shouldn't. If it get triggered, it means that a newer // version of Eigen now does have const-correct // TensorMap. This means that const-correct field maps // are then also possible for tensors BOOST_CHECK(!std::is_const>::value); } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(const_matrix_iter_test, F, iter_collections, F) { using FC_t = typename F::Parent::FC_t; using MatrixMap = MatrixFieldMap; MatrixMap Mmap{F::fc["Matrixfield Complex sdim x mdim"]}; for (auto it = Mmap.cbegin(); it != Mmap.cend(); ++it) { // maps to const tensors can't be initialised with a const pointer this sucks auto&& mat = *it; auto&& ptr = mat.data(); static_assert(std::is_pointer>::value, "should be getting a pointer"); //static_assert(std::is_const>::value, "should be const"); // If Matrix were written well, above static_assert should pass, and the // following check shouldn't. If it get triggered, it means that a newer // version of Eigen now does have const-correct // MatrixMap. This means that const-correct field maps // are then also possible for matrices BOOST_CHECK(!std::is_const>::value); } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(const_scalar_iter_test, F, iter_collections, F) { using FC_t = typename F::Parent::FC_t; using ScalarMap = ScalarFieldMap; ScalarMap Smap{F::fc["integer Scalar"]}; for (auto it = Smap.cbegin(); it != Smap.cend(); ++it) { auto&& scal = *it; static_assert(std::is_const>::value, "referred type should be const"); static_assert(std::is_lvalue_reference::value, "Should have returned an lvalue ref"); } } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_field_collections_3.cc b/tests/test_field_collections_3.cc index 3c2221c..439c5b1 100644 --- a/tests/test_field_collections_3.cc +++ b/tests/test_field_collections_3.cc @@ -1,85 +1,85 @@ /** * file test_field_collections_3.cc * * @author Till Junge * * @date 19 Dec 2017 * * @brief Continuation of tests from test_field_collection_2.cc, split for faster * compilation * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "test_field_collections_header.hh" #include "common/test_goodies.hh" #include "common/tensor_algebra.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(field_collection_tests); BOOST_FIXTURE_TEST_CASE_TEMPLATE(assignment_test, Fix, iter_collections, Fix) { auto t4map = Fix::t4_field.get_map(); auto t2map = Fix::t2_field.get_map(); auto scmap = Fix::sc_field.get_map(); auto m2map = Fix::m2_field.get_map(); const auto t4map_val{Matrices::Isymm()}; t4map = t4map_val; const auto t2map_val{Matrices::I2()}; t2map = t2map_val; const Int scmap_val{1}; scmap = scmap_val; Eigen::Matrix m2map_val; m2map_val.setRandom(); m2map = m2map_val; const size_t nb_pts{Fix::fc.size()}; testGoodies::RandRange rnd{}; BOOST_CHECK_EQUAL((t4map[rnd.randval(0, nb_pts-1)] - t4map_val).norm(), 0.); BOOST_CHECK_EQUAL((t2map[rnd.randval(0, nb_pts-1)] - t2map_val).norm(), 0.); BOOST_CHECK_EQUAL((scmap[rnd.randval(0, nb_pts-1)] - scmap_val), 0.); BOOST_CHECK_EQUAL((m2map[rnd.randval(0, nb_pts-1)] - m2map_val).norm(), 0.); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(Eigentest, Fix, iter_collections, Fix) { auto t4eigen = Fix::t4_field.eigen(); auto t2eigen = Fix::t2_field.eigen(); BOOST_CHECK_EQUAL(t4eigen.rows(), ipow(Fix::mdim(), 4)); BOOST_CHECK_EQUAL(t4eigen.cols(), Fix::t4_field.size()); using T2_t = typename Eigen::Matrix; T2_t test_mat; test_mat.setRandom(); Eigen::Map> test_map(test_mat.data()); t2eigen.col(0) = test_map; BOOST_CHECK_EQUAL((Fix::t2_field.get_map()[0] - test_mat).norm(), 0.); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_field_collections_header.hh b/tests/test_field_collections_header.hh index 99ced74..7b42a6b 100644 --- a/tests/test_field_collections_header.hh +++ b/tests/test_field_collections_header.hh @@ -1,158 +1,158 @@ /** * file test_field_collections_header.hh * * @author Till Junge * * @date 23 Nov 2017 * * @brief declares fixtures for field_collection tests, so that they can be split * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef TEST_FIELD_COLLECTIONS_HEADER_H #define TEST_FIELD_COLLECTIONS_HEADER_H #include #include #include #include #include #include #include "common/common.hh" #include "common/ccoord_operations.hh" #include "common/test_goodies.hh" #include "tests.hh" #include "common/field_collection.hh" #include "common/field.hh" #include "common/field_map.hh" namespace muSpectre { //! Test fixture for simple tests on single field in collection template struct FC_fixture: public FieldCollection { FC_fixture() :fc() {} inline static constexpr Dim_t sdim(){return DimS;} inline static constexpr Dim_t mdim(){return DimM;} inline static constexpr bool global(){return Global;} using FC_t = FieldCollection; FC_t fc; }; using test_collections = boost::mpl::list, FC_fixture<2, 3, true>, FC_fixture<3, 3, true>, FC_fixture<2, 2, false>, FC_fixture<2, 3, false>, FC_fixture<3, 3, false>>; constexpr Dim_t order{4}, matrix_order{2}; //! Test fixture for multiple fields in the collection template struct FC_multi_fixture{ using FC_t = FieldCollection; using T4_t = TensorField; using T2_t = TensorField; using Sc_t = ScalarField; using M2_t = MatrixField; FC_multi_fixture() :fc(), t4_field{make_field("Tensorfield Real o4", fc)},//Real tensor field t2_field{make_field("Tensorfield Real o2", fc)},//Real tensor field sc_field{make_field("integer Scalar", fc)}, // integer scalar field m2_field{make_field("Matrixfield Complex sdim x mdim", fc)} //complex matrix field { } inline static constexpr Dim_t sdim(){return DimS;} inline static constexpr Dim_t mdim(){return DimM;} inline static constexpr bool global(){return Global;} FC_t fc; T4_t & t4_field; T2_t & t2_field; Sc_t & sc_field; M2_t & m2_field; }; using mult_collections = boost::mpl::list, FC_multi_fixture<2, 3, true>, FC_multi_fixture<3, 3, true>, FC_multi_fixture<2, 2, false>, FC_multi_fixture<2, 3, false>, FC_multi_fixture<3, 3, false>>; //! Test fixture for iterators over multiple fields template struct FC_iterator_fixture : public FC_multi_fixture { using Parent = FC_multi_fixture; FC_iterator_fixture() :Parent() { this-> fill(); } template std::enable_if_t fill() { static_assert(Global==isGlobal, "You're breaking my SFINAE plan"); Ccoord_t size; for (auto && s: size) { s = cube_size(); } this->fc.initialise(size); } template std::enable_if_t fill (int dummy = 0) { static_assert(notGlobal != Global, "You're breaking my SFINAE plan"); testGoodies::RandRange rng; this->fc.add_pixel({0,0}); for (int i = 0*dummy; i < sele_size(); ++i) { Ccoord_t pixel; for (auto && s: pixel) { s = rng.randval(0, 7); } this->fc.add_pixel(pixel); } this->fc.initialise(); } constexpr static Dim_t cube_size() {return 3;} constexpr static Dim_t sele_size() {return 7;} }; using iter_collections = boost::mpl::list, FC_iterator_fixture<2, 3, true>, FC_iterator_fixture<3, 3, true>, FC_iterator_fixture<2, 2, false>, FC_iterator_fixture<2, 3, false>, FC_iterator_fixture<3, 3, false>>; using glob_iter_colls = boost::mpl::list, FC_iterator_fixture<2, 3, true>, FC_iterator_fixture<3, 3, true>>; } // muSpectre #endif /* TEST_FIELD_COLLECTIONS_HEADER_H */ diff --git a/tests/test_fields.cc b/tests/test_fields.cc index fb74764..64edce3 100644 --- a/tests/test_fields.cc +++ b/tests/test_fields.cc @@ -1,51 +1,51 @@ /** * file test_fields.cc * * @author Till Junge * * @date 20 Sep 2017 * * @brief Test Fields that are used in FieldCollections * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "tests.hh" #include "common/field_collection.hh" #include "common/field.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(field_test); BOOST_AUTO_TEST_CASE(simple_creation) { const Dim_t sdim = 2; const Dim_t mdim = 2; const Dim_t order = 4; using FC_t = FieldCollection; FC_t fc; using TF_t = TensorField; make_field("TensorField 1", fc); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_material_hyper_elastic1.cc b/tests/test_material_hyper_elastic1.cc index 7419e4a..7356e80 100644 --- a/tests/test_material_hyper_elastic1.cc +++ b/tests/test_material_hyper_elastic1.cc @@ -1,212 +1,212 @@ /** * file test_material_hyper_elastic1.cc * * @author Till Junge * * @date 28 Nov 2017 * * @brief Tests for the large-strain, objective Hooke's law, implemented in * the convenient strategy (i.e., using MaterialMuSpectre) * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include "materials/material_hyper_elastic1.hh" #include "tests.hh" #include "common/test_goodies.hh" #include "common/field_collection.hh" #include "common/iterators.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(material_hyper_elastic_1); template struct MaterialFixture { using Mat_t = MaterialHyperElastic1; constexpr static Real lambda{2}, mu{1.5}; constexpr static Real young{mu*(3*lambda + 2*mu)/(lambda + mu)}; constexpr static Real poisson{lambda/(2*(lambda + mu))}; MaterialFixture():mat("Name", young, poisson){}; constexpr static Dim_t sdim{DimS}; constexpr static Dim_t mdim{DimM}; Mat_t mat; }; using mat_list = boost::mpl::list, MaterialFixture, MaterialFixture>; BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_constructor, Fix, mat_list, Fix) { BOOST_CHECK_EQUAL("Name", Fix::mat.get_name()); auto & mat{Fix::mat}; auto sdim{Fix::sdim}; auto mdim{Fix::mdim}; BOOST_CHECK_EQUAL(sdim, mat.sdim()); BOOST_CHECK_EQUAL(mdim, mat.mdim()); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_add_pixel, Fix, mat_list, Fix) { auto & mat{Fix::mat}; constexpr Dim_t sdim{Fix::sdim}; testGoodies::RandRange rng;; const Dim_t nb_pixel{7}, box_size{17}; using Ccoord = Ccoord_t; for (Dim_t i = 0; i < nb_pixel; ++i) { Ccoord c; for (Dim_t j = 0; j < sdim; ++j) { c[j] = rng.randval(0, box_size); } BOOST_CHECK_NO_THROW(mat.add_pixel(c)); } BOOST_CHECK_NO_THROW(mat.initialise()); } template struct MaterialFixtureFilled: public MaterialFixture { using Mat_t = typename MaterialFixture::Mat_t; constexpr static Dim_t box_size{3}; MaterialFixtureFilled():MaterialFixture(){ using Ccoord = Ccoord_t; Ccoord cube{CcoordOps::get_cube(box_size)}; CcoordOps::Pixels pixels(cube); for (auto pixel: pixels) { this->mat.add_pixel(pixel); } this->mat.initialise(); }; }; using mat_fill = boost::mpl::list, MaterialFixtureFilled, MaterialFixtureFilled>; BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_evaluate_law, Fix, mat_fill, Fix) { constexpr auto cube{CcoordOps::get_cube(Fix::box_size)}; auto & mat{Fix::mat}; using FC_t = FieldCollection; FC_t globalfields; auto & F{make_field ("Transformation Gradient", globalfields)}; auto & P1 = make_field ("Nominal Stress1", globalfields); // to be computed alone auto & P2 = make_field ("Nominal Stress2", globalfields); // to be computed with tangent auto & K = make_field ("Tangent Moduli", globalfields); // to be computed with tangent auto & Pr = make_field ("Nominal Stress reference", globalfields); auto & Kr = make_field ("Tangent Moduli reference", globalfields); // to be computed with tangent globalfields.initialise(cube); static_assert(std::is_same::value, "oh oh"); static_assert(std::is_same::value, "oh oh"); static_assert(std::is_same::value, "oh oh"); static_assert(std::is_same::value, "oh oh"); static_assert(std::is_same::value, "oh oh"); static_assert(std::is_same::value, "oh oh"); { // block to contain not-constant gradient map typename Fix::Mat_t::StressMap_t grad_map (globalfields["Transformation Gradient"]); for (auto F_: grad_map) { F_.setRandom(); } grad_map[0] = grad_map[0].Identity(); // identifiable gradients for debug grad_map[1] = 1.2*grad_map[1].Identity(); // ditto } //compute stresses using material mat.compute_stresses(globalfields["Transformation Gradient"], globalfields["Nominal Stress1"], Formulation::finite_strain); //compute stresses and tangent moduli using material BOOST_CHECK_THROW (mat.compute_stresses_tangent(globalfields["Transformation Gradient"], globalfields["Nominal Stress2"], globalfields["Nominal Stress2"], Formulation::finite_strain), std::runtime_error); mat.compute_stresses_tangent(globalfields["Transformation Gradient"], globalfields["Nominal Stress2"], globalfields["Tangent Moduli"], Formulation::finite_strain); typename Fix::Mat_t::StrainMap_t Fmap(globalfields["Transformation Gradient"]); typename Fix::Mat_t::StressMap_t Pmap_ref(globalfields["Nominal Stress reference"]); typename Fix::Mat_t::TangentMap_t Kmap_ref(globalfields["Tangent Moduli reference"]); for (auto tup: akantu::zip(Fmap, Pmap_ref, Kmap_ref)) { auto F_ = std::get<0>(tup); auto P_ = std::get<1>(tup); auto K_ = std::get<2>(tup); std::tie(P_,K_) = testGoodies::objective_hooke_explicit (Fix::lambda, Fix::mu, F_); } typename Fix::Mat_t::StressMap_t Pmap_1(globalfields["Nominal Stress1"]); for (auto tup: akantu::zip(Pmap_ref, Pmap_1)) { auto P_r = std::get<0>(tup); auto P_1 = std::get<1>(tup); Real error = (P_r - P_1).norm(); BOOST_CHECK_LT(error, tol); } typename Fix::Mat_t::StressMap_t Pmap_2(globalfields["Nominal Stress2"]); typename Fix::Mat_t::TangentMap_t Kmap(globalfields["Tangent Moduli"]); for (auto tup: akantu::zip(Pmap_ref, Pmap_2, Kmap_ref, Kmap)) { auto P_r = std::get<0>(tup); auto P = std::get<1>(tup); Real error = (P_r - P).norm(); BOOST_CHECK_LT(error, tol); auto K_r = std::get<2>(tup); auto K = std::get<3>(tup); error = (K_r - K).norm(); BOOST_CHECK_LT(error, tol); } } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_materials_toolbox.cc b/tests/test_materials_toolbox.cc index ea9ae2a..1079f2a 100644 --- a/tests/test_materials_toolbox.cc +++ b/tests/test_materials_toolbox.cc @@ -1,175 +1,175 @@ /** * file test_materials_toolbox.cc * * @author Till Junge * * @date 05 Nov 2017 * * @brief Tests for the materials toolbox * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "tests.hh" #include "materials/materials_toolbox.hh" #include "common/T4_map_proxy.hh" #include "common/tensor_algebra.hh" #include "common/test_goodies.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(materials_toolbox) BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_strain_conversion, Fix, testGoodies::dimlist, Fix){ constexpr Dim_t dim{Fix::dim}; using T2 = Eigen::Matrix; T2 F; F.setRandom(); auto Eref = .5*(F.transpose()*F-T2::Identity()); auto E_tb = MatTB::convert_strain (Eigen::Map>(F.data())); auto error = (Eref-E_tb).norm(); BOOST_CHECK_LT(error, tol); auto F_tb = MatTB::convert_strain(F); error = (F-F_tb).norm(); BOOST_CHECK_LT(error, tol); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(dumb_tensor_mult_test, Fix, testGoodies::dimlist, Fix) { constexpr Dim_t dim{Fix::dim}; using T4 = T4Mat; T4 A,B, R1, R2; A.setRandom(); B.setRandom(); R1 = A*B; R2.setZero(); for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t a = 0; a < dim; ++a) { for (Dim_t b = 0; b < dim; ++b) { for (Dim_t k = 0; k < dim; ++k) { for (Dim_t l = 0; l < dim; ++l) { get(R2,i,j,k,l) += get(A, i,j,a,b)*get(B, a,b, k,l); } } } } } } auto error{(R1-R2).norm()}; BOOST_CHECK_LT(error, tol); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_PK1_stress, Fix, testGoodies::dimlist, Fix) { using namespace Matrices; constexpr Dim_t dim{Fix::dim}; using T2 = Eigen::Matrix; using T4 = T4Mat; testGoodies::RandRange rng; T2 F=T2::Identity()*2 ; //F.setRandom(); T2 E_tb = MatTB::convert_strain (Eigen::Map>(F.data())); Real lambda = 3;//rng.randval(1, 2); Real mu = 4;//rng.randval(1,2); T4 J = Itrac(); T2 I = I2(); T4 I4 = Isymm(); T4 C = lambda*J + 2*mu*I4; T2 S = tensmult(C, E_tb); T2 Sref = lambda*E_tb.trace()*I + 2*mu*E_tb; auto error{(Sref-S).norm()}; BOOST_CHECK_LT(error, tol); T4 K = outer_under(I,S) + outer_under(F,I)*C*outer_under(F.transpose(),I); // See Curnier, 2000, "Méthodes numériques en mécanique des solides", p 252 T4 Kref; Real Fkrkr = (F.array()*F.array()).sum(); T2 Fkmkn = F.transpose()*F; T2 Fisjs = F*F.transpose(); Kref.setZero(); for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t m = 0; m < dim; ++m) { for (Dim_t n = 0; n < dim; ++n) { get(Kref, i, m, j, n) = (lambda*((Fkrkr-dim)/2 * I(i,j)*I(m,n) + F(i,m)*F(j,n)) + mu * (I(i,j)*Fkmkn(m,n) + Fisjs(i,j)*I(m,n) - I(i,j) *I(m,n) + F(i,n)*F(j,m))); } } } } error = (Kref-K).norm(); BOOST_CHECK_LT(error, tol); T2 P = MatTB::PK1_stress(F, S); T2 Pref = F*S; error = (P-Pref).norm(); BOOST_CHECK_LT(error, tol); auto && stress_tgt = MatTB::PK1_stress(F, S, C); T2 P_t = std::move(std::get<0>(stress_tgt)); T4 K_t = std::move(std::get<1>(stress_tgt)); error = (P_t-Pref).norm(); BOOST_CHECK_LT(error, tol); error = (K_t-Kref).norm(); BOOST_CHECK_LT(error, tol); auto && stress_tgt_trivial = MatTB::PK1_stress(F, P, K); T2 P_u = std::move(std::get<0>(stress_tgt_trivial)); T4 K_u = std::move(std::get<1>(stress_tgt_trivial)); error = (P_u-Pref).norm(); BOOST_CHECK_LT(error, tol); error = (K_u-Kref).norm(); BOOST_CHECK_LT(error, tol); T2 P_g; T4 K_g; std::tie(P_g, K_g) = testGoodies::objective_hooke_explicit(lambda, mu, F); error = (P_g-Pref).norm(); BOOST_CHECK_LT(error, tol); error = (K_g-Kref).norm(); BOOST_CHECK_LT(error, tol); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_projection_finite.cc b/tests/test_projection_finite.cc index 57461ed..7179dfc 100644 --- a/tests/test_projection_finite.cc +++ b/tests/test_projection_finite.cc @@ -1,251 +1,251 @@ /** * file test_projection_finite.cc * * @author Till Junge * * @date 07 Dec 2017 * * @brief tests for standard finite strain projection operator * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include "tests.hh" #include "fft/fftw_engine.hh" #include "fft/projection_finite_strain.hh" #include "fft/projection_finite_strain_fast.hh" #include "fft/fft_utils.hh" #include "common/common.hh" #include "common/field_collection.hh" #include "common/field_map.hh" #include "common/iterators.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(projection_finite_strain); /* ---------------------------------------------------------------------- */ template struct Sizes { }; template<> struct Sizes { constexpr static Ccoord_t get_resolution() { return Ccoord_t{3, 5};} constexpr static Rcoord_t get_lengths() { return Rcoord_t{3.4, 5.8};} }; template<> struct Sizes { constexpr static Ccoord_t get_resolution() { return Ccoord_t{3, 5, 7};} constexpr static Rcoord_t get_lengths() { return Rcoord_t{3.4, 5.8, 6.7};} }; template struct Squares { }; template<> struct Squares { constexpr static Ccoord_t get_resolution() { return Ccoord_t{5, 5};} constexpr static Rcoord_t get_lengths() { return Rcoord_t{5, 5};} }; template<> struct Squares { constexpr static Ccoord_t get_resolution() { return Ccoord_t{7, 7, 7};} constexpr static Rcoord_t get_lengths() { return Rcoord_t{7, 7, 7};} }; /* ---------------------------------------------------------------------- */ template struct ProjectionFixture { using Engine = FFTW_Engine; using Parent = Proj; constexpr static Dim_t sdim{DimS}; constexpr static Dim_t mdim{DimM}; ProjectionFixture() :projector(std::make_unique(SizeGiver::get_resolution(), SizeGiver::get_lengths())){} Parent projector; }; /* ---------------------------------------------------------------------- */ using fixlist = boost::mpl::list< ProjectionFixture, ProjectionFiniteStrain>, ProjectionFixture, ProjectionFiniteStrain>, ProjectionFixture, ProjectionFiniteStrain>, ProjectionFixture, ProjectionFiniteStrain>, ProjectionFixture, ProjectionFiniteStrainFast>, ProjectionFixture, ProjectionFiniteStrainFast>, ProjectionFixture, ProjectionFiniteStrainFast>, ProjectionFixture, ProjectionFiniteStrainFast>>; /* ---------------------------------------------------------------------- */ BOOST_FIXTURE_TEST_CASE_TEMPLATE(constructor_test, fix, fixlist, fix) { BOOST_CHECK_NO_THROW(fix::projector.initialise(FFT_PlanFlags::estimate)); } /* ---------------------------------------------------------------------- */ BOOST_FIXTURE_TEST_CASE_TEMPLATE(Gradient_preservation_test, fix, fixlist, fix) { // create a gradient field with a zero mean gradient and verify // that the projection preserves it constexpr Dim_t dim{fix::sdim}, sdim{fix::sdim}, mdim{fix::mdim}; static_assert(dim == fix::mdim, "These tests assume that the material and spatial dimension are " "identical"); using Fields = FieldCollection; using FieldT = TensorField; using FieldMap = MatrixFieldMap; using Vector = Eigen::Matrix; Fields fields{}; FieldT & f_grad{make_field("gradient", fields)}; FieldT & f_var{make_field("working field", fields)}; FieldMap grad(f_grad); FieldMap var(f_var); fields.initialise(fix::projector.get_resolutions()); FFT_freqs freqs{fix::projector.get_resolutions(), fix::projector.get_lengths()}; Vector k; for (Dim_t i = 0; i < dim; ++i) { // the wave vector has to be such that it leads to an integer // number of periods in each length of the domain k(i) = (i+1)*2*pi/fix::projector.get_lengths()[i]; ; } for (auto && tup: akantu::zip(fields, grad, var)) { auto & ccoord = std::get<0>(tup); auto & g = std::get<1>(tup); auto & v = std::get<2>(tup); Vector vec = CcoordOps::get_vector(ccoord, fix::projector.get_lengths()/ fix::projector.get_resolutions()); g.row(0) << k.transpose() * cos(k.dot(vec)); v.row(0) = g.row(0); } fix::projector.initialise(FFT_PlanFlags::estimate); fix::projector.apply_projection(f_var); for (auto && tup: akantu::zip(fields, grad, var)) { auto & ccoord = std::get<0>(tup); auto & g = std::get<1>(tup); auto & v = std::get<2>(tup); Vector vec = CcoordOps::get_vector(ccoord, fix::projector.get_lengths()/ fix::projector.get_resolutions()); Real error = (g-v).norm(); BOOST_CHECK_LT(error, tol); if (error >=tol) { std::cout << std::endl << "grad_ref :" << std::endl << g << std::endl; std::cout << std::endl << "grad_proj :" << std::endl << v << std::endl; std::cout << std::endl << "ccoord :" << std::endl << ccoord << std::endl; std::cout << std::endl << "vector :" << std::endl << vec.transpose() << std::endl; } } } // /* ---------------------------------------------------------------------- */ // using F3 = ProjectionFixture>; // BOOST_FIXTURE_TEST_CASE(Helmholtz_decomposition, F3) { // // create a field that is explicitely the sum of a gradient and a // // curl, then verify that the projected field corresponds to the // // gradient (without the zero'th component) // constexpr Dim_t sdim{F3::sdim}, mdim{F3::mdim}; // using Fields = FieldCollection; // Fields fields{}; // using FieldT = TensorField; // using FieldMap = MatrixFieldMap; // FieldT & f_grad{make_field("gradient", fields)}; // FieldT & f_curl{make_field("curl", fields)}; // FieldT & f_sum{make_field("sum", fields)}; // FieldT & f_var{make_field("working field", fields)}; // FieldMap grad(f_grad); // FieldMap curl(f_curl); // FieldMap sum(f_sum); // FieldMap var(f_var); // fields.initialise(F3::engine.get_resolutions()); // for (auto && tup: akantu::zip(fields, grad, curl, sum, var)) { // auto & ccoord = std::get<0>(tup); // auto & g = std::get<1>(tup); // auto & c = std::get<2>(tup); // auto & s = std::get<3>(tup); // auto & v = std::get<4>(tup); // auto vec = CcoordOps::get_vector(ccoord); // Real & x{vec(0)}; // Real & y{vec(1)}; // Real & z{vec(2)}; // g.row(0) << y*z, x*z, y*z; // c.row(0) << 0, x*y, -x*z; // v.row(0) = s.row(0) = g.row(0) + c.row(0); // } // projector.initialise(FFT_PlanFlags::estimate); // projector.apply_projection(f_var); // for (auto && tup: akantu::zip(fields, grad, curl, sum, var)) { // auto & ccoord = std::get<0>(tup); // auto & g = std::get<1>(tup); // auto & c = std::get<2>(tup); // auto & s = std::get<3>(tup); // auto & v = std::get<4>(tup); // auto vec = CcoordOps::get_vector(ccoord); // Real error = (s-g).norm(); // //BOOST_CHECK_LT(error, tol); // if (error >=tol) { // std::cout << std::endl << "grad_ref :" << std::endl << g << std::endl; // std::cout << std::endl << "grad_proj :" << std::endl << v << std::endl; // std::cout << std::endl << "curl :" << std::endl << c << std::endl; // std::cout << std::endl << "sum :" << std::endl << s << std::endl; // std::cout << std::endl << "ccoord :" << std::endl << ccoord << std::endl; // std::cout << std::endl << "vector :" << std::endl << vec.transpose() << std::endl; // } // } // } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_solver_newton_cg.cc b/tests/test_solver_newton_cg.cc index 448205c..fcfb7ed 100644 --- a/tests/test_solver_newton_cg.cc +++ b/tests/test_solver_newton_cg.cc @@ -1,175 +1,175 @@ /** * file test_solver_newton_cg.cc * * @author Till Junge * * @date 20 Dec 2017 * * @brief Tests for the standard Newton-Raphson + Conjugate Gradient solver * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "tests.hh" #include "solver/solvers.hh" #include "fft/fftw_engine.hh" #include "fft/projection_finite_strain_fast.hh" #include "materials/material_hyper_elastic1.hh" #include "common/iterators.hh" #include "common/ccoord_operations.hh" #include "system/system_factory.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(newton_cg_tests); BOOST_AUTO_TEST_CASE(manual_construction_test) { // constexpr Dim_t dim{twoD}; constexpr Dim_t dim{threeD}; // constexpr Ccoord_t resolutions{3, 3}; // constexpr Rcoord_t lengths{2.3, 2.7}; constexpr Ccoord_t resolutions{5, 5, 5}; constexpr Rcoord_t lengths{5, 5, 5}; auto fft_ptr{std::make_unique>(resolutions, lengths)}; auto proj_ptr{std::make_unique>(std::move(fft_ptr))}; SystemBase sys(std::move(proj_ptr)); using Mat_t = MaterialHyperElastic1; //const Real Young{210e9}, Poisson{.33}; const Real Young{1.0030648180242636}, Poisson{0.29930675909878679}; // const Real lambda{Young*Poisson/((1+Poisson)*(1-2*Poisson))}; // const Real mu{Young/(2*(1+Poisson))}; auto Material_hard = std::make_unique("hard", 10*Young, Poisson); auto Material_soft = std::make_unique("soft", Young, Poisson); for (auto && tup: akantu::enumerate(sys)) { auto && pixel = std::get<1>(tup); if (std::get<0>(tup) == 0) { Material_hard->add_pixel(pixel); } else { Material_soft->add_pixel(pixel); } } sys.add_material(std::move(Material_hard)); sys.add_material(std::move(Material_soft)); sys.initialise(); Grad_t delF0; delF0 << 0, 1., 0, 0, 0, 0, 0, 0, 0; constexpr Real cg_tol{1e-8}, newton_tol{1e-5}; constexpr Uint maxiter{CcoordOps::get_size(resolutions)*ipow(dim, secondOrder)*10}; constexpr bool verbose{false}; constexpr Formulation form{Formulation::finite_strain}; GradIncrements grads; grads.push_back(delF0); Eigen::ArrayXXd res1{de_geus(sys, grads, form, cg_tol, newton_tol, maxiter, verbose).eigen()}; Eigen::ArrayXXd res2{newton_cg(sys, grads, form, cg_tol, newton_tol, maxiter, verbose).eigen()}; BOOST_CHECK_LE(abs(res1-res2).mean(), cg_tol); } BOOST_AUTO_TEST_CASE(small_strain_patch_test) { constexpr Dim_t dim{twoD}; using Ccoord = Ccoord_t; using Rcoord = Rcoord_t; constexpr Ccoord resolutions{3, 3}; constexpr Rcoord lengths{3, 3}; constexpr Formulation form{Formulation::small_strain}; // number of layers in the hard material constexpr Uint nb_lays{1}; constexpr Real contrast{2}; static_assert(nb_lays < resolutions[0], "the number or layers in the hard material must be smaller " "than the total number of layers in dimension 0"); auto sys{make_system(resolutions, lengths, form)}; using Mat_t = MaterialHyperElastic1; constexpr Real Young{2}, Poisson{.33}; auto material_hard{std::make_unique("hard", contrast*Young, Poisson)}; auto material_soft{std::make_unique("soft", Young, Poisson)}; for (const auto & pixel: sys) { if (pixel[0] < Dim_t(nb_lays)) { material_hard->add_pixel(pixel); } else { material_soft->add_pixel(pixel); } } sys.add_material(std::move(material_hard)); sys.add_material(std::move(material_soft)); sys.initialise(); Grad_t delEps0; constexpr Real eps0 = 1.; delEps0 << eps0, 0, 0, 0; constexpr Real cg_tol{1e-8}, newton_tol{1e-5}; constexpr Uint maxiter{CcoordOps::get_size(resolutions)*ipow(dim, secondOrder)*10}; constexpr bool verbose{false}; auto & result = newton_cg(sys, delEps0, form, cg_tol, newton_tol, maxiter, verbose); if (verbose) { std::cout << "result:" << std::endl << result.eigen() << std::endl; std::cout << "mean strain = " << std::endl << result.get_map().mean() << std::endl; } /** * verification of resultant strains: subscript ₕ for hard and ₛ * for soft, Nₕ is nb_lays and Nₜₒₜ is resolutions, k is contrast * * Δl = εl = Δlₕ + Δlₛ = εₕlₕ+εₛlₛ * => ε = εₕ Nₕ/Nₜₒₜ + εₛ (Nₜₒₜ-Nₕ)/Nₜₒₜ * * σ is constant across all layers * σₕ = σₛ * => Eₕ εₕ = Eₛ εₛ * => εₕ = 1/k εₛ * => ε / (1/k Nₕ/Nₜₒₜ + (Nₜₒₜ-Nₕ)/Nₜₒₜ) = εₛ */ constexpr Real factor{1/contrast * Real(nb_lays)/resolutions[0] + 1.-nb_lays/Real(resolutions[0])}; constexpr Real eps_soft{eps0/factor}; constexpr Real eps_hard{eps_soft/contrast}; if (verbose) { std::cout << "εₕ = " << eps_hard << ", εₛ = " << eps_soft << std::endl; std::cout << "ε = εₕ Nₕ/Nₜₒₜ + εₛ (Nₜₒₜ-Nₕ)/Nₜₒₜ" << std::endl; } Grad_t Eps_hard; Eps_hard << eps_hard, 0, 0, 0; Grad_t Eps_soft; Eps_soft << eps_soft, 0, 0, 0; for (const auto & pixel: sys) { if (pixel[0] < Dim_t(nb_lays)) { BOOST_CHECK_LE((Eps_hard-result.get_map()[pixel]).norm(), tol); } else { BOOST_CHECK_LE((Eps_soft-result.get_map()[pixel]).norm(), tol); } } } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_system_base.cc b/tests/test_system_base.cc index fc7eff0..dfc12bf 100644 --- a/tests/test_system_base.cc +++ b/tests/test_system_base.cc @@ -1,195 +1,195 @@ /** * file test_system_base.cc * * @author Till Junge * * @date 14 Dec 2017 * * @brief Tests for the basic system class * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include "tests.hh" #include "common/common.hh" #include "common/iterators.hh" #include "common/field_map.hh" #include "common/test_goodies.hh" #include "system/system_factory.hh" #include "materials/material_hyper_elastic1.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(system_base); template struct Sizes { }; template<> struct Sizes { constexpr static Dim_t sdim{twoD}; constexpr static Ccoord_t get_resolution() { return Ccoord_t{3, 5};} constexpr static Rcoord_t get_lengths() { return Rcoord_t{3.4, 5.8};} }; template<> struct Sizes { constexpr static Dim_t sdim{threeD}; constexpr static Ccoord_t get_resolution() { return Ccoord_t{3, 5, 7};} constexpr static Rcoord_t get_lengths() { return Rcoord_t{3.4, 5.8, 6.7};} }; template struct SystemBaseFixture: SystemBase { constexpr static Dim_t sdim{DimS}; constexpr static Dim_t mdim{DimM}; constexpr static Formulation formulation{form}; SystemBaseFixture() :SystemBase{ std::move(system_input(Sizes::get_resolution(), Sizes::get_lengths())), form} {} }; using fixlist = boost::mpl::list, SystemBaseFixture, SystemBaseFixture, SystemBaseFixture>; BOOST_AUTO_TEST_CASE(manual_construction) { constexpr Dim_t dim{twoD}; Ccoord_t resolutions{3, 3}; Rcoord_t lengths{2.3, 2.7}; auto fft_ptr{std::make_unique>(resolutions, lengths)}; auto proj_ptr{std::make_unique>(std::move(fft_ptr))}; SystemBase sys{std::move(proj_ptr)}; auto sys2{make_system(resolutions, lengths)}; auto sys2b{std::move(sys2)}; BOOST_CHECK_EQUAL(sys2b.size(), sys.size()); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(constructor_test, fix, fixlist, fix) { BOOST_CHECK_THROW(fix::check_material_coverage(), std::runtime_error); BOOST_CHECK_THROW(fix::initialise(), std::runtime_error); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(add_material_test, fix, fixlist, fix) { constexpr Dim_t dim{fix::sdim}; using Material_t = MaterialHyperElastic1; auto Material_hard = std::make_unique("hard", 210e9, .33); BOOST_CHECK_NO_THROW(fix::add_material(std::move(Material_hard))); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(simple_evaluation_test, fix, fixlist, fix) { constexpr Dim_t dim{fix::sdim}; constexpr Formulation form{fix::formulation}; using Mat_t = MaterialHyperElastic1; const Real Young{210e9}, Poisson{.33}; const Real lambda{Young*Poisson/((1+Poisson)*(1-2*Poisson))}; const Real mu{Young/(2*(1+Poisson))}; auto Material_hard = std::make_unique("hard", Young, Poisson); for (auto && pixel: *this) { Material_hard->add_pixel(pixel); } fix::add_material(std::move(Material_hard)); auto & F = fix::get_strain(); auto F_map = F.get_map(); // finite strain formulation expects the deformation gradient F, // while small strain expects infinitesimal strain ε for (auto grad: F_map) { switch (form) { case Formulation::finite_strain: { grad = grad.Identity(); break; } case Formulation::small_strain: { grad = grad.Zero(); break; } default: BOOST_CHECK(false); break; } } fix::initialise_materials(); auto res_tup{fix::evaluate_stress_tangent(F)}; auto stress{std::get<0>(res_tup).get_map()}; auto tangent{std::get<1>(res_tup).get_map()}; auto tup = testGoodies::objective_hooke_explicit (lambda, mu, Matrices::I2()); auto P_ref = std::get<0>(tup); for (auto mat: stress) { Real norm = (mat - P_ref).norm(); BOOST_CHECK_EQUAL(norm, 0.); } auto tan_ref = std::get<1>(tup); for (const auto tan: tangent) { Real norm = (tan - tan_ref).norm(); BOOST_CHECK_EQUAL(norm, 0.); } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(evaluation_test, fix, fixlist, fix) { constexpr Dim_t dim{fix::sdim}; using Mat_t = MaterialHyperElastic1; auto Material_hard = std::make_unique("hard", 210e9, .33); auto Material_soft = std::make_unique("soft", 70e9, .3); for (auto && cnt_pixel: akantu::enumerate(*this)) { auto counter = std::get<0>(cnt_pixel); auto && pixel = std::get<1>(cnt_pixel); if (counter < 5) { Material_hard->add_pixel(pixel); } else { Material_soft->add_pixel(pixel); } } fix::add_material(std::move(Material_hard)); fix::add_material(std::move(Material_soft)); auto & F = fix::get_strain(); fix::initialise_materials(); fix::evaluate_stress_tangent(F); fix::evaluate_stress_tangent(F); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_t4_map.cc b/tests/test_t4_map.cc index e2b0ec0..232a2ec 100644 --- a/tests/test_t4_map.cc +++ b/tests/test_t4_map.cc @@ -1,118 +1,118 @@ /** * file test_t4_map.cc * * @author Till Junge * * @date 20 Nov 2017 * * @brief Test the fourth-order map on second-order tensor implementation * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include "common/common.hh" #include "tests.hh" #include "common/T4_map_proxy.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(T4map_tests); /** * Test fixture for construction of T4Map for the time being, symmetry is not * exploited */ template struct T4_fixture { T4_fixture():matrix{}, tensor(matrix.data()){} EIGEN_MAKE_ALIGNED_OPERATOR_NEW; using M4 = T4Mat; using T4 = T4MatMap; constexpr static Dim_t dim{Dim}; M4 matrix; T4 tensor; }; using fix_collection = boost::mpl::list, T4_fixture>; BOOST_FIXTURE_TEST_CASE_TEMPLATE(Simple_construction_test, F, fix_collection, F) { BOOST_CHECK_EQUAL(F::tensor.cols(), F::dim*F::dim); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(write_access_test, F, fix_collection, F) { auto & t4 = F::tensor; constexpr Dim_t dim{F::dim}; Eigen::TensorFixedSize> t4c; Eigen::Map t4c_map(t4c.data()); for (Dim_t i = 0; i < F::dim; ++i) { for (Dim_t j = 0; j < F::dim; ++j) { for (Dim_t k = 0; k < F::dim; ++k) { for (Dim_t l = 0; l < F::dim; ++l) { get(t4,i,j,k,l) = 1000*(i+1) + 100*(j+1) + 10*(k+1) + l+1; t4c(i,j,k,l) = 1000*(i+1) + 100*(j+1) + 10*(k+1) + l+1; } } } } for (Dim_t i = 0; i < ipow(dim,4); ++i) { BOOST_CHECK_EQUAL(F::matrix.data()[i], t4c.data()[i]); } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(assign_matrix_test, F, fix_collection, F) { decltype(F::matrix) matrix; matrix.setRandom(); F::tensor = matrix; for (Dim_t i = 0; i < ipow(F::dim,4); ++i) { BOOST_CHECK_EQUAL(F::matrix.data()[i], matrix.data()[i]); } } BOOST_AUTO_TEST_CASE(Return_ref_from_const_test) { constexpr Dim_t dim{2}; using T = int; using M4 = Eigen::Matrix; using M4c = const Eigen::Matrix; using T4 = T4MatMap; using T4c = T4MatMap; M4 mat; mat.setRandom(); M4c cmat{mat}; T4 tensor{mat.data()}; T4c ctensor{mat.data()}; T a = get(tensor,0,0,0,1); T b = get(ctensor,0,0,0,1); BOOST_CHECK_EQUAL(a, b); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/test_tensor_algebra.cc b/tests/test_tensor_algebra.cc index ccd4bb5..24a16fb 100644 --- a/tests/test_tensor_algebra.cc +++ b/tests/test_tensor_algebra.cc @@ -1,294 +1,294 @@ /** * file test_tensor_algebra.cc * * @author Till Junge * * @date 05 Nov 2017 * * @brief Tests for the tensor algebra functions * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include "common/tensor_algebra.hh" #include "tests.hh" #include "common/test_goodies.hh" namespace muSpectre { BOOST_AUTO_TEST_SUITE(tensor_algebra) auto TerrNorm = [](auto && t){ return Eigen::Tensor(t.abs().sum())(); }; /* ---------------------------------------------------------------------- */ BOOST_AUTO_TEST_CASE(tensor_outer_product_test) { constexpr Dim_t dim{2}; Eigen::TensorFixedSize> A, B; // use prime numbers so that every multiple is uniquely identifiable A.setValues({{1, 2}, {3 ,7}}); B.setValues({{11, 13}, {17 ,19}}); Eigen::TensorFixedSize> Res1, Res2, Res3; for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t k = 0; k < dim; ++k) { for (Dim_t l = 0; l < dim; ++l) { Res1(i, j, k, l) = A(i, j)*B(k, l); Res2(i, j, k, l) = A(i, k)*B(j, l); Res3(i, j, k, l) = A(i, l)*B(j, k); } } } } Real error = TerrNorm(Res1 - Tensors::outer(A,B)); BOOST_CHECK_LT(error, tol); error = TerrNorm(Res2 - Tensors::outer_under(A, B)); BOOST_CHECK_LT(error, tol); error = TerrNorm(Res3 - Tensors::outer_over(A, B)); if (error > tol) { std::cout << "reference:" << std::endl << Res3 << std::endl; std::cout << "result:" << std::endl << Tensors::outer_over(A, B) << std::endl; std::cout << "A:" << std::endl << A << std::endl; std::cout << "B" << std::endl << B << std::endl; decltype(Res3) tmp = Tensors::outer_over(A, B); for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t k = 0; k < dim; ++k) { for (Dim_t l = 0; l < dim; ++l) { std::cout << "for (" << i << ", " << j << ", " << k << ", " << l << "), ref: " << std::setw(3)<< Res3(i,j,k,l) << ", res: " << std::setw(3)<< tmp(i,j,k,l) << std::endl; } } } } } BOOST_CHECK_LT(error, tol); error = TerrNorm(Res3 - Tensors::outer(A, B)); BOOST_CHECK_GT(error, tol); }; BOOST_FIXTURE_TEST_CASE_TEMPLATE(outer_products, Fix, testGoodies::dimlist, Fix) { constexpr auto dim{Fix::dim}; using T2 = Tensors::Tens2_t; using M2 = Matrices::Tens2_t; using Map2 = Eigen::Map; using T4 = Tensors::Tens4_t; using M4 = Matrices::Tens4_t; using Map4 = Eigen::Map; T2 A, B; T4 RT; A.setRandom(); B.setRandom(); Map2 Amap(A.data()); Map2 Bmap(B.data()); M2 C, D; M4 RM; C = Amap; D = Bmap; auto error =[](const T4& A, const M4& B) {return (B - Map4(A.data())).norm();}; // Check outer product RT = Tensors::outer(A, B); RM = Matrices::outer(C, D); BOOST_CHECK_LT(error(RT, RM), tol); // Check outer_under product RT = Tensors::outer_under(A, B); RM = Matrices::outer_under(C, D); BOOST_CHECK_LT(error(RT, RM), tol); // Check outer_over product RT = Tensors::outer_over(A, B); RM = Matrices::outer_over(C, D); BOOST_CHECK_LT(error(RT, RM), tol); } BOOST_AUTO_TEST_CASE(tensor_multiplication) { constexpr Dim_t dim{2}; using Strain_t = Eigen::TensorFixedSize>; Strain_t A, B; A.setValues({{1, 2}, {3 ,7}}); B.setValues({{11, 13}, {17 ,19}}); Strain_t FF1 = A*B; // element-wise multiplication std::array, 1> prod_dims { Eigen::IndexPair{1, 0}}; Strain_t FF2 = A.contract(B, prod_dims); // correct option 1 Strain_t FF3; using Mat_t = Eigen::Map>; // following only works for evaluated tensors (which already have data()) Mat_t(FF3.data()) = Mat_t(A.data()) * Mat_t(B.data()); Strain_t ref; ref.setZero(); for (Dim_t i = 0; i < dim; ++i) { for (Dim_t j = 0; j < dim; ++j) { for (Dim_t a = 0; a < dim; ++a) { ref(i,j) += A(i, a) * B(a, j); } } } using Strain_tw = Eigen::TensorFixedSize>; Strain_tw C; C.setConstant(100); //static_assert(!std::is_convertible::value, // "Tensors not size-protected"); if (std::is_convertible::value) { //std::cout << "this is not good, should I abandon Tensors?"; } // this test seems useless. I use to detect if Eigen changed the // default tensor product Real error = TerrNorm(FF1-ref); if (error < tol) { std::cout << "A =" << std::endl << A << std::endl; std::cout << "B =" << std::endl << B << std::endl; std::cout << "FF1 =" << std::endl << FF1 << std::endl; std::cout << "ref =" << std::endl << ref << std::endl; } BOOST_CHECK_GT(error, tol); error = TerrNorm(FF2-ref); if (error > tol) { std::cout << "A =" << std::endl << A << std::endl; std::cout << "B =" << std::endl << B << std::endl; std::cout << "FF2 =" << std::endl << FF2 << std::endl; std::cout << "ref =" << std::endl << ref << std::endl; } BOOST_CHECK_LT(error, tol); error = TerrNorm(FF3-ref); if (error > tol) { std::cout << "A =" << std::endl << A << std::endl; std::cout << "B =" << std::endl << B << std::endl; std::cout << "FF3 =" << std::endl << FF3 << std::endl; std::cout << "ref =" << std::endl << ref << std::endl; } BOOST_CHECK_LT(error, tol); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensmult, Fix, testGoodies::dimlist, Fix) { using namespace Matrices; constexpr Dim_t dim{Fix::dim}; using T4 = Tens4_t; using T2 = Tens2_t; using V2 = Eigen::Matrix; T4 C; C.setRandom(); T2 E; E.setRandom(); Eigen::Map Ev(E.data()); T2 R = tensmult(C, E); auto error = (Eigen::Map(R.data())-C*Ev).norm(); BOOST_CHECK_LT(error, tol); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tracer, Fix, testGoodies::dimlist, Fix) { using namespace Matrices; constexpr Dim_t dim{Fix::dim}; using T2 = Tens2_t; auto tracer = Itrac(); T2 F; F.setRandom(); auto Ftrac = tensmult(tracer, F); auto error = (Ftrac-F.trace()*F.Identity()).norm(); BOOST_CHECK_LT(error, tol); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_identity, Fix, testGoodies::dimlist, Fix) { using namespace Matrices; constexpr Dim_t dim{Fix::dim}; using T2 = Tens2_t; auto ident = Iiden(); T2 F; F.setRandom(); auto Fiden = tensmult(ident, F); auto error = (Fiden-F).norm(); BOOST_CHECK_LT(error, tol); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_transposer, Fix, testGoodies::dimlist, Fix) { using namespace Matrices; constexpr Dim_t dim{Fix::dim}; using T2 = Tens2_t; auto trnst = Itrns(); T2 F; F.setRandom(); auto Ftrns = tensmult(trnst, F); auto error = (Ftrns-F.transpose()).norm(); BOOST_CHECK_LT(error, tol); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_symmetriser, Fix, testGoodies::dimlist, Fix) { using namespace Matrices; constexpr Dim_t dim{Fix::dim}; using T2 = Tens2_t; auto symmt = Isymm(); T2 F; F.setRandom(); auto Fsymm = tensmult(symmt, F); auto error = (Fsymm-.5*(F+F.transpose())).norm(); BOOST_CHECK_LT(error, tol); } BOOST_AUTO_TEST_SUITE_END(); } // muSpectre diff --git a/tests/tests.hh b/tests/tests.hh index cddf95e..c37f3ce 100644 --- a/tests/tests.hh +++ b/tests/tests.hh @@ -1,45 +1,45 @@ /** * file tests.hh * * @author Till Junge * * @date 10 May 2017 * * @brief common defs for tests * * @section LICENCE * - * Copyright (C) 2017 Till Junge + * Copyright © 2017 Till Junge * * µSpectre 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, or (at * your option) any later version. * * µSpectre 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 GNU Emacs; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "common/common.hh" #include #include #ifndef TESTS_H #define TESTS_H namespace muSpectre { const Real tol = 1e-14*100; //it's in percent } // muSpectre #endif /* TESTS_H */