├── .github └── workflows │ ├── python.yml │ ├── python_build_posix.sh │ ├── python_build_win.ps1 │ ├── python_cmake.yml │ ├── python_test_posix.sh │ └── python_test_win.ps1 ├── .gitignore ├── .readthedocs.yaml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── c ├── .empty ├── include │ ├── helmrouts2d.h │ ├── hfmm2d.h │ └── wideband2d.h └── src │ └── .empty ├── docs ├── FMM-logo.png ├── Makefile ├── _static │ └── custom.css ├── _templates │ └── page.html ├── conf.py ├── fortran-c.rst ├── fortrandocs_helm.raw ├── fortrandocs_helm2.raw ├── fortrandocs_helm2_vec.raw ├── fortrandocs_helm_header.raw ├── fortrandocs_helm_header_vec.raw ├── genfortdocumentation_helm.py ├── index.rst ├── install.rst ├── math.rst └── requirements.txt ├── examples ├── hfmm2d_example.f ├── hfmm2d_example.make ├── hfmm2d_vec_example.f └── hfmm2d_vec_example.make ├── fmm2d_manual.pdf ├── include └── fmm2d │ └── helmholtz.h ├── lib-static └── .keep ├── lib └── .keep ├── make.inc.icc ├── make.inc.macos.gnu ├── make.inc.macos.gnu.x86-64 ├── make.inc.macos.intel ├── make.inc.macos.nag ├── make.inc.macos_arm64.gnu ├── make.inc.manylinux ├── make.inc.windows.mingw ├── makefile ├── makehelm ├── matlab ├── c2ddir.m ├── cfmm2d.m ├── cfmm2dTest.m ├── fmm2d.c ├── fmm2d.mw ├── h2ddir.m ├── hfmm2d.m ├── hfmm2dTest.m ├── l2ddir.m ├── lfmm2d.m ├── lfmm2dTest.m ├── r2ddir.m ├── rfmm2d.m ├── rfmm2dTest.m ├── st2ddir.m ├── stfmm2d.m └── stfmm2dTest.m ├── meson.build ├── pyproject.toml ├── python ├── CMakeLists.txt ├── examples │ ├── bhfmm_example.py │ ├── cfmm_example.py │ ├── lfmm_example.py │ ├── rfmm_example.py │ └── stfmm_example.py ├── fmm2dpy │ ├── __init__.py │ └── fmm2d.py ├── pyproject.toml ├── setup.py └── test │ ├── test_bhfmm.py │ ├── test_cfmm.py │ ├── test_hfmm.py │ ├── test_lfmm.py │ └── test_rfmm.py ├── src ├── biharmonic │ ├── bh2dterms.f │ ├── bhfmm2d.f │ ├── bhfmm2dwrap.f │ ├── bhkernels2d.f │ ├── bhndiv2d.f │ └── bhrouts2d.f ├── common │ ├── cdjseval2d.f │ ├── cumsum.f │ ├── dfft.f │ ├── dfft_threadsafe.f │ ├── dlaran.f │ ├── fmmcommon2d.f │ ├── hank103.f │ ├── hkrand.f │ ├── next235.f │ ├── prini.f │ ├── pts_tree2d.f │ └── tree_routs2d.f ├── helmholtz │ ├── h2dcommon.f │ ├── h2dterms.f │ ├── helmkernels2d.f │ ├── helmrouts2d.f │ ├── hfmm2d.f │ ├── hfmm2d_mps.f │ ├── hfmm2d_mps_ndiv.f │ ├── hfmm2d_ndiv.f │ ├── hfmm2dwrap.f │ ├── hfmm2dwrap_vec.f │ ├── hndiv2d.f │ └── wideband2d.f ├── helmholtz_c.f03 ├── laplace │ ├── cauchykernels2d.f │ ├── cfmm2d.f │ ├── cfmm2d_ndiv.f │ ├── cfmm2dwrap.f │ ├── cfmm2dwrap_vec.f │ ├── l2dterms.f │ ├── lapkernels2d.f │ ├── laprouts2d.f │ ├── lfmm2d.f │ ├── lfmm2d_ndiv.f │ ├── lfmm2dwrap.f │ ├── lfmm2dwrap_vec.f │ ├── lndiv2d.f │ ├── rfmm2d.f │ ├── rfmm2d_ndiv.f │ ├── rfmm2dwrap.f │ ├── rfmm2dwrap_vec.f │ └── rlapkernels2d.f ├── modified-biharmonic │ ├── jinjaroot.yaml │ ├── jinjaroot.yaml.py │ ├── mbhfmm2d.f │ ├── mbhgreen2d.f │ ├── mbhkernels2d.f │ ├── mbhkernels2d.f.j2 │ ├── mbhrouts2d.f │ └── mbhrouts2d.f.j2 └── stokes │ ├── kernels.nb │ ├── stfmm2d.f │ └── stokkernels2d.f └── test ├── biharmonic ├── run_bhtest.sh ├── test_bhfmm2d.f ├── test_bhfmm2d.make ├── test_bhrouts2d.f └── test_bhrouts2d.make ├── helmholtz ├── run_helmtest.sh ├── test_hfmm2d.f ├── test_hfmm2d.make ├── test_hfmm2d_hf.f ├── test_hfmm2d_hf.make ├── test_hfmm2d_mps.f90 ├── test_hfmm2d_mps.make └── test_hfmm2d_vec.f ├── laplace ├── run_laptest.sh ├── test_cfmm2d.f ├── test_cfmm2d.make ├── test_cfmm2d_vec.f ├── test_cfmm2d_vec.make ├── test_lfmm2d.f ├── test_lfmm2d.make ├── test_lfmm2d_vec.f ├── test_lfmm2d_vec.make ├── test_rfmm2d.f ├── test_rfmm2d.make ├── test_rfmm2d_vec.f └── test_rfmm2d_vec.make ├── modified-biharmonic ├── jinjaroot.yaml ├── jinjaroot.yaml.py ├── run_mbhtest.sh ├── test_mbhfmm2d.f ├── test_mbhfmm2d.f.j2 ├── test_mbhfmm2d.make ├── test_mbhrouts2d.f ├── test_mbhrouts2d.f.j2 └── test_mbhrouts2d.make └── stokes ├── test_stfmm2d.f └── test_stfmm2d.make /.github/workflows/python_build_posix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # This is an auxiliary script to build wheels 3 | PYTHON=$1 4 | echo "PYTHON=$PYTHON" >> make.inc 5 | $PYTHON -m pip install --upgrade setuptools wheel numpy pip 6 | make python-dist 7 | -------------------------------------------------------------------------------- /.github/workflows/python_build_win.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | Set-Variable -Name PYTHON -Value (Get-Command python).definition 3 | Set-Variable -Name MSYSTEM -Value MINGW64 4 | 5 | # setup setup.cfg 6 | New-Item -Force -Path .\python -Name "setup.cfg" -ItemType "file" -Value "[build]`r`ncompiler=mingw32`r`n[build_ext]`r`ncompiler=mingw32" 7 | 8 | # Setup the make.inc file 9 | Copy-Item -Path make.inc.windows.mingw -Destination make.inc 10 | Add-Content -Path make.inc -Value "PYTHON=""$PYTHON""" 11 | Add-Content -Path make.inc -Value "FFLAGS+= -fallow-argument-mismatch -march=x86-64" 12 | Add-Content -Path make.inc -Value "CFLAGS+= -march=x86-64" 13 | Add-Content -Path make.inc -Value "CXXFLAGS+= -march=x86-64" 14 | 15 | # Setup the distutils.cfg file 16 | Set-Variable distutils_cfg -Value ([IO.Path]::Combine((Split-Path -Path $PYTHON), "Lib", 'distutils', 'distutils.cfg')) 17 | Set-Content -Path $distutils_cfg -Value "[build]`r`ncompiler=mingw32`r`n[build_ext]`r`ncompiler=mingw32" 18 | python -m pip install --upgrade setuptools wheel numpy pip 19 | if (-not $?) {throw "Failed pip install"} 20 | 21 | # call make 22 | Set-Variable repo_root -Value ([IO.Path]::Combine($PSScriptRoot, '..', '..')) 23 | c:\msys64\usr\bin\env MSYSTEM=MINGW64 c:\msys64\usr\bin\bash.exe -lc "cd '$repo_root' && make python-dist" 24 | if (-not $?) {throw "Failed make python-dist"} 25 | 26 | # Move the required DLLs inside the wheel 27 | wheel.exe unpack (get-item .\python\dist\*.whl).FullName -d .\tpm 28 | if (-not $?) {throw "Failed unpack wheel"} 29 | Set-Variable unpacked_wheel -Value (get-item .\tpm\fmm2dpy-*).FullName 30 | Copy-Item -Path C:\msys64\mingw64\bin\libgcc_s_seh-*.dll -Destination ([IO.Path]::Combine($unpacked_wheel, 'fmm2dpy')) 31 | Copy-Item -Path C:\msys64\mingw64\bin\libgomp-*.dll -Destination ([IO.Path]::Combine($unpacked_wheel, 'fmm2dpy')) 32 | Copy-Item -Path C:\msys64\mingw64\bin\libgfortran-*.dll -Destination ([IO.Path]::Combine($unpacked_wheel, 'fmm2dpy')) 33 | Copy-Item -Path C:\msys64\mingw64\bin\libwinpthread-*.dll -Destination ([IO.Path]::Combine($unpacked_wheel, 'fmm2dpy')) 34 | Copy-Item -Path C:\msys64\mingw64\bin\libquadmath-*.dll -Destination ([IO.Path]::Combine($unpacked_wheel, 'fmm2dpy')) 35 | New-Item -Path .\wheelhouse -ItemType Directory -Force 36 | wheel.exe pack $unpacked_wheel -d .\wheelhouse 37 | if (-not $?) {throw "Failed pack wheel"} 38 | 39 | # Cleanup 40 | Remove-Item -Path $unpacked_wheel -Force -Recurse 41 | Remove-Item -Path .\python\build -Force -Recurse 42 | Remove-Item -Path .\python\dist -Force -Recurse 43 | -------------------------------------------------------------------------------- /.github/workflows/python_cmake.yml: -------------------------------------------------------------------------------- 1 | name: Python cmake build test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - v* 9 | - py_v* 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | jobs: 15 | Linux: 16 | runs-on: ubuntu-latest 17 | container: quay.io/pypa/manylinux_2_28_x86_64:latest 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: install gfortran 23 | run: | 24 | yum install -y gcc-toolset-12.x86_64 25 | 26 | - name: Compile and install python bindings 27 | run: | 28 | scl enable gcc-toolset-12 bash 29 | /opt/python/cp311-cp311/bin/python -m pip install . 30 | 31 | - name: Test python bindings 32 | run: | 33 | /opt/python/cp311-cp311/bin/python -m pip install pytest 34 | /opt/python/cp311-cp311/bin/python -m pytest -s python/test 35 | -------------------------------------------------------------------------------- /.github/workflows/python_test_posix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # This is an auxiliary script to test wheels 3 | PYTHON=$1 4 | $PYTHON -m pip install pytest 5 | $PYTHON -m pip install fmm2dpy -f wheelhouse/ --no-index --no-cache 6 | $PYTHON -m pytest -s python/test 7 | -------------------------------------------------------------------------------- /.github/workflows/python_test_win.ps1: -------------------------------------------------------------------------------- 1 | python -m pip install pytest 2 | if (-not $?) {throw "Failed to pip install pytest"} 3 | python -m pip install fmm2dpy -f .\wheelhouse\ 4 | if (-not $?) {throw "Failed to pip install fmm2dpy"} 5 | python -m pytest -s python/test 6 | if (-not $?) {throw "Tests failed"} 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | build 3 | dist 4 | res 5 | docs/_build 6 | make.inc 7 | *.so 8 | *.egg-info 9 | *.o 10 | *.out 11 | fort.* 12 | int2 13 | *.save* 14 | *_save* 15 | *.txt 16 | *.pyc 17 | *int2* 18 | *.mex* 19 | *debug* 20 | *~ 21 | lib-static/*.a 22 | GPATH 23 | GRTAGS 24 | GTAGS -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # "Read the Docs" doc-hosting website configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required (for this file format) 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build all formats 15 | formats: all 16 | 17 | # Build documentation in the docs/ directory with Sphinx 18 | sphinx: 19 | configuration: docs/conf.py 20 | 21 | # Optionally set the version of Python and requirements required to build your docs 22 | python: 23 | install: 24 | - requirements: docs/requirements.txt 25 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(fmm2d LANGUAGES C Fortran) 6 | 7 | # verbose makefile 8 | set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | # Safety net 11 | if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) 12 | message( 13 | FATAL_ERROR 14 | "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n" 15 | ) 16 | endif() 17 | 18 | # Grab Python 19 | find_package(Python REQUIRED COMPONENTS Interpreter Development.Module NumPy) 20 | # Grab OpenMP 21 | find_package(OpenMP REQUIRED) 22 | if (OpenMP_Fortran_FOUND) 23 | set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") 24 | endif() 25 | 26 | # Grab the variables from a local Python installation 27 | # F2PY headers 28 | execute_process( 29 | COMMAND "${Python_EXECUTABLE}" 30 | -c "import numpy.f2py; print(numpy.f2py.get_include())" 31 | OUTPUT_VARIABLE F2PY_INCLUDE_DIR 32 | OUTPUT_STRIP_TRAILING_WHITESPACE 33 | ) 34 | 35 | # build static lib libfmm2d.a 36 | # source files for libfmm2d.a 37 | file(GLOB_RECURSE source_list "src/*.f" "src/*.f90") 38 | #message(${source_list}) 39 | # add fmm2d static lib 40 | add_library(fmm2d STATIC ${source_list}) 41 | #compiler options 42 | target_compile_options(fmm2d PRIVATE -fallow-argument-mismatch -fPIC -O3 -march=native -funroll-loops -std=legacy -w) 43 | 44 | set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fallow-argument-mismatch") 45 | 46 | # Print out the discovered paths 47 | include(CMakePrintHelpers) 48 | cmake_print_variables(Python_INCLUDE_DIRS) 49 | cmake_print_variables(F2PY_INCLUDE_DIR) 50 | cmake_print_variables(Python_NumPy_INCLUDE_DIRS) 51 | 52 | # extensions variables 53 | # hfmm2d_fortran 54 | set(hfmm_module_name "hfmm2d_fortran") 55 | set(hfmm_fortran_src_file ${CMAKE_SOURCE_DIR}/src/helmholtz/hfmm2dwrap.f 56 | ${CMAKE_SOURCE_DIR}/src/helmholtz/hfmm2dwrap_vec.f 57 | ${CMAKE_SOURCE_DIR}/src/helmholtz/helmkernels2d.f) 58 | set(f2py_helm_module_c "${hfmm_module_name}module.c") 59 | # lfmm2d_fortran 60 | set(lfmm_module_name "lfmm2d_fortran") 61 | set(lfmm_fortran_src_file ${CMAKE_SOURCE_DIR}/src/laplace/lfmm2dwrap.f 62 | ${CMAKE_SOURCE_DIR}/src/laplace/lfmm2dwrap_vec.f 63 | ${CMAKE_SOURCE_DIR}/src/laplace/lapkernels2d.f 64 | ${CMAKE_SOURCE_DIR}/src/laplace/rfmm2dwrap.f 65 | ${CMAKE_SOURCE_DIR}/src/laplace/rfmm2dwrap_vec.f 66 | ${CMAKE_SOURCE_DIR}/src/laplace/rlapkernels2d.f 67 | ${CMAKE_SOURCE_DIR}/src/laplace/cfmm2dwrap.f 68 | ${CMAKE_SOURCE_DIR}/src/laplace/cfmm2dwrap_vec.f 69 | ${CMAKE_SOURCE_DIR}/src/laplace/cauchykernels2d.f) 70 | set(f2py_lap_module_c "${lfmm_module_name}module.c") 71 | # bhfmm2d_fortran 72 | set(bhfmm_module_name "bhfmm2d_fortran") 73 | set(bhfmm_fortran_src_file ${CMAKE_SOURCE_DIR}/src/biharmonic/bhfmm2dwrap.f 74 | ${CMAKE_SOURCE_DIR}/src/biharmonic/bhkernels2d.f) 75 | set(f2py_bh_module_c "${bhfmm_module_name}module.c") 76 | # stfmm2d_fortran 77 | set(stfmm_module_name "stfmm2d_fortran") 78 | set(stfmm_fortran_src_file ${CMAKE_SOURCE_DIR}/src/stokes/stfmm2d.f 79 | ${CMAKE_SOURCE_DIR}/src/stokes/stokkernels2d.f) 80 | set(f2py_st_module_c "${stfmm_module_name}module.c") 81 | 82 | # Generate extensions' sources 83 | # hfmm2d_fortran 84 | add_custom_target( 85 | hfmm_genpyf 86 | DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${f2py_helm_module_c}" 87 | ) 88 | add_custom_command( 89 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${f2py_helm_module_c}" "${CMAKE_CURRENT_BINARY_DIR}/${hfmm_module_name}-f2pywrappers2.f90" 90 | COMMAND ${Python_EXECUTABLE} -m "numpy.f2py" 91 | -m "hfmm2d_fortran" 92 | ${hfmm_fortran_src_file} 93 | --lower 94 | DEPENDS ${hfmm_fortran_src_file} # Fortran source 95 | ) 96 | # lfmm2d_fortran 97 | add_custom_target( 98 | lfmm_genpyf 99 | DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${f2py_lap_module_c}" 100 | ) 101 | add_custom_command( 102 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${f2py_lap_module_c}" "${CMAKE_CURRENT_BINARY_DIR}/${lfmm_module_name}-f2pywrappers2.f90" 103 | COMMAND ${Python_EXECUTABLE} -m "numpy.f2py" 104 | -m "lfmm2d_fortran" 105 | ${lfmm_fortran_src_file} 106 | --lower 107 | DEPENDS ${lfmm_fortran_src_file} # Fortran source 108 | ) 109 | # bhfmm2d_fortran 110 | add_custom_target( 111 | bhfmm_genpyf 112 | DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${f2py_bh_module_c}" 113 | ) 114 | add_custom_command( 115 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${f2py_bh_module_c}" "${CMAKE_CURRENT_BINARY_DIR}/${bhfmm_module_name}-f2pywrappers2.f90" 116 | COMMAND ${Python_EXECUTABLE} -m "numpy.f2py" 117 | -m "bhfmm2d_fortran" 118 | ${bhfmm_fortran_src_file} 119 | --lower 120 | DEPENDS ${bhfmm_fortran_src_file} # Fortran source 121 | ) 122 | # stfmm2d_fortran 123 | add_custom_target( 124 | stfmm_genpyf 125 | DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${f2py_st_module_c}" 126 | ) 127 | add_custom_command( 128 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${f2py_st_module_c}" "${CMAKE_CURRENT_BINARY_DIR}/${stfmm_module_name}-f2pywrappers2.f90" 129 | COMMAND ${Python_EXECUTABLE} -m "numpy.f2py" 130 | -m "stfmm2d_fortran" 131 | ${stfmm_fortran_src_file} 132 | --lower 133 | DEPENDS ${stfmm_fortran_src_file} # Fortran source 134 | ) 135 | 136 | # Set up extensions targets 137 | # hfmm2d_fortran 138 | Python_add_library(hfmm2d_fortran MODULE WITH_SOABI 139 | "${CMAKE_CURRENT_BINARY_DIR}/${f2py_helm_module_c}" # Generated 140 | "${F2PY_INCLUDE_DIR}/fortranobject.c" # From NumPy 141 | "${hfmm_fortran_src_file}" # Fortran source(s) 142 | ) 143 | # lfmm2d_fortran 144 | Python_add_library(lfmm2d_fortran MODULE WITH_SOABI 145 | "${CMAKE_CURRENT_BINARY_DIR}/${f2py_lap_module_c}" # Generated 146 | "${F2PY_INCLUDE_DIR}/fortranobject.c" # From NumPy 147 | "${lfmm_fortran_src_file}" # Fortran source(s) 148 | ) 149 | # bhfmm2d_fortran 150 | Python_add_library(bhfmm2d_fortran MODULE WITH_SOABI 151 | "${CMAKE_CURRENT_BINARY_DIR}/${f2py_bh_module_c}" # Generated 152 | "${F2PY_INCLUDE_DIR}/fortranobject.c" # From NumPy 153 | "${bhfmm_fortran_src_file}" # Fortran source(s) 154 | ) 155 | # stfmm2d_fortran 156 | Python_add_library(stfmm2d_fortran MODULE WITH_SOABI 157 | "${CMAKE_CURRENT_BINARY_DIR}/${f2py_st_module_c}" # Generated 158 | "${F2PY_INCLUDE_DIR}/fortranobject.c" # From NumPy 159 | "${stfmm_fortran_src_file}" # Fortran source(s) 160 | ) 161 | 162 | # Dependencies for extensions 163 | # hfmm2d_fortran 164 | target_link_libraries(hfmm2d_fortran PRIVATE Python::NumPy fmm2d) 165 | add_dependencies(hfmm2d_fortran hfmm_genpyf) 166 | target_include_directories(hfmm2d_fortran PRIVATE "${F2PY_INCLUDE_DIR}") 167 | # lfmm2d_fortran 168 | target_link_libraries(lfmm2d_fortran PRIVATE Python::NumPy fmm2d) 169 | add_dependencies(lfmm2d_fortran lfmm_genpyf) 170 | target_include_directories(lfmm2d_fortran PRIVATE "${F2PY_INCLUDE_DIR}") 171 | # bhfmm2d_fortran 172 | target_link_libraries(bhfmm2d_fortran PRIVATE Python::NumPy fmm2d) 173 | add_dependencies(bhfmm2d_fortran bhfmm_genpyf) 174 | target_include_directories(bhfmm2d_fortran PRIVATE "${F2PY_INCLUDE_DIR}") 175 | # stfmm2d_fortran 176 | target_link_libraries(stfmm2d_fortran PRIVATE Python::NumPy fmm2d) 177 | add_dependencies(stfmm2d_fortran stfmm_genpyf) 178 | target_include_directories(stfmm2d_fortran PRIVATE "${F2PY_INCLUDE_DIR}") 179 | 180 | add_subdirectory(python) 181 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Flatiron Institute Fast Multipole Libraries 2 | 3 | This codebase is a set of libraries to compute N-body interactions 4 | governed by the Laplace and Helmholtz equations, to a specified 5 | precision, in two dimensions, on a multi-core shared-memory machine. 6 | 7 | Please see the [online documentation](https://fmm2d.readthedocs.io), 8 | or its equivalent [user manual](fmm2d_manual.pdf). 9 | -------------------------------------------------------------------------------- /c/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/fmm2d/550dae5b77b1e006c8ffae37fc832f8c2b536871/c/.empty -------------------------------------------------------------------------------- /c/include/helmrouts2d.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | void h2dformmpc_(int *nd, double complex *zk, double *rscale, double *source, 5 | int *ns, double complex *charge, double *center, 6 | int *nterms, double complex *mpole); 7 | 8 | 9 | void h2dmpmp_(int *nd, double complex *zk, double *rscale1, double *center1, 10 | double complex *hexp1, int *nterms1, double *rscale2, 11 | double *center2, double complex *hexp2, int *nterms2); 12 | 13 | 14 | void h2dmpmp_(int *nd, double _Complex *zk, double *rscale0, double *center0, 15 | double _Complex *mpole0, int *nterms0, 16 | double *rscale1, double *center1, 17 | double _Complex *mpole1, int *nterms1); 18 | 19 | 20 | -------------------------------------------------------------------------------- /c/include/hfmm2d.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /c/include/wideband2d.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | void h2dmpmphf_(int *nd, double _Complex *zk, double *rscale0, double *center0, 4 | double _Complex *mpole0, int *nterms0, 5 | double *rscale1, double *center1, 6 | double _Complex *mpole1, int *nterms1); 7 | 8 | void h2dmplochf_(int *nd, double _Complex *zk, double *rscale0, double *center0, 9 | double _Complex *mpole0, int *nterms0, 10 | double *rscale1, double *center1, 11 | double _Complex *mpole1, int *nterms1); 12 | 13 | void h2dloclochf_(int *nd, double _Complex *zk, double *rscale0, double *center0, 14 | double _Complex *mpole0, int *nterms0, 15 | double *rscale1, double *center1, 16 | double _Complex *mpole1, int *nterms1); 17 | 18 | -------------------------------------------------------------------------------- /c/src/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/fmm2d/550dae5b77b1e006c8ffae37fc832f8c2b536871/c/src/.empty -------------------------------------------------------------------------------- /docs/FMM-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/fmm2d/550dae5b77b1e006c8ffae37fc832f8c2b536871/docs/FMM-logo.png -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help 23 | help: 24 | @echo "Please use \`make ' where is one of" 25 | @echo " html to make standalone HTML files" 26 | @echo " dirhtml to make HTML files named index.html in directories" 27 | @echo " singlehtml to make a single large HTML file" 28 | @echo " pickle to make pickle files" 29 | @echo " json to make JSON files" 30 | @echo " htmlhelp to make HTML files and a HTML help project" 31 | @echo " qthelp to make HTML files and a qthelp project" 32 | @echo " applehelp to make an Apple Help Book" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | @echo " coverage to run coverage check of the documentation (if enabled)" 49 | 50 | .PHONY: clean 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | .PHONY: html 55 | html: 56 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 57 | @echo 58 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 59 | 60 | .PHONY: dirhtml 61 | dirhtml: 62 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 63 | @echo 64 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 65 | 66 | .PHONY: singlehtml 67 | singlehtml: 68 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 69 | @echo 70 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 71 | 72 | .PHONY: pickle 73 | pickle: 74 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 75 | @echo 76 | @echo "Build finished; now you can process the pickle files." 77 | 78 | .PHONY: json 79 | json: 80 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 81 | @echo 82 | @echo "Build finished; now you can process the JSON files." 83 | 84 | .PHONY: htmlhelp 85 | htmlhelp: 86 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 87 | @echo 88 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 89 | ".hhp project file in $(BUILDDIR)/htmlhelp." 90 | 91 | .PHONY: qthelp 92 | qthelp: 93 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 94 | @echo 95 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 96 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 97 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/finufft.qhcp" 98 | @echo "To view the help file:" 99 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/finufft.qhc" 100 | 101 | .PHONY: applehelp 102 | applehelp: 103 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 104 | @echo 105 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 106 | @echo "N.B. You won't be able to view it unless you put it in" \ 107 | "~/Library/Documentation/Help or install it in your application" \ 108 | "bundle." 109 | 110 | .PHONY: devhelp 111 | devhelp: 112 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 113 | @echo 114 | @echo "Build finished." 115 | @echo "To view the help file:" 116 | @echo "# mkdir -p $$HOME/.local/share/devhelp/finufft" 117 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/finufft" 118 | @echo "# devhelp" 119 | 120 | .PHONY: epub 121 | epub: 122 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 123 | @echo 124 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 125 | 126 | .PHONY: latex 127 | latex: 128 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 129 | @echo 130 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 131 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 132 | "(use \`make latexpdf' here to do that automatically)." 133 | 134 | .PHONY: latexpdf 135 | latexpdf: 136 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 137 | @echo "Running LaTeX files through pdflatex..." 138 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 139 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 140 | 141 | .PHONY: latexpdfja 142 | latexpdfja: 143 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 144 | @echo "Running LaTeX files through platex and dvipdfmx..." 145 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 146 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 147 | 148 | .PHONY: text 149 | text: 150 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 151 | @echo 152 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 153 | 154 | .PHONY: man 155 | man: 156 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 157 | @echo 158 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 159 | 160 | .PHONY: texinfo 161 | texinfo: 162 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 163 | @echo 164 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 165 | @echo "Run \`make' in that directory to run these through makeinfo" \ 166 | "(use \`make info' here to do that automatically)." 167 | 168 | .PHONY: info 169 | info: 170 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 171 | @echo "Running Texinfo files through makeinfo..." 172 | make -C $(BUILDDIR)/texinfo info 173 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 174 | 175 | .PHONY: gettext 176 | gettext: 177 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 178 | @echo 179 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 180 | 181 | .PHONY: changes 182 | changes: 183 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 184 | @echo 185 | @echo "The overview file is in $(BUILDDIR)/changes." 186 | 187 | .PHONY: linkcheck 188 | linkcheck: 189 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 190 | @echo 191 | @echo "Link check complete; look for any errors in the above output " \ 192 | "or in $(BUILDDIR)/linkcheck/output.txt." 193 | 194 | .PHONY: doctest 195 | doctest: 196 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 197 | @echo "Testing of doctests in the sources finished, look at the " \ 198 | "results in $(BUILDDIR)/doctest/output.txt." 199 | 200 | .PHONY: coverage 201 | coverage: 202 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 203 | @echo "Testing of coverage in the sources finished, look at the " \ 204 | "results in $(BUILDDIR)/coverage/python.txt." 205 | 206 | .PHONY: xml 207 | xml: 208 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 209 | @echo 210 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 211 | 212 | .PHONY: pseudoxml 213 | pseudoxml: 214 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 215 | @echo 216 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 217 | -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | .center {text-align: center;} 2 | 3 | .rttext {text-align: right;} 4 | 5 | .hruleaft {display: block; border-bottom: 1px solid #000000;} 6 | -------------------------------------------------------------------------------- /docs/_templates/page.html: -------------------------------------------------------------------------------- 1 | {% extends "!page.html" %} 2 | 3 | {% block footer %} 4 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /docs/fortran-c.rst: -------------------------------------------------------------------------------- 1 | .. _fcexmp: 2 | 3 | Fortran interfaces 4 | ======================== 5 | 6 | - :ref:`helm` 7 | 8 | 9 | .. _helm: 10 | 11 | Helmholtz FMM 12 | -------------- 13 | 14 | The Helmholtz FMM evaluates the following potential, its 15 | gradient and its hessian 16 | 17 | .. math:: 18 | 19 | 20 | u(x) = \sum_{j=1}^{N} c_{j} H_{0}^{(1)}(\|x-x_{j}\|) - v_{j} d_{j}\cdot \nabla H_{0}^{(1)}(\|x-x_{j}\|) \, . 21 | 22 | Here $x_{j}$ are the source locations, $c_{j}$ are the 23 | charge strengths, $v_{j}$ are the dipole strengths, and 24 | $d_{j}$ are the dipole orientation vectors. 25 | The collection of $x$ at which the potential 26 | and its gradient are evaluated are referred to as the 27 | evalution points. 28 | 29 | 30 | There are 27 different Fortran wrappers for the Helmholtz FMM 31 | to account for collection of evaluation points (sources only, 32 | targets only, sources+targets), interaction kernel (charges only, 33 | dipoles only, charges + dipoles), output request (potential, 34 | potential+gradient,potential+gradient+hessian). 35 | 36 | For example, the subroutine to evaluate the potential and gradient, at a collection 37 | of targets $t_{i}$ due to a collection of charges is:: 38 | 39 | hfmm2d_t_c_g 40 | 41 | In general, the subroutine names take the following form:: 42 | 43 | hfmm2d___ 44 | 45 | 46 | 47 | - : evaluation points. Collection of `x` where $u$ and its gradient is to be evaluated 48 | 49 | - s: Evaluate $u$ and its gradient at the source locations $x_{i}$ 50 | - t: Evaluate $u$ and its gradient at $t_{i}$, a collection of target locations specified by the user. 51 | - st: Evaluate $u$ and its gradient at both source and target locations $x_{i}$ and $t_{i}$. 52 | 53 | - : kernel of interaction (type of sources present) 54 | 55 | - c: charges 56 | - d: dipoles 57 | - cd: charges + dipoles 58 | 59 | - : flag for evaluating potential or potential + gradient 60 | 61 | - p: on output only $u$ is evaluated 62 | - g: on output both $u$ and its gradient are evaluated 63 | - h: on output $u$, its gradient and its hessian are evaluated 64 | 65 | These are all the single density routines. To get a vectorized version 66 | of any of the routines use:: 67 | 68 | _vec 69 | 70 | .. note:: 71 | 72 | For the vectorized subroutines, the charge strengths, dipole 73 | strengths, potentials, and gradients are interleaved as opposed to 74 | provided in a sequential manner. For example for three sets of charge 75 | strengths, they should be stored as $c_{1,1}, c_{2,1}, c_{3,1}, 76 | c_{1,2}, c_{2,2},c_{3,2} \ldots c_{1,N}, c_{2,N}, c_{3,N}$. 77 | 78 | 79 | Example drivers: 80 | 81 | - ``examples/hfmm2d_example.f``. The corresponding makefile is 82 | ``examples/hfmm2d_example.make`` 83 | - ``examples/hfmm2d_vec_example.f``. The corresponding makefile is 84 | ``examples/hfmm2d_vec_example.make`` 85 | 86 | 87 | .. container:: rttext 88 | 89 | `Back to top `__ 90 | 91 | 92 | List of interfaces 93 | ****************** 94 | 95 | - Evaluation points: Sources 96 | 97 | - Interaction Type: Charges 98 | 99 | - Potential (:ref:`hscp`) 100 | - Gradient (:ref:`hscg`) 101 | - Hessian (:ref:`hsch`) 102 | 103 | - Interaction Type: Dipoles 104 | 105 | - Potential (:ref:`hsdp`) 106 | - Gradient (:ref:`hsdg`) 107 | - Hessian (:ref:`hsdh`) 108 | 109 | - Interaction Type: Charges + Dipoles 110 | 111 | - Potential (:ref:`hscdp`) 112 | - Gradient (:ref:`hscdg`) 113 | - Hessian (:ref:`hscdh`) 114 | 115 | 116 | - Evaluation points: Targets 117 | 118 | - Interaction Type: Charges 119 | 120 | - Potential (:ref:`htcp`) 121 | - Gradient (:ref:`htcg`) 122 | - Hessian (:ref:`htch`) 123 | 124 | - Interaction Type: Dipoles 125 | 126 | - Potential (:ref:`htdp`) 127 | - Gradient (:ref:`htdg`) 128 | - Hessian (:ref:`htdh`) 129 | 130 | - Interaction Type: Charges + Dipoles 131 | 132 | - Potential (:ref:`htcdp`) 133 | - Gradient (:ref:`htcdg`) 134 | - Hessian (:ref:`htcdh`) 135 | 136 | - Evaluation points: Sources + Targets 137 | 138 | - Interaction Type: Charges 139 | 140 | - Potential (:ref:`hstcp`) 141 | - Gradient (:ref:`hstcg`) 142 | - Hessian (:ref:`hstch`) 143 | 144 | - Interaction Type: Dipoles 145 | 146 | - Potential (:ref:`hstdp`) 147 | - Gradient (:ref:`hstdg`) 148 | - Hessian (:ref:`hstdh`) 149 | 150 | - Interaction Type: Charges + Dipoles 151 | 152 | - Potential (:ref:`hstcdp`) 153 | - Gradient (:ref:`hstcdg`) 154 | - Hessian (:ref:`hstcdh`) 155 | 156 | 157 | .. container:: rttext 158 | 159 | `Back to top `__ 160 | 161 | 162 | .. include:: fortrandocs_helm.raw 163 | 164 | 165 | -------------------------------------------------------------------------------- /docs/fortrandocs_helm_header.raw: -------------------------------------------------------------------------------- 1 | c -hfmm2d_s_c_p 2 | c - Evaluation points: Sources 3 | c - Interaction kernel: Charges 4 | c - Outputs requested: Potential 5 | c------------------------------------- 6 | c -hfmm2d_s_c_g 7 | c - Evaluation points: Sources 8 | c - Interaction kernel: Charges 9 | c - Outputs requested: Potential and Gradient 10 | c------------------------------------- 11 | c -hfmm2d_s_c_h 12 | c - Evaluation points: Sources 13 | c - Interaction kernel: Charges 14 | c - Outputs requested: Potential, Gradient and Hessian 15 | c------------------------------------- 16 | c -hfmm2d_s_d_p 17 | c - Evaluation points: Sources 18 | c - Interaction kernel: Dipoles 19 | c - Outputs requested: Potential 20 | c------------------------------------- 21 | c -hfmm2d_s_d_g 22 | c - Evaluation points: Sources 23 | c - Interaction kernel: Dipoles 24 | c - Outputs requested: Potential and Gradient 25 | c------------------------------------- 26 | c -hfmm2d_s_d_h 27 | c - Evaluation points: Sources 28 | c - Interaction kernel: Dipoles 29 | c - Outputs requested: Potential, Gradient and Hessian 30 | c------------------------------------- 31 | c -hfmm2d_s_cd_p 32 | c - Evaluation points: Sources 33 | c - Interaction kernel: Charges and Dipoles 34 | c - Outputs requested: Potential 35 | c------------------------------------- 36 | c -hfmm2d_s_cd_g 37 | c - Evaluation points: Sources 38 | c - Interaction kernel: Charges and Dipoles 39 | c - Outputs requested: Potential and Gradient 40 | c------------------------------------- 41 | c -hfmm2d_s_cd_h 42 | c - Evaluation points: Sources 43 | c - Interaction kernel: Charges and Dipoles 44 | c - Outputs requested: Potential, Gradient and Hessian 45 | c------------------------------------- 46 | c -hfmm2d_t_c_p 47 | c - Evaluation points: Targets 48 | c - Interaction kernel: Charges 49 | c - Outputs requested: Potential 50 | c------------------------------------- 51 | c -hfmm2d_t_c_g 52 | c - Evaluation points: Targets 53 | c - Interaction kernel: Charges 54 | c - Outputs requested: Potential and Gradient 55 | c------------------------------------- 56 | c -hfmm2d_t_c_h 57 | c - Evaluation points: Targets 58 | c - Interaction kernel: Charges 59 | c - Outputs requested: Potential, Gradient and Hessian 60 | c------------------------------------- 61 | c -hfmm2d_t_d_p 62 | c - Evaluation points: Targets 63 | c - Interaction kernel: Dipoles 64 | c - Outputs requested: Potential 65 | c------------------------------------- 66 | c -hfmm2d_t_d_g 67 | c - Evaluation points: Targets 68 | c - Interaction kernel: Dipoles 69 | c - Outputs requested: Potential and Gradient 70 | c------------------------------------- 71 | c -hfmm2d_t_d_h 72 | c - Evaluation points: Targets 73 | c - Interaction kernel: Dipoles 74 | c - Outputs requested: Potential, Gradient and Hessian 75 | c------------------------------------- 76 | c -hfmm2d_t_cd_p 77 | c - Evaluation points: Targets 78 | c - Interaction kernel: Charges and Dipoles 79 | c - Outputs requested: Potential 80 | c------------------------------------- 81 | c -hfmm2d_t_cd_g 82 | c - Evaluation points: Targets 83 | c - Interaction kernel: Charges and Dipoles 84 | c - Outputs requested: Potential and Gradient 85 | c------------------------------------- 86 | c -hfmm2d_t_cd_h 87 | c - Evaluation points: Targets 88 | c - Interaction kernel: Charges and Dipoles 89 | c - Outputs requested: Potential, Gradient and Hessian 90 | c------------------------------------- 91 | c -hfmm2d_st_c_p 92 | c - Evaluation points: Sources and Targets 93 | c - Interaction kernel: Charges 94 | c - Outputs requested: Potential 95 | c------------------------------------- 96 | c -hfmm2d_st_c_g 97 | c - Evaluation points: Sources and Targets 98 | c - Interaction kernel: Charges 99 | c - Outputs requested: Potential and Gradient 100 | c------------------------------------- 101 | c -hfmm2d_st_c_h 102 | c - Evaluation points: Sources and Targets 103 | c - Interaction kernel: Charges 104 | c - Outputs requested: Potential, Gradient and Hessian 105 | c------------------------------------- 106 | c -hfmm2d_st_d_p 107 | c - Evaluation points: Sources and Targets 108 | c - Interaction kernel: Dipoles 109 | c - Outputs requested: Potential 110 | c------------------------------------- 111 | c -hfmm2d_st_d_g 112 | c - Evaluation points: Sources and Targets 113 | c - Interaction kernel: Dipoles 114 | c - Outputs requested: Potential and Gradient 115 | c------------------------------------- 116 | c -hfmm2d_st_d_h 117 | c - Evaluation points: Sources and Targets 118 | c - Interaction kernel: Dipoles 119 | c - Outputs requested: Potential, Gradient and Hessian 120 | c------------------------------------- 121 | c -hfmm2d_st_cd_p 122 | c - Evaluation points: Sources and Targets 123 | c - Interaction kernel: Charges and Dipoles 124 | c - Outputs requested: Potential 125 | c------------------------------------- 126 | c -hfmm2d_st_cd_g 127 | c - Evaluation points: Sources and Targets 128 | c - Interaction kernel: Charges and Dipoles 129 | c - Outputs requested: Potential and Gradient 130 | c------------------------------------- 131 | c -hfmm2d_st_cd_h 132 | c - Evaluation points: Sources and Targets 133 | c - Interaction kernel: Charges and Dipoles 134 | c - Outputs requested: Potential, Gradient and Hessian 135 | c------------------------------------- 136 | -------------------------------------------------------------------------------- /docs/fortrandocs_helm_header_vec.raw: -------------------------------------------------------------------------------- 1 | c -hfmm2d_s_c_p_vec 2 | c - Evaluation points: Sources 3 | c - Interaction kernel: Charges 4 | c - Outputs requested: Potential 5 | c------------------------------------- 6 | c -hfmm2d_s_c_g_vec 7 | c - Evaluation points: Sources 8 | c - Interaction kernel: Charges 9 | c - Outputs requested: Potential and Gradient 10 | c------------------------------------- 11 | c -hfmm2d_s_c_h_vec 12 | c - Evaluation points: Sources 13 | c - Interaction kernel: Charges 14 | c - Outputs requested: Potential, Gradient and Hessian 15 | c------------------------------------- 16 | c -hfmm2d_s_d_p_vec 17 | c - Evaluation points: Sources 18 | c - Interaction kernel: Dipoles 19 | c - Outputs requested: Potential 20 | c------------------------------------- 21 | c -hfmm2d_s_d_g_vec 22 | c - Evaluation points: Sources 23 | c - Interaction kernel: Dipoles 24 | c - Outputs requested: Potential and Gradient 25 | c------------------------------------- 26 | c -hfmm2d_s_d_h_vec 27 | c - Evaluation points: Sources 28 | c - Interaction kernel: Dipoles 29 | c - Outputs requested: Potential, Gradient and Hessian 30 | c------------------------------------- 31 | c -hfmm2d_s_cd_p_vec 32 | c - Evaluation points: Sources 33 | c - Interaction kernel: Charges and Dipoles 34 | c - Outputs requested: Potential 35 | c------------------------------------- 36 | c -hfmm2d_s_cd_g_vec 37 | c - Evaluation points: Sources 38 | c - Interaction kernel: Charges and Dipoles 39 | c - Outputs requested: Potential and Gradient 40 | c------------------------------------- 41 | c -hfmm2d_s_cd_h_vec 42 | c - Evaluation points: Sources 43 | c - Interaction kernel: Charges and Dipoles 44 | c - Outputs requested: Potential, Gradient and Hessian 45 | c------------------------------------- 46 | c -hfmm2d_t_c_p_vec 47 | c - Evaluation points: Targets 48 | c - Interaction kernel: Charges 49 | c - Outputs requested: Potential 50 | c------------------------------------- 51 | c -hfmm2d_t_c_g_vec 52 | c - Evaluation points: Targets 53 | c - Interaction kernel: Charges 54 | c - Outputs requested: Potential and Gradient 55 | c------------------------------------- 56 | c -hfmm2d_t_c_h_vec 57 | c - Evaluation points: Targets 58 | c - Interaction kernel: Charges 59 | c - Outputs requested: Potential, Gradient and Hessian 60 | c------------------------------------- 61 | c -hfmm2d_t_d_p_vec 62 | c - Evaluation points: Targets 63 | c - Interaction kernel: Dipoles 64 | c - Outputs requested: Potential 65 | c------------------------------------- 66 | c -hfmm2d_t_d_g_vec 67 | c - Evaluation points: Targets 68 | c - Interaction kernel: Dipoles 69 | c - Outputs requested: Potential and Gradient 70 | c------------------------------------- 71 | c -hfmm2d_t_d_h_vec 72 | c - Evaluation points: Targets 73 | c - Interaction kernel: Dipoles 74 | c - Outputs requested: Potential, Gradient and Hessian 75 | c------------------------------------- 76 | c -hfmm2d_t_cd_p_vec 77 | c - Evaluation points: Targets 78 | c - Interaction kernel: Charges and Dipoles 79 | c - Outputs requested: Potential 80 | c------------------------------------- 81 | c -hfmm2d_t_cd_g_vec 82 | c - Evaluation points: Targets 83 | c - Interaction kernel: Charges and Dipoles 84 | c - Outputs requested: Potential and Gradient 85 | c------------------------------------- 86 | c -hfmm2d_t_cd_h_vec 87 | c - Evaluation points: Targets 88 | c - Interaction kernel: Charges and Dipoles 89 | c - Outputs requested: Potential, Gradient and Hessian 90 | c------------------------------------- 91 | c -hfmm2d_st_c_p_vec 92 | c - Evaluation points: Sources and Targets 93 | c - Interaction kernel: Charges 94 | c - Outputs requested: Potential 95 | c------------------------------------- 96 | c -hfmm2d_st_c_g_vec 97 | c - Evaluation points: Sources and Targets 98 | c - Interaction kernel: Charges 99 | c - Outputs requested: Potential and Gradient 100 | c------------------------------------- 101 | c -hfmm2d_st_c_h_vec 102 | c - Evaluation points: Sources and Targets 103 | c - Interaction kernel: Charges 104 | c - Outputs requested: Potential, Gradient and Hessian 105 | c------------------------------------- 106 | c -hfmm2d_st_d_p_vec 107 | c - Evaluation points: Sources and Targets 108 | c - Interaction kernel: Dipoles 109 | c - Outputs requested: Potential 110 | c------------------------------------- 111 | c -hfmm2d_st_d_g_vec 112 | c - Evaluation points: Sources and Targets 113 | c - Interaction kernel: Dipoles 114 | c - Outputs requested: Potential and Gradient 115 | c------------------------------------- 116 | c -hfmm2d_st_d_h_vec 117 | c - Evaluation points: Sources and Targets 118 | c - Interaction kernel: Dipoles 119 | c - Outputs requested: Potential, Gradient and Hessian 120 | c------------------------------------- 121 | c -hfmm2d_st_cd_p_vec 122 | c - Evaluation points: Sources and Targets 123 | c - Interaction kernel: Charges and Dipoles 124 | c - Outputs requested: Potential 125 | c------------------------------------- 126 | c -hfmm2d_st_cd_g_vec 127 | c - Evaluation points: Sources and Targets 128 | c - Interaction kernel: Charges and Dipoles 129 | c - Outputs requested: Potential and Gradient 130 | c------------------------------------- 131 | c -hfmm2d_st_cd_h_vec 132 | c - Evaluation points: Sources and Targets 133 | c - Interaction kernel: Charges and Dipoles 134 | c - Outputs requested: Potential, Gradient and Hessian 135 | c------------------------------------- 136 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. fmm2d documentation master file, created by 2 | sphinx-quickstart on Wed Nov 1 16:19:13 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Fast multipole methods in two dimensions (fmm2d) 7 | ================================================== 8 | 9 | .. image:: FMM-logo.png 10 | :width: 60% 11 | :align: center 12 | 13 | `fmm2d `_ 14 | is a set of libraries to compute N-body interactions 15 | governed by the Laplace and Helmholtz equations, 16 | to a specified precision, in three dimensions, 17 | on a multi-core shared-memory machine. 18 | The library is written in Fortran, 19 | wrappers will soon be available for C, MATLAB, and Python. 20 | As an example, given $M$ arbitrary points $y_j \in \mathbb{R}^{2}$ 21 | with corresponding real numbers $c_j$, and 22 | $N$ arbitrary points $x_{j} \in \mathbb{R}^{2}$, the Laplace FMM 23 | evaluates the $N$ real numbers 24 | 25 | .. math:: u_{\ell} = \sum_{j=1}^M c_j\log{\| x_{\ell} - y_{j}\|} ~, 26 | \qquad \mbox{ for } \; \ell=1,2,\ldots N ~. 27 | :label: lapcp 28 | 29 | The $y_j$ can be interpreted as source locations, $c_j$ 30 | as charge strengths, and $u_{\ell}$ as the resulting potential at 31 | target location $x_{\ell}$. 32 | 33 | Such N-body interactions are needed in many applications in 34 | science and engineering, including molecular dynamics, astrophysics, 35 | rheology, and the numerical solution of partial differential equations. 36 | The naive CPU effort to evaluate :eq:`lapcp` is $O(NM)$. 37 | The FMM approximates :eq:`lapcp` to a requested relative precision 38 | $\epsilon$ with linear effort $O((M+N) \log (1/\epsilon))$. 39 | 40 | The FMM relies on compressing the interactions between well-separated 41 | clusters of source and target points at a hierarchy of scales using 42 | analytic outgoing, incoming, and plane-wave 43 | expansions of the interaction kernel and associated translation 44 | operators. 45 | This library is an improved version of the `FMMLIB2D `_ 46 | software, Copyright (C) 2010-2012: Leslie Greengard and Zydrunas Gimbutas, released under the 47 | BSD license. 48 | The major improvements are the following: 49 | 50 | - Vectorization of the FMM, to apply the same kernel with the same source and target locations to multiple 51 | strength vectors 52 | - A redesign of the adaptive tree data structure 53 | - Diagonal form translation operators for high frequency Helmholtz 54 | problems 55 | 56 | 57 | .. note:: 58 | 59 | For very small repeated problems (less than 1000 input and output points), 60 | users should also consider dense matrix-matrix multiplication using 61 | BLAS3 (eg DGEMM,ZGEMM). 62 | 63 | 64 | .. toctree:: 65 | :maxdepth: 2 66 | 67 | install 68 | math 69 | fortran-c 70 | python 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinxcontrib.bibtex 2 | sphinx-math-dollar 3 | -------------------------------------------------------------------------------- /examples/hfmm2d_example.f: -------------------------------------------------------------------------------- 1 | implicit none 2 | integer ns 3 | double precision, allocatable :: source(:,:) 4 | double complex, allocatable :: charge(:) 5 | double complex, allocatable :: pot(:) 6 | double complex, allocatable :: grad(:,:) 7 | 8 | double precision eps 9 | double complex eye,zk 10 | integer i,j,k,ier 11 | double precision hkrand,t1,t2,omp_get_wtime,thet 12 | 13 | 14 | data eye/(0.0d0,1.0d0)/ 15 | 16 | c 17 | cc initialize printing routine 18 | c 19 | call prini(6,13) 20 | write(*,*) 21 | write(*,*) 22 | write(*,*) "=================================" 23 | call prin2("This code is an example fortran driver*",i,0) 24 | call prin2("On output, the code prints sample pot,grad*",i,0) 25 | write(*,*) 26 | write(*,*) 27 | 28 | 29 | zk = 2.2d0 30 | zk = 3.1418 31 | zk = 4096*2*3.14 32 | 33 | ns = 1000000 34 | 35 | 36 | allocate(source(2,ns)) 37 | allocate(charge(ns)) 38 | allocate(pot(ns)) 39 | allocate(grad(2,ns)) 40 | 41 | 42 | eps = 0.51d-12 43 | 44 | write(*,*) "==========================================" 45 | 46 | c 47 | c 48 | c example demonstrating use of 49 | c source to source, charges, pot + gradient 50 | c 51 | 52 | 53 | 54 | c 55 | cc generate sources with distribution unif^2 56 | c 57 | c 58 | do i=1,ns 59 | source(1,i) = hkrand(0)**2 60 | source(2,i) = hkrand(0)**2 61 | 62 | thet = hkrand(0)*6.28 63 | source(1,i) = 0.5*cos(thet) 64 | source(2,i) = 0.5*sin(thet) 65 | 66 | source(1,i) = hkrand(0)-0.5d0 67 | source(2,i) = hkrand(0)-0.5d0 68 | 69 | charge(i) = hkrand(0) + eye*hkrand(0) 70 | 71 | pot(i) = 0 72 | grad(1,i) = 0 73 | grad(2,i) = 0 74 | enddo 75 | 76 | call cpu_time(t1) 77 | C$ t1 = omp_get_wtime() 78 | call hfmm2d_s_c_p(eps,zk,ns,source,charge, 79 | 1 pot,ier) 80 | call cpu_time(t2) 81 | C$ t2 = omp_get_wtime() 82 | call prin2('time taken=*',t2-t1,1) 83 | call prin2("pot at sources=*",pot,12) 84 | cc call prin2("grad at sources=*",grad,12) 85 | 86 | 87 | stop 88 | end 89 | c---------------------------------------------------------- 90 | c 91 | cc 92 | c 93 | c 94 | -------------------------------------------------------------------------------- /examples/hfmm2d_example.make: -------------------------------------------------------------------------------- 1 | OS = osx 2 | 3 | HOST = gcc 4 | #HOST = gcc-openmp 5 | #HOST = intel 6 | #HOST = intel-openmp 7 | 8 | PROJECT = int2-hfmm2d-example 9 | 10 | # FC - fortran compiler 11 | # FFLAGS - fortran compiler flags 12 | 13 | # This make file presumes that the static library is already created 14 | # and located at location given by 15 | # STATICLIB 16 | # 17 | # It also assumes that the static library is compiled using 18 | # the same compiler that you are using to run the make file with 19 | # 20 | # In case you wish to you use a different compiler, make sure to include 21 | # the cross compiled libraries. See fmm2d.readthedocs.io/install.html 22 | # for additional info 23 | 24 | ifeq ($(OS),osx) 25 | LDFMM = /usr/local/lib 26 | endif 27 | 28 | ifeq ($(OS),linux) 29 | LDFMM = ./../lib 30 | endif 31 | 32 | 33 | ifeq ($(HOST),gcc) 34 | FC=gfortran -L${LDFMM} 35 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 36 | endif 37 | 38 | ifeq ($(HOST),gcc-openmp) 39 | FC = gfortran -L${LDFMM} 40 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 41 | endif 42 | 43 | ifeq ($(HOST),intel) 44 | FC=ifort 45 | FFLAGS= -O3 -fPIC -march=native 46 | endif 47 | 48 | ifeq ($(HOST),intel-openmp) 49 | FC = ifort 50 | FFLAGS= -O3 -fPIC -march=native -qopenmp 51 | endif 52 | 53 | # Test objects 54 | TOBJS = $(COM)/hkrand.o $(COM)/dlaran.o 55 | 56 | .PHONY: all clean 57 | 58 | default: all 59 | 60 | 61 | OBJECTS = hfmm2d_example.o \ 62 | ../src/Common/hkrand.o \ 63 | ../src/Common/dlaran.o 64 | 65 | all: $(OBJECTS) 66 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) -lfmm2d 67 | ./$(PROJECT) 68 | 69 | 70 | # implicit rules for objects (note -o ensures writes to correct dir) 71 | %.o: %.f %.h 72 | $(FC) -c $(FFLAGS) $< -o $@ 73 | 74 | clean: 75 | rm -f $(OBJECTS) $(PROJECT) fort.13 76 | -------------------------------------------------------------------------------- /examples/hfmm2d_vec_example.f: -------------------------------------------------------------------------------- 1 | implicit none 2 | integer ns,nt,nd 3 | double precision, allocatable :: source(:,:),targ(:,:) 4 | double complex, allocatable :: charge(:,:),dipstr(:,:) 5 | real *8, allocatable :: dipvec(:,:,:) 6 | double complex, allocatable :: pot(:,:) 7 | double complex, allocatable :: pottarg(:,:) 8 | 9 | double precision eps 10 | double complex eye,zk 11 | integer i,j,k,idim,ier 12 | double precision hkrand,pi,thet,phi,t1,t2,omp_get_wtime 13 | 14 | 15 | data eye/(0.0d0,1.0d0)/ 16 | 17 | pi = 4.0d0*atan(1.0d0) 18 | 19 | c 20 | cc initialize printing routine 21 | c 22 | call prini(6,13) 23 | write(*,*) 24 | write(*,*) 25 | write(*,*) "=================================" 26 | call prin2("This code is an example fortran driver*",i,0) 27 | call prin2("On output, the code prints sample pot,pottarg*",i,0) 28 | write(*,*) 29 | write(*,*) 30 | 31 | zk = 2.2d0 32 | 33 | ns = 1600 34 | nt = 62500 35 | 36 | nd = 1 37 | 38 | allocate(source(2,ns)) 39 | allocate(targ(2,nt)) 40 | allocate(charge(nd,ns)) 41 | allocate(dipstr(nd,ns)) 42 | allocate(dipvec(nd,2,ns)) 43 | allocate(pot(nd,ns)) 44 | allocate(pottarg(nd,nt)) 45 | 46 | 47 | eps = 0.51d-6 48 | 49 | write(*,*) "==========================================" 50 | 51 | c 52 | c 53 | c example demonstrating use of 54 | c source to source+targ, charges+dipoles, pot 55 | c 56 | 57 | 58 | 59 | c 60 | cc generate sources uniformly on the sphere 61 | c 62 | c 63 | do i=1,ns 64 | thet = hkrand(0)*pi 65 | phi = hkrand(0)*2*pi 66 | source(1,i) = sin(thet)*cos(phi) 67 | source(2,i) = sin(thet)*sin(phi) 68 | 69 | do idim=1,nd 70 | charge(idim,i) = hkrand(0) + eye*hkrand(0) 71 | dipstr(idim,i) = hkrand(0) + eye*hkrand(0) 72 | dipvec(idim,1,i) = hkrand(0) 73 | dipvec(idim,2,i) = hkrand(0) 74 | pot(idim,i) = 0 75 | enddo 76 | enddo 77 | 78 | do i=1,nt 79 | targ(1,i) = -3.0d0 + hkrand(0)*6.0d0 80 | targ(2,i) = -3.0d0 + hkrand(0)*6.0d0 81 | 82 | do idim=1,nd 83 | pottarg(idim,i) = 0 84 | enddo 85 | enddo 86 | 87 | call cpu_time(t1) 88 | C$ t1 = omp_get_wtime() 89 | 90 | call hfmm2d_t_cd_p(eps,zk,ns,source,charge, 91 | 1 dipstr,dipvec,nt,targ,pottarg,ier) 92 | 93 | call cpu_time(t2) 94 | C$ t2 = omp_get_wtime() 95 | 96 | call prin2('time taken=*',t2-t1,1) 97 | call prin2("potential at targets=*",pottarg,12) 98 | 99 | 100 | stop 101 | end 102 | c---------------------------------------------------------- 103 | c 104 | cc 105 | c 106 | c 107 | -------------------------------------------------------------------------------- /examples/hfmm2d_vec_example.make: -------------------------------------------------------------------------------- 1 | OS = osx 2 | 3 | #HOST = gcc 4 | HOST = gcc-openmp 5 | #HOST = intel 6 | #HOST = intel-openmp 7 | 8 | PROJECT = int2-hfmm2d-vec-example 9 | 10 | # FC - fortran compiler 11 | # FFLAGS - fortran compiler flags 12 | 13 | # This make file presumes that the static library is already created 14 | # and located at location given by 15 | # STATICLIB 16 | # 17 | # It also assumes that the static library is compiled using 18 | # the same compiler that you are using to run the make file with 19 | # 20 | # In case you wish to you use a different compiler, make sure to include 21 | # the cross compiled libraries. See fmm2d.readthedocs.io/install.html 22 | # for additional info 23 | 24 | ifeq ($(OS),osx) 25 | LDFMM = /usr/local/lib 26 | endif 27 | 28 | ifeq ($(OS),linux) 29 | LDFMM = ./../lib 30 | endif 31 | 32 | 33 | ifeq ($(HOST),gcc) 34 | FC=gfortran -L${LDFMM} 35 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 36 | endif 37 | 38 | ifeq ($(HOST),gcc-openmp) 39 | FC = gfortran -L${LDFMM} 40 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 41 | endif 42 | 43 | ifeq ($(HOST),intel) 44 | FC=ifort -L${LDFMM} 45 | FFLAGS= -O3 -fPIC -march=native 46 | endif 47 | 48 | ifeq ($(HOST),intel-openmp) 49 | FC = ifort -L${LDFMM} 50 | FFLAGS= -O3 -fPIC -march=native -qopenmp 51 | endif 52 | 53 | # Test objects 54 | TOBJS = $(COM)/hkrand.o $(COM)/dlaran.o 55 | 56 | .PHONY: all clean 57 | 58 | default: all 59 | 60 | 61 | OBJECTS = hfmm2d_vec_example.o \ 62 | ../src/Common/hkrand.o \ 63 | ../src/Common/dlaran.o 64 | 65 | all: $(OBJECTS) 66 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) -lfmm2d 67 | ./$(PROJECT) 68 | 69 | 70 | # implicit rules for objects (note -o ensures writes to correct dir) 71 | %.o: %.f %.h 72 | $(FC) -c $(FFLAGS) $< -o $@ 73 | 74 | 75 | 76 | clean: 77 | rm -f $(OBJECTS) $(PROJECT) fort.13 78 | -------------------------------------------------------------------------------- /fmm2d_manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/fmm2d/550dae5b77b1e006c8ffae37fc832f8c2b536871/fmm2d_manual.pdf -------------------------------------------------------------------------------- /include/fmm2d/helmholtz.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | void hfmm2d_s_c_p(double eps, double _Complex zk, int64_t ns, double const *sources, double _Complex const *charge, double _Complex *pot, int64_t *ier); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /lib-static/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/fmm2d/550dae5b77b1e006c8ffae37fc832f8c2b536871/lib-static/.keep -------------------------------------------------------------------------------- /lib/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatironinstitute/fmm2d/550dae5b77b1e006c8ffae37fc832f8c2b536871/lib/.keep -------------------------------------------------------------------------------- /make.inc.icc: -------------------------------------------------------------------------------- 1 | CC=icc 2 | CXX=icpc 3 | FC=ifort 4 | FFLAGS= -fPIC -O3 -march=native -funroll-loops -mkl -w 5 | LIBS=-lm 6 | CLIBS = -lm -ldl -lifcore 7 | 8 | ifeq ($(FAST_KER),ON) 9 | 10 | CXXFLAGS = $(FFLAGS) 11 | CXXFLAGS += -std=c++11 -DSCTL_HAVE_SVML -DSCTL_PROFILE=-1 12 | LIBS += -cxxlib 13 | endif 14 | 15 | OMPLIBS = 16 | OMPFLAGS = -qopenmp 17 | -------------------------------------------------------------------------------- /make.inc.macos.gnu: -------------------------------------------------------------------------------- 1 | # makefile overrides 2 | # OS: macOS 3 | # Compiler: gfortran X.X/Clang 4 | # OpenMP: enabled 5 | # 6 | 7 | CC=gcc 8 | CXX=g++ 9 | FC=gfortran 10 | 11 | ifeq ($(PREFIX),) 12 | FMM_INSTALL_DIR=/usr/local/lib 13 | endif 14 | 15 | 16 | CFLAGS += -I src 17 | 18 | # OpenMP with gcc on OSX needs the following 19 | OMPFLAGS = -fopenmp 20 | OMPLIBS = -lgomp 21 | 22 | # MATLAB interface: 23 | FDIR=$$(dirname `gfortran --print-file-name libgfortran.dylib`) 24 | MFLAGS +=-L${FDIR} 25 | MEX = $(shell ls -d /Applications/MATLAB_R* | sort | tail -1)/bin/mex 26 | 27 | 28 | -------------------------------------------------------------------------------- /make.inc.macos.gnu.x86-64: -------------------------------------------------------------------------------- 1 | # makefile overrides 2 | # OS: macOS 3 | # Compiler: gfortran 9.X 4 | # OpenMP: enabled 5 | # 6 | 7 | CC=gcc 8 | CXX=g++ 9 | FC=gfortran 10 | 11 | FFLAGS= -fPIC -O3 -march=x86-64 -funroll-loops -std=legacy -w 12 | 13 | ifeq ($(PREFIX),) 14 | FMM_INSTALL_DIR=/usr/local/lib 15 | endif 16 | 17 | 18 | CFLAGS += -I src 19 | 20 | # OpenMP with gcc on OSX needs the following 21 | OMPFLAGS = -fopenmp 22 | OMPLIBS = -lgomp 23 | 24 | # MATLAB interface: 25 | FDIR=$$(dirname `gfortran --print-file-name libgfortran.dylib`) 26 | MFLAGS += -L${FDIR} 27 | MEX = $(shell ls -d /Applications/MATLAB_R20**.app)/bin/mex 28 | #LIBS = -lm -lstdc++.6 29 | #MEXLIBS= -lm -lstdc++.6 -lgfortran -ldl 30 | 31 | 32 | -------------------------------------------------------------------------------- /make.inc.macos.intel: -------------------------------------------------------------------------------- 1 | # 2 | # This config tested under Intel Parallel Studio XE Composer Edition 3 | # for macOS Version 2020 Update 1, released April 2020 4 | # This release is only tested with Xcode 13.1.1 5 | # 6 | 7 | CC=icc 8 | CXX=icpc 9 | FC=ifort 10 | 11 | FFLAGS= -fPIC -O3 -march=native -funroll-loops -mkl -std=legacy -w 12 | LIBS= 13 | #CLIBS = -lm -ldl -lifcore 14 | CLIBS = -lm -ldl 15 | 16 | ifeq ($(PREFIX),) 17 | FMM_INSTALL_DIR=/usr/local/lib 18 | endif 19 | 20 | ifeq ($(FAST_KER),ON) 21 | CXXFLAGS = $(FFLAGS) 22 | CXXFLAGS += -std=c++11 -DSCTL_HAVE_SVML -DSCTL_PROFILE=-1 23 | LIBS += -cxxlib 24 | endif 25 | 26 | # used to be needed on the CXXFLAGS for weird intel compiler problems 27 | # -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk 28 | 29 | OMPFLAGS = -qopenmp 30 | OMPLIBS = -qopenmp 31 | 32 | # MATLAB interface: 33 | FDIR=$$(dirname `gfortran --print-file-name libgfortran.dylib`) 34 | MFLAGS +=-L${FDIR} 35 | MEX = $(shell ls -d /Applications/MATLAB_R* | sort | tail -1)/bin/mex 36 | 37 | 38 | -------------------------------------------------------------------------------- /make.inc.macos.nag: -------------------------------------------------------------------------------- 1 | # make.inc for NAG Fortran compiler 2 | # Online documentation: https://www.nag.com/nagware/np/r71_doc/manual/compiler_2_4.html#OPTIONS 3 | 4 | FC=nagfor 5 | 6 | # The path of libraries by NAG compiler 7 | LIB_NAG = /usr/local/lib/NAG_Fortran 8 | 9 | # Brief descriptions of specified options below: 10 | # -PIC: produce position-independent code 11 | # -O2: optimization at a normal level 12 | # -Ounroll=2: the depth of loo-unrolling 13 | # -f90_sign: use the Fortran 77/90 version of the SIGN intrinsic instead of the Fortran 95 one 14 | # -dcfuns: enable recognition of non-standard double precision complex intrinsic functions. 15 | # -dusty: allows the compilation and execution of legacy software. 16 | # -w=x77: suppresses extension warnings for obsolete but common extensions to Fortran 77. 17 | # -w=unreffed: suppresses warning messages about variables set but never referenced. 18 | # -w=unused: suppresses warning messages about unused entities. 19 | # -ieee=full: set the mode of IEEE arithmetic operation according to full mode. 20 | 21 | # Main compile command for NAG Fortran compiler 22 | FFLAGS = -PIC -O2 -Ounroll=1 -f90_sign -dcfuns -dusty -w=obs -w=x77 -w=unreffed -w=unused -ieee=full 23 | 24 | # Flags overwritten in makefile 25 | OMPFLAGS = -openmp 26 | # OMPLIBS = -lf71omp64 -L$(LIB_NAG) 27 | OMPLIBS = -lf71omp64 -lf71rts -L$(LIB_NAG) 28 | LIBS = -lf71rts -L$(LIB_NAG) 29 | CLIBS = -lm -ldl -L$(LIB_NAG) 30 | FFLAGS_DYN = -PIC 31 | -------------------------------------------------------------------------------- /make.inc.macos_arm64.gnu: -------------------------------------------------------------------------------- 1 | # makefile overrides 2 | # OS: macOS 3 | # Compiler: gfortran X.X/Clang 4 | # OpenMP: enabled 5 | # 6 | 7 | CC=gcc 8 | CXX=g++ 9 | FC=gfortran 10 | 11 | FFLAGS= -fPIC -O3 -arch arm64 -std=legacy -w -mno-outline-atomics 12 | FFLAGS_DYN= -shared -fPIC 13 | CFLAGS= -fPIC -O3 -arch arm64 -std=c99 14 | CXXFLAGS= -std=c++11 -DSCTL_PROFILE=-1 -fPIC -O3 -arch arm64 15 | 16 | 17 | ifeq ($(PREFIX),) 18 | FMM_INSTALL_DIR=/usr/local/lib 19 | endif 20 | 21 | 22 | CFLAGS += -I src 23 | 24 | # OpenMP with gcc on OSX needs the following 25 | OMPFLAGS = -fopenmp 26 | OMPLIBS = -lgomp 27 | 28 | # MATLAB interface: 29 | FDIR=$$(dirname `gfortran --print-file-name libgfortran.dylib`) 30 | MFLAGS +=-L${FDIR} 31 | MEX = $(shell ls -d /Applications/MATLAB_R* | sort | tail -1)/bin/mex 32 | 33 | 34 | -------------------------------------------------------------------------------- /make.inc.manylinux: -------------------------------------------------------------------------------- 1 | PYTHON=python3 2 | FFLAGS= -fPIC -O3 -funroll-loops -march=x86-64 -mtune=generic -msse4 -fcx-limited-range -std=legacy -w 3 | -------------------------------------------------------------------------------- /make.inc.windows.mingw: -------------------------------------------------------------------------------- 1 | # makefile overrides 2 | # OS: windows 3 | # Compiler: mingw 4 | # OpenMP: default enabled unless specified 5 | # 6 | 7 | FFLAGS= -fPIC -O3 -funroll-loops -std=legacy 8 | 9 | DYNAMICLIB = $(LIBNAME).dll 10 | LIMPLIB = $(LIBNAME)_dll.lib 11 | 12 | LLINKLIB = -llibfmm2d_dll 13 | 14 | DYLIBS += -Wl,--out-implib,$(LIMPLIB) 15 | 16 | ifeq ($(PREFIX),) 17 | FMM_INSTALL_DIR=C:\lib 18 | endif 19 | 20 | 21 | MINGW_LPATH=C:/mingw-w64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0 22 | MEXLIBS = -lmex -lmat -lmx -lgfortran -lquadmath -L${MINGW_LPATH} 23 | -------------------------------------------------------------------------------- /makehelm: -------------------------------------------------------------------------------- 1 | # Makefile for FMM2d 2 | # # This is the only makefile; there are no makefiles in subdirectories. 3 | # Users should not need to edit this makefile (doing so would make it 4 | # hard to stay up to date with repo version). Rather in order to 5 | # change OS/environment-specific compilers and flags, create 6 | # the file make.inc, which overrides the defaults below (which are 7 | # for ubunutu linux/gcc system). 8 | 9 | 10 | # compiler, and linking from C, fortran 11 | CC=gcc 12 | CXX=g++ 13 | FC=gfortran 14 | ###export OMP_NUM_THREADS=1 15 | 16 | # set compiler flags for c and fortran 17 | FFLAGS= -fPIC -O3 -march=native -funroll-loops -std=legacy -w 18 | CFLAGS= -std=c99 19 | CFLAGS+= $(FFLAGS) 20 | CXXFLAGS= -std=c++11 -DSCTL_PROFILE=-1 21 | CXXFLAGS+=$(FFLAGS) 22 | 23 | # set linking libraries 24 | CLIBS = -lgfortran -lm -ldl 25 | LIBS = -lm 26 | 27 | # extra flags for multithreaded: C/Fortran, MATLAB 28 | OMPFLAGS =-fopenmp 29 | OMPLIBS =-lgomp 30 | 31 | # Python Exetucable 32 | PYTHON=python 33 | 34 | 35 | # flags for MATLAB MEX compilation.. 36 | MFLAGS=-compatibleArrayDims -DMWF77_UNDERSCORE1 37 | MWFLAGS=-c99complex 38 | MOMPFLAGS = -D_OPENMP 39 | 40 | # location of MATLAB's mex compiler 41 | MEX=mex 42 | 43 | # For experts, location of Mwrap executable 44 | MWRAP=../../mwrap/mwrap 45 | MEXLIBS=-lm -lstdc++ -ldl -lgfortran 46 | 47 | FMM_INSTALL_DIR=$(PREFIX) 48 | ifeq ($(PREFIX),) 49 | FMM_INSTALL_DIR = ${HOME}/lib 50 | endif 51 | 52 | DYLIBS = $(LIBS) 53 | 54 | LIBNAME=libfmm2d 55 | DYNAMICLIB = $(LIBNAME).so 56 | STATICLIB = $(LIBNAME).a 57 | LIMPLIB = $(DYNAMICLIB) 58 | 59 | LLINKLIB = -lfmm2d 60 | 61 | 62 | 63 | # For your OS, override the above by placing make variables in make.inc 64 | -include make.inc 65 | 66 | # additional compile flags for FAST_KER 67 | ifeq ($(FAST_KER),ON) 68 | LIBS += -lstdc++ 69 | DYLIBS += -lstdc++ 70 | CLIBS += -lstdc++ 71 | FFLAGS += -lstdc++ 72 | CFLAGS += -lstdc++ 73 | OMP = ON 74 | endif 75 | 76 | 77 | # multi-threaded libs & flags needed 78 | ifneq ($(OMP),OFF) 79 | 80 | CFLAGS += $(OMPFLAGS) 81 | FFLAGS += $(OMPFLAGS) 82 | MFLAGS += $(MOMPFLAGS) 83 | LIBS += $(OMPLIBS) 84 | DYLIBS += $(OMPLIBS) 85 | MEXLIBS += $(OMPLIBS) 86 | 87 | endif 88 | 89 | 90 | # vectorized kernel directory 91 | SRCDIR = ./vec-kernels/src 92 | INCDIR = ./vec-kernels/include 93 | LIBDIR = lib-static 94 | 95 | # objects to compile 96 | # 97 | # Common objects 98 | COM = src/common 99 | COMOBJS = $(COM)/cdjseval2d.o $(COM)/dfft.o \ 100 | $(COM)/fmmcommon2d.o $(COM)/next235.o $(COM)/prini.o \ 101 | $(COM)/tree_routs2d.o $(COM)/pts_tree2d.o \ 102 | $(COM)/cumsum.o $(COM)/hank103.o 103 | 104 | # Helmholtz objects 105 | HELM = src/helmholtz 106 | HOBJS = $(HELM)/h2dcommon.o $(HELM)/h2dterms.o \ 107 | $(HELM)/helmrouts2d.o $(HELM)/hfmm2dnew.o $(HELM)/hfmm2dwrap.o \ 108 | $(HELM)/wideband2dnew.o $(HELM)/hndiv2d.o 109 | 110 | 111 | ifneq ($(FAST_KER),ON) 112 | HOBJS += $(HELM)/helmkernels2d.o 113 | endif 114 | 115 | ifeq ($(FAST_KER),ON) 116 | HOBJS += $(HELM)/helmkernels2d.o 117 | endif 118 | 119 | # Test objects 120 | TOBJS = $(COM)/hkrand.o $(COM)/dlaran.o 121 | 122 | OBJS = $(COMOBJS) $(HOBJS) 123 | 124 | .PHONY: usage install lib test all python 125 | 126 | default: usage 127 | 128 | cxxkernel: $(CXXOBJ) 129 | 130 | $(SRCDIR)/libkernels.o: $(SRCDIR)/libkernels.cpp 131 | $(CXX) $(CXXFLAGS) -I$(INCDIR) -c $^ -o $@ 132 | 133 | usage: 134 | @echo "Makefile for FMM2d. Specify what to make:" 135 | @echo " make install - compile and install the main library" 136 | @echo " make install PREFIX=(INSTALL_DIR) - compile and install the main library at custom location given by PREFIX" 137 | @echo " make lib - compile the main library (in lib/ and lib-static/)" 138 | @echo " make test - compile and run validation tests (will take a couple of mins)" 139 | @echo " make objclean - removal all object files, preserving lib & MEX" 140 | @echo " make clean - also remove lib, MEX, py, and demo executables" 141 | @echo "For faster (multicore) making, append the flag -j" 142 | @echo " 'make [task] OMP=OFF' for single-threaded" 143 | 144 | 145 | # implicit rules for objects (note -o ensures writes to correct dir) 146 | %.o: %.cpp %.h 147 | $(CXX) -c $(CXXFLAGS) $< -o $@ 148 | %.o: %.c %.h 149 | $(CC) -c $(CFLAGS) $< -o $@ 150 | %.o: %.f %.h 151 | $(FC) -c $(FFLAGS) $< -o $@ 152 | %.o: %.f90 153 | $(FC) -c $(FFLAGS) $< -o $@ 154 | 155 | # build the library... 156 | lib: $(STATICLIB) $(DYNAMICLIB) 157 | ifneq ($(OMP),OFF) 158 | @echo "$(STATICLIB) and $(DYNAMICLIB) built, multithread versions" 159 | else 160 | @echo "$(STATICLIB) and $(DYNAMICLIB) built, single-threaded versions" 161 | endif 162 | 163 | 164 | install: $(STATICLIB) $(DYNAMICLIB) 165 | echo $(FMM_INSTALL_DIR) 166 | mkdir -p $(FMM_INSTALL_DIR) 167 | cp -f lib/$(DYNAMICLIB) $(FMM_INSTALL_DIR)/ 168 | cp -f lib-static/$(STATICLIB) $(FMM_INSTALL_DIR)/ 169 | [ ! -f lib/$(LIMPLIB) ] || cp lib/$(LIMPLIB) $(FMM_INSTALL_DIR)/ 170 | @echo "Make sure to include " $(FMM_INSTALL_DIR) " in the appropriate path variable" 171 | @echo " LD_LIBRARY_PATH on Linux" 172 | @echo " PATH on windows" 173 | @echo " DYLD_LIBRARY_PATH on Mac OSX (not needed if default installation directory is used" 174 | @echo " " 175 | @echo "In order to link against the dynamic library, use -L"$(FMM_INSTALL_DIR) " -lfmm2d" 176 | 177 | 178 | $(STATICLIB): $(OBJS) 179 | ar rcs $(STATICLIB) $(OBJS) 180 | mv $(STATICLIB) lib-static/ 181 | $(DYNAMICLIB): $(OBJS) 182 | $(FC) -shared -fPIC $(OBJS) -o $(DYNAMICLIB) $(DYLIBS) 183 | mv $(DYNAMICLIB) lib/ 184 | [ ! -f $(LIMPLIB) ] || mv $(LIMPLIB) lib/ 185 | 186 | 187 | # testing routines 188 | # 189 | test: $(STATICLIB) $(TOBJS) test/hfmm2d 190 | (cd test/helmholtz; ./run_helmtest2.sh) 191 | cat print_testreshelm.txt 192 | rm print_testreshelm.txt 193 | 194 | test/hfmm2d: 195 | $(FC) $(FFLAGS) test/helmholtz/test_hfmm2d.f $(TOBJS) $(COMOBJS) $(HOBJS) -o test/helmholtz/int2-test-hfmm2d $(LIBS) 196 | 197 | #python 198 | python: $(STATICLIB) 199 | cd python && \ 200 | FMM_FLIBS='$(LIBS) $(OMPFLAGS)' $(PYTHON) -m pip install -e . 201 | 202 | # matlab.. 203 | MWRAPFILE = fmm2d 204 | GATEWAY = $(MWRAPFILE) 205 | 206 | matlab: $(STATICLIB) matlab/$(GATEWAY).c 207 | $(MEX) matlab/$(GATEWAY).c lib-static/$(STATICLIB) $(MFLAGS) \ 208 | -output matlab/fmm2d $(MEXLIBS) 209 | 210 | 211 | mex: $(STATICLIB) 212 | cd matlab; $(MWRAP) $(MWFLAGS) -list -mex $(GATEWAY) -mb $(MWRAPFILE).mw;\ 213 | $(MWRAP) $(MWFLAGS) -mex $(GATEWAY) -c $(GATEWAY).c $(MWRAPFILE).mw;\ 214 | $(MEX) $(GATEWAY).c ../lib-static/$(STATICLIB) $(MFLAGS) -output $(MWRAPFILE) \ 215 | $(MEXLIBS); \ 216 | 217 | clean: objclean 218 | rm -f lib-static/*.a lib/*.so lib/*.dll lib/*.lib 219 | rm -f test/laplace/int2-* 220 | rm -f test/helmholtz/int2-* 221 | 222 | objclean: 223 | rm -f $(OBJS) $(COBJS) $(TOBJS) 224 | rm -f test/laplace/*.o test/helmholtz/*.o 225 | -------------------------------------------------------------------------------- /matlab/c2ddir.m: -------------------------------------------------------------------------------- 1 | function [U] = c2ddir(srcinfo,targ,pgt) 2 | % 3 | % This subroutine computes the N-body Laplace 4 | % interactions and its gradients in two dimensions where 5 | % the interaction kernel is given by $\log(r)$ 6 | % 7 | % u(x) = \frac{i}{4}\sum_{j=1}^{N} c_{j} \log(\|x-x_{j}\|) - d_{j} v_{j} 8 | % \cdot \nabla \left( \log(\|x-x_{j} \|) \right) 9 | % 10 | % where $c_{j}$ are the charge densities, $d_{j}$ are the dipole 11 | % densities, 12 | % $v_{j}$ are the dipole orientation vectors, and 13 | % $x_{j}$ are the source locations. 14 | % When $\|x-x_{j}\| <= L \eps_{m}$, with $L$ being the size of the bounding 15 | % box of sources and targets and $\eps_{m}$ being machine precision, 16 | % the term corresponding to $x_{j}$ is dropped 17 | % from the sum. 18 | % 19 | % 20 | % The sum is evaluated directly - (slow code for testing) 21 | % 22 | % 23 | % Note: Here gradients and hessians are complex gradients and hessians 24 | % as opposed to cartesian gradients and hessians. Also, dipvec is dropped 25 | % 26 | % Args: 27 | % 28 | % - srcinfo: structure 29 | % structure containing sourceinfo 30 | % 31 | % * srcinfo.sources: double(2,n) 32 | % source locations, $x_{j}$ 33 | % * srcinfo.nd: integer 34 | % number of charge/dipole vectors (optional, 35 | % default - nd = 1) 36 | % * srcinfo.charges: complex(nd,n) 37 | % charge densities, $c_{j}$ (optional, 38 | % default - term corresponding to charges dropped) 39 | % * srcinfo.dipstr: complex(nd,n) 40 | % dipole densities, $d_{j}$ (optional, 41 | % default - term corresponding to dipoles dropped) 42 | % 43 | % - targ: double(3,nt) 44 | % target locations, $t_{i}$ 45 | % - pgt: integer 46 | % | target eval flag 47 | % | potential at targets evaluated if pgt = 1 48 | % | potential and gradient at targets evaluated if pgt=2 49 | % 50 | % Returns: 51 | % 52 | % - U.pottarg: potential at target locations, if requested, $u(t_{i})$ 53 | % - U.gradtarg: gradient at target locations, if requested, $d/dz u(t_{i})$ 54 | % - U.hesstarg: hessian at target locations, if requested, $d/dz d/dz u(t_{i})$ 55 | 56 | 57 | thresh = 1e-15; 58 | sources = srcinfo.sources; 59 | [m,ns] = size(sources); 60 | assert(m==2,'The first dimension of sources must be 2'); 61 | if(~isfield(srcinfo,'nd')) 62 | nd = 1; 63 | end 64 | if(isfield(srcinfo,'nd')) 65 | nd = srcinfo.nd; 66 | end 67 | 68 | 69 | pottarg = complex(zeros(nd,1)); 70 | gradtarg = complex(zeros(nd,1)); 71 | hesstarg = complex(zeros(nd,1)); 72 | [m,nt] = size(targ); 73 | assert(m==2,'First dimension of targets must be 2'); 74 | if(pgt >=1), pottarg = complex(zeros(nd,nt)); end; 75 | if(pgt >= 2), gradtarg = complex(zeros(nd,nt)); end; 76 | if(pgt == 3), hesstarg = complex(zeros(nd,nt)); end; 77 | 78 | if(pgt ==0), disp('Nothing to compute, set pgt to 1,2 or 3'); return; end; 79 | 80 | if(isfield(srcinfo,'charges')) 81 | ifcharge = 1; 82 | charges = srcinfo.charges; 83 | if(nd==1), assert(length(charges)==ns,'Charges must be same length as second dimension of sources'); end; 84 | if(nd>1), [a,b] = size(charges); assert(a==nd && b==ns,'Charges must be of shape [nd,ns] where nd is the number of densities, and ns is the number of sources'); end; 85 | else 86 | ifcharge = 0; 87 | charges = complex(zeros(nd,1)); 88 | end 89 | 90 | if(isfield(srcinfo,'dipstr')) 91 | ifdipole = 1; 92 | dipstr = srcinfo.dipstr; 93 | if(nd==1), assert(length(dipstr)==ns,'Dipole strength must be same length as second dimension of sources'); end; 94 | if(nd>1), [a,b] = size(dipstr); assert(a==nd && b==ns,'Dipstr must be of shape [nd,ns] where nd is the number of densities, and ns is the number of sources'); end; 95 | else 96 | ifdipole = 0; 97 | dipstr = complex(zeros(nd,ns)); 98 | end 99 | 100 | 101 | if(pgt == 1) 102 | if(ifcharge==1 && ifdipole == 0) 103 | mex_id_ = 'c2d_directcp(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], i double[x])'; 104 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, 1); 105 | end 106 | if(ifcharge==0 && ifdipole == 1) 107 | mex_id_ = 'c2d_directdp(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], i double[x])'; 108 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, 1); 109 | end 110 | if(ifcharge==1 && ifdipole == 1) 111 | mex_id_ = 'c2d_directcdp(i int[x], i double[xx], i int[x], i dcomplex[xx], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], i double[x])'; 112 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, 2, nt, 1, nd, nt, 1); 113 | end 114 | U.pottarg = pottarg; 115 | end 116 | if(pgt == 2) 117 | if(ifcharge==1 && ifdipole == 0) 118 | mex_id_ = 'c2d_directcg(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], i double[x])'; 119 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, nd, nt, 1); 120 | end 121 | if(ifcharge==0 && ifdipole == 1) 122 | mex_id_ = 'c2d_directdg(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], i double[x])'; 123 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, nd, nt, 1); 124 | end 125 | if(ifcharge==1 && ifdipole == 1) 126 | mex_id_ = 'c2d_directcdg(i int[x], i double[xx], i int[x], i dcomplex[xx], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], i double[x])'; 127 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, 2, nt, 1, nd, nt, nd, nt, 1); 128 | end 129 | U.pottarg = pottarg; 130 | U.gradtarg = squeeze(reshape(gradtarg,[nd,nt])); 131 | end 132 | if(pgt == 3) 133 | if(ifcharge==1 && ifdipole == 0) 134 | mex_id_ = 'c2d_directch(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], io dcomplex[xx], i double[x])'; 135 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, nd, nt, nd, nt, 1); 136 | end 137 | if(ifcharge==0 && ifdipole == 1) 138 | mex_id_ = 'c2d_directdh(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], io dcomplex[xx], i double[x])'; 139 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, nd, nt, nd, nt, 1); 140 | end 141 | if(ifcharge==1 && ifdipole == 1) 142 | mex_id_ = 'c2d_directcdh(i int[x], i double[xx], i int[x], i dcomplex[xx], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], io dcomplex[xx], i double[x])'; 143 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, 2, nt, 1, nd, nt, nd, nt, nd, nt, 1); 144 | end 145 | U.pottarg = pottarg; 146 | U.gradtarg = squeeze(reshape(gradtarg,[nd,nt])); 147 | U.hesstarg = squeeze(reshape(hesstarg,[nd,nt])); 148 | end 149 | end 150 | % 151 | % 152 | % --------------------------------------------------------------------- 153 | -------------------------------------------------------------------------------- /matlab/l2ddir.m: -------------------------------------------------------------------------------- 1 | function [U] = l2ddir(srcinfo,targ,pgt) 2 | % 3 | % This subroutine computes the N-body Laplace 4 | % interactions and its gradients in two dimensions where 5 | % the interaction kernel is given by $\log(r)$ 6 | % 7 | % u(x) = \frac{i}{4}\sum_{j=1}^{N} c_{j} \log(\|x-x_{j}\|) - d_{j} v_{j} 8 | % \cdot \nabla \left( \log(\|x-x_{j} \|) \right) 9 | % 10 | % where $c_{j}$ are the charge densities, $d_{j}$ are the dipole 11 | % densities, 12 | % $v_{j}$ are the dipole orientation vectors, and 13 | % $x_{j}$ are the source locations. 14 | % When $\|x-x_{j}\| <= L \eps_{m}$, with $L$ being the size of the bounding 15 | % box of sources and targets and $\eps_{m}$ being machine precision, 16 | % the term corresponding to $x_{j}$ is dropped 17 | % from the sum. 18 | % 19 | % 20 | % The sum is evaluated directly - (slow code for testing) 21 | % 22 | % Args: 23 | % 24 | % - srcinfo: structure 25 | % structure containing sourceinfo 26 | % 27 | % * srcinfo.sources: double(2,n) 28 | % source locations, $x_{j}$ 29 | % * srcinfo.nd: integer 30 | % number of charge/dipole vectors (optional, 31 | % default - nd = 1) 32 | % * srcinfo.charges: complex(nd,n) 33 | % charge densities, $c_{j}$ (optional, 34 | % default - term corresponding to charges dropped) 35 | % * srcinfo.dipstr: complex(nd,n) 36 | % dipole densities, $d_{j}$ (optional, 37 | % default - term corresponding to dipoles dropped) 38 | % * srcinfo.dipvec: double(nd,2,n) 39 | % dipole orientation vectors, $v_{j}$ (optional 40 | % default - term corresponding to dipoles dropped) 41 | % 42 | % - targ: double(3,nt) 43 | % target locations, $t_{i}$ 44 | % - pgt: integer 45 | % | target eval flag 46 | % | potential at targets evaluated if pgt = 1 47 | % | potential and gradient at targets evaluated if pgt=2 48 | % 49 | % Returns: 50 | % 51 | % - U.pottarg: potential at target locations, if requested, $u(t_{i})$ 52 | % - U.gradtarg: gradient at target locations, if requested, $\nabla u(t_{i})$ 53 | % - U.hesstarg: hessian at target locations, if requested, $\nabla \nabla u(t_{i})$ 54 | 55 | 56 | thresh = 1e-15; 57 | sources = srcinfo.sources; 58 | [m,ns] = size(sources); 59 | assert(m==2,'The first dimension of sources must be 2'); 60 | if(~isfield(srcinfo,'nd')) 61 | nd = 1; 62 | end 63 | if(isfield(srcinfo,'nd')) 64 | nd = srcinfo.nd; 65 | end 66 | 67 | 68 | pottarg = complex(zeros(nd,1)); 69 | gradtarg = complex(zeros(nd*2,1)); 70 | hesstarg = complex(zeros(nd*3,1)); 71 | [m,nt] = size(targ); 72 | assert(m==2,'First dimension of targets must be 2'); 73 | if(pgt >=1), pottarg = complex(zeros(nd,nt)); end; 74 | if(pgt >= 2), gradtarg = complex(zeros(nd*2,nt)); end; 75 | if(pgt == 3), hesstarg = complex(zeros(nd*3,nt)); end; 76 | 77 | if(pgt ==0), disp('Nothing to compute, set pgt to 1,2 or 3'); return; end; 78 | 79 | if(isfield(srcinfo,'charges')) 80 | ifcharge = 1; 81 | charges = srcinfo.charges; 82 | if(nd==1), assert(length(charges)==ns,'Charges must be same length as second dimension of sources'); end; 83 | if(nd>1), [a,b] = size(charges); assert(a==nd && b==ns,'Charges must be of shape [nd,ns] where nd is the number of densities, and ns is the number of sources'); end; 84 | else 85 | ifcharge = 0; 86 | charges = complex(zeros(nd,1)); 87 | end 88 | 89 | if(isfield(srcinfo,'dipstr') || isfield(srcinfo,'dipvec')) 90 | ifdipole = 1; 91 | dipstr = srcinfo.dipstr; 92 | if(nd==1), assert(length(dipstr)==ns,'Dipole strength must be same length as second dimension of sources'); end; 93 | if(nd>1), [a,b] = size(dipstr); assert(a==nd && b==ns,'Dipstr must be of shape [nd,ns] where nd is the number of densities, and ns is the number of sources'); end; 94 | dipvec = srcinfo.dipvec; 95 | if(nd == 1), [a,b] = size(squeeze(dipvec)); assert(a==2 && b==ns,'Dipvec must be of shape[2,ns], where ns is the number of sources'); end; 96 | if(nd>1), [a,b,c] = size(dipvec); assert(a==nd && b==2 && c==ns, 'Dipvec must be of shape[nd,2,ns], where nd is number of densities, and ns is the number of sources'); end; 97 | dipvec = reshape(dipvec,[2*nd,ns]); 98 | else 99 | ifdipole = 0; 100 | dipvec = zeros(nd*2,ns); 101 | dipstr = complex(zeros(nd,ns)); 102 | end 103 | 104 | nd2 = 2*nd; 105 | nd3 = 3*nd; 106 | 107 | if(pgt == 1) 108 | if(ifcharge==1 && ifdipole == 0) 109 | mex_id_ = 'l2d_directcp(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], i double[x])'; 110 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, 1); 111 | end 112 | if(ifcharge==0 && ifdipole == 1) 113 | mex_id_ = 'l2d_directdp(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i double[xx], i int[x], io dcomplex[xx], i double[x])'; 114 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, dipvec, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, nd2, ns, 2, nt, 1, nd, nt, 1); 115 | end 116 | if(ifcharge==1 && ifdipole == 1) 117 | mex_id_ = 'l2d_directcdp(i int[x], i double[xx], i int[x], i dcomplex[xx], i dcomplex[xx], i double[xx], i double[xx], i int[x], io dcomplex[xx], i double[x])'; 118 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, dipvec, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, nd2, ns, 2, nt, 1, nd, nt, 1); 119 | end 120 | U.pottarg = pottarg; 121 | end 122 | if(pgt == 2) 123 | if(ifcharge==1 && ifdipole == 0) 124 | mex_id_ = 'l2d_directcg(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], i double[x])'; 125 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, nd2, nt, 1); 126 | end 127 | if(ifcharge==0 && ifdipole == 1) 128 | mex_id_ = 'l2d_directdg(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], i double[x])'; 129 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, dipvec, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, nd2, ns, 2, nt, 1, nd, nt, nd2, nt, 1); 130 | end 131 | if(ifcharge==1 && ifdipole == 1) 132 | mex_id_ = 'l2d_directcdg(i int[x], i double[xx], i int[x], i dcomplex[xx], i dcomplex[xx], i double[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], i double[x])'; 133 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, dipvec, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, nd2, ns, 2, nt, 1, nd, nt, nd2, nt, 1); 134 | end 135 | U.pottarg = pottarg; 136 | U.gradtarg = squeeze(reshape(gradtarg,[nd,2,nt])); 137 | end 138 | if(pgt == 3) 139 | if(ifcharge==1 && ifdipole == 0) 140 | mex_id_ = 'l2d_directch(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], io dcomplex[xx], i double[x])'; 141 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, nd2, nt, nd3, nt, 1); 142 | end 143 | if(ifcharge==0 && ifdipole == 1) 144 | mex_id_ = 'l2d_directdh(i int[x], i double[xx], i int[x], i dcomplex[xx], i double[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], io dcomplex[xx], i double[x])'; 145 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, dipvec, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, nd2, ns, 2, nt, 1, nd, nt, nd2, nt, nd3, nt, 1); 146 | end 147 | if(ifcharge==1 && ifdipole == 1) 148 | mex_id_ = 'l2d_directcdh(i int[x], i double[xx], i int[x], i dcomplex[xx], i dcomplex[xx], i double[xx], i double[xx], i int[x], io dcomplex[xx], io dcomplex[xx], io dcomplex[xx], i double[x])'; 149 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, dipvec, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, nd2, ns, 2, nt, 1, nd, nt, nd2, nt, nd3, nt, 1); 150 | end 151 | U.pottarg = pottarg; 152 | U.gradtarg = squeeze(reshape(gradtarg,[nd,2,nt])); 153 | U.hesstarg = squeeze(reshape(hesstarg,[nd,3,nt])); 154 | end 155 | end 156 | % 157 | % 158 | % --------------------------------------------------------------------- 159 | -------------------------------------------------------------------------------- /matlab/r2ddir.m: -------------------------------------------------------------------------------- 1 | function [U] = r2ddir(srcinfo,targ,pgt) 2 | % 3 | % This subroutine computes the N-body Laplace 4 | % interactions and its gradients in two dimensions where 5 | % the interaction kernel is given by $\log(r)$ 6 | % 7 | % u(x) = \frac{i}{4}\sum_{j=1}^{N} c_{j} \log(\|x-x_{j}\|) - d_{j} v_{j} 8 | % \cdot \nabla \left( \log(\|x-x_{j} \|) \right) 9 | % 10 | % where $c_{j}$ are the charge densities, $d_{j}$ are the dipole 11 | % densities, 12 | % $v_{j}$ are the dipole orientation vectors, and 13 | % $x_{j}$ are the source locations. 14 | % When $\|x-x_{j}\| <= L \eps_{m}$, with $L$ being the size of the bounding 15 | % box of sources and targets and $\eps_{m}$ being machine precision, 16 | % the term corresponding to $x_{j}$ is dropped 17 | % from the sum. 18 | % 19 | % 20 | % The sum is evaluated directly - (slow code for testing) 21 | % 22 | % 23 | % Note: The charge, dipstr, pot,grad,hess,pottarg,gradtarg,hesstarg are 24 | % real valued for these routines 25 | % 26 | % Args: 27 | % 28 | % - srcinfo: structure 29 | % structure containing sourceinfo 30 | % 31 | % * srcinfo.sources: double(2,n) 32 | % source locations, $x_{j}$ 33 | % * srcinfo.nd: integer 34 | % number of charge/dipole vectors (optional, 35 | % default - nd = 1) 36 | % * srcinfo.charges: double(nd,n) 37 | % charge densities, $c_{j}$ (optional, 38 | % default - term corresponding to charges dropped) 39 | % * srcinfo.dipstr: double(nd,n) 40 | % dipole densities, $d_{j}$ (optional, 41 | % default - term corresponding to dipoles dropped) 42 | % * srcinfo.dipvec: double(nd,2,n) 43 | % dipole orientation vectors, $v_{j}$ (optional 44 | % default - term corresponding to dipoles dropped) 45 | % 46 | % - targ: double(3,nt) 47 | % target locations, $t_{i}$ 48 | % - pgt: integer 49 | % | target eval flag 50 | % | potential at targets evaluated if pgt = 1 51 | % | potential and gradient at targets evaluated if pgt=2 52 | % 53 | % Returns: 54 | % 55 | % - U.pottarg: potential at target locations, if requested, $u(t_{i})$ 56 | % - U.gradtarg: gradient at target locations, if requested, $\nabla u(t_{i})$ 57 | % - U.hesstarg: hessian at target locations, if requested, $\nabla \nabla u(t_{i})$ 58 | 59 | 60 | thresh = 1e-15; 61 | sources = srcinfo.sources; 62 | [m,ns] = size(sources); 63 | assert(m==2,'The first dimension of sources must be 2'); 64 | if(~isfield(srcinfo,'nd')) 65 | nd = 1; 66 | end 67 | if(isfield(srcinfo,'nd')) 68 | nd = srcinfo.nd; 69 | end 70 | 71 | 72 | pottarg = zeros(nd,1); 73 | gradtarg = zeros(nd*2,1); 74 | hesstarg = zeros(nd*3,1); 75 | [m,nt] = size(targ); 76 | assert(m==2,'First dimension of targets must be 2'); 77 | if(pgt >=1), pottarg = zeros(nd,nt); end; 78 | if(pgt >= 2), gradtarg = zeros(nd*2,nt); end; 79 | if(pgt == 3), hesstarg = zeros(nd*3,nt); end; 80 | 81 | if(pgt ==0), disp('Nothing to compute, set pgt to 1,2 or 3'); return; end; 82 | 83 | if(isfield(srcinfo,'charges')) 84 | ifcharge = 1; 85 | charges = srcinfo.charges; 86 | if(nd==1), assert(length(charges)==ns,'Charges must be same length as second dimension of sources'); end; 87 | if(nd>1), [a,b] = size(charges); assert(a==nd && b==ns,'Charges must be of shape [nd,ns] where nd is the number of densities, and ns is the number of sources'); end; 88 | else 89 | ifcharge = 0; 90 | charges = zeros(nd,1); 91 | end 92 | 93 | if(isfield(srcinfo,'dipstr') || isfield(srcinfo,'dipvec')) 94 | ifdipole = 1; 95 | dipstr = srcinfo.dipstr; 96 | if(nd==1), assert(length(dipstr)==ns,'Dipole strength must be same length as second dimension of sources'); end; 97 | if(nd>1), [a,b] = size(dipstr); assert(a==nd && b==ns,'Dipstr must be of shape [nd,ns] where nd is the number of densities, and ns is the number of sources'); end; 98 | dipvec = srcinfo.dipvec; 99 | if(nd == 1), [a,b] = size(squeeze(dipvec)); assert(a==2 && b==ns,'Dipvec must be of shape[2,ns], where ns is the number of sources'); end; 100 | if(nd>1), [a,b,c] = size(dipvec); assert(a==nd && b==2 && c==ns, 'Dipvec must be of shape[nd,2,ns], where nd is number of densities, and ns is the number of sources'); end; 101 | dipvec = reshape(dipvec,[2*nd,ns]); 102 | else 103 | ifdipole = 0; 104 | dipvec = zeros(nd*2,ns); 105 | dipstr = zeros(nd,ns); 106 | end 107 | 108 | nd2 = 2*nd; 109 | nd3 = 3*nd; 110 | 111 | if(pgt == 1) 112 | if(ifcharge==1 && ifdipole == 0) 113 | mex_id_ = 'r2d_directcp(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i int[x], io double[xx], i double[x])'; 114 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, 1); 115 | end 116 | if(ifcharge==0 && ifdipole == 1) 117 | mex_id_ = 'r2d_directdp(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i double[xx], i int[x], io double[xx], i double[x])'; 118 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, dipvec, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, nd2, ns, 2, nt, 1, nd, nt, 1); 119 | end 120 | if(ifcharge==1 && ifdipole == 1) 121 | mex_id_ = 'r2d_directcdp(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i double[xx], i double[xx], i int[x], io double[xx], i double[x])'; 122 | [pottarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, dipvec, targ, nt, pottarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, nd2, ns, 2, nt, 1, nd, nt, 1); 123 | end 124 | U.pottarg = pottarg; 125 | end 126 | if(pgt == 2) 127 | if(ifcharge==1 && ifdipole == 0) 128 | mex_id_ = 'r2d_directcg(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i int[x], io double[xx], io double[xx], i double[x])'; 129 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, nd2, nt, 1); 130 | end 131 | if(ifcharge==0 && ifdipole == 1) 132 | mex_id_ = 'r2d_directdg(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i double[xx], i int[x], io double[xx], io double[xx], i double[x])'; 133 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, dipvec, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, nd2, ns, 2, nt, 1, nd, nt, nd2, nt, 1); 134 | end 135 | if(ifcharge==1 && ifdipole == 1) 136 | mex_id_ = 'r2d_directcdg(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i double[xx], i double[xx], i int[x], io double[xx], io double[xx], i double[x])'; 137 | [pottarg, gradtarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, dipvec, targ, nt, pottarg, gradtarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, nd2, ns, 2, nt, 1, nd, nt, nd2, nt, 1); 138 | end 139 | U.pottarg = pottarg; 140 | U.gradtarg = squeeze(reshape(gradtarg,[nd,2,nt])); 141 | end 142 | if(pgt == 3) 143 | if(ifcharge==1 && ifdipole == 0) 144 | mex_id_ = 'r2d_directch(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i int[x], io double[xx], io double[xx], io double[xx], i double[x])'; 145 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, charges, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, 2, nt, 1, nd, nt, nd2, nt, nd3, nt, 1); 146 | end 147 | if(ifcharge==0 && ifdipole == 1) 148 | mex_id_ = 'r2d_directdh(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i double[xx], i int[x], io double[xx], io double[xx], io double[xx], i double[x])'; 149 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, dipstr, dipvec, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, nd2, ns, 2, nt, 1, nd, nt, nd2, nt, nd3, nt, 1); 150 | end 151 | if(ifcharge==1 && ifdipole == 1) 152 | mex_id_ = 'r2d_directcdh(i int[x], i double[xx], i int[x], i double[xx], i double[xx], i double[xx], i double[xx], i int[x], io double[xx], io double[xx], io double[xx], i double[x])'; 153 | [pottarg, gradtarg, hesstarg] = fmm2d(mex_id_, nd, sources, ns, charges, dipstr, dipvec, targ, nt, pottarg, gradtarg, hesstarg, thresh, 1, 2, ns, 1, nd, ns, nd, ns, nd2, ns, 2, nt, 1, nd, nt, nd2, nt, nd3, nt, 1); 154 | end 155 | U.pottarg = pottarg; 156 | U.gradtarg = squeeze(reshape(gradtarg,[nd,2,nt])); 157 | U.hesstarg = squeeze(reshape(hesstarg,[nd,3,nt])); 158 | end 159 | end 160 | 161 | 162 | % --------------------------------------------------------------------- 163 | -------------------------------------------------------------------------------- /matlab/st2ddir.m: -------------------------------------------------------------------------------- 1 | function [U] = st2ddir(srcinfo,targ,ifppregtarg) 2 | % ST2dDIR Direct (slow) 2d Stokes kernel sums (reference for STFMM2d). 3 | % 4 | % U = st2ddir(srcinfo,targ,ifppregtarg) 5 | % 6 | % Stokes direct evaluation in R^2: evaluate all pairwise particle 7 | % interactions with targets. This is the slow O(N^2) direct code used 8 | % as a reference for testing the (fast) code stfmm2d. 9 | % 10 | % Kernel definitions, input and outputs arguments are identical to 11 | % stfmm2d (see that function for all definitions), apart from: 12 | % 1) the first argument (eps) is absent. 13 | % 2) there are currently no outputs at sources, meaning that U.pot, U.pre, 14 | % and U.grad are missing (as if ifppreg=0). In other words, 15 | % just targets for now, and targ is thus not an optional argument. 16 | % 17 | % See also: STFMM2d 18 | 19 | sources = srcinfo.sources; 20 | [m,ns] = size(sources); 21 | assert(m==2,'The first dimension of sources must be 2'); 22 | if(~isfield(srcinfo,'nd')) 23 | nd = 1; 24 | end 25 | if(isfield(srcinfo,'nd')) 26 | nd = srcinfo.nd; 27 | end 28 | 29 | thresh = 1e-15; 30 | 31 | if( nargin <= 1 ) 32 | return; 33 | else 34 | if( nargin <= 2 ), ifppregtarg = 3; end; 35 | [m,nt] = size(targ); 36 | assert(m==2,'First dimension of targets must be 2'); 37 | pottarg = zeros(nd*2,nt); 38 | pretarg = zeros(nd,nt); 39 | gradtarg = zeros(nd*4,nt); 40 | end 41 | 42 | if(ifppregtarg == 0), disp('Nothing to compute, set eigher ifppregtarg to 1 or 2 or 3'); return; end; 43 | 44 | if(isfield(srcinfo,'stoklet')) 45 | ifstoklet = 1; 46 | ns_stok = ns; 47 | stoklet = srcinfo.stoklet; 48 | if(nd == 1), [a,b] = size(squeeze(stoklet)); assert(a==2 && b==ns,'Stoklet must be of shape[2,ns], where ns is the number of sources'); end; 49 | if(nd>1), [a,b,c] = size(stoklet); assert(a==nd && b==2 && c==ns, 'Stoklet must be of shape[nd,2,ns], where nd is number of densities, and ns is the number of sources'); end; 50 | stoklet = reshape(stoklet,[2*nd,ns]); 51 | else 52 | ifstoklet = 0; 53 | ns_stok = 1; 54 | stoklet = zeros(nd*2,1); 55 | end 56 | 57 | if(isfield(srcinfo,'strslet') && isfield(srcinfo,'strsvec')) 58 | ifstrslet = 1; 59 | ns_strs = ns; 60 | strslet = srcinfo.strslet; 61 | strsvec = srcinfo.strsvec; 62 | if(nd == 1), [a,b] = size(squeeze(strslet)); assert(a==2 && b==ns,'Strslet must be of shape[2,ns], where ns is the number of sources'); end; 63 | if(nd == 1), [a,b] = size(squeeze(strsvec)); assert(a==2 && b==ns,'Strsvec must be of shape[2,ns], where ns is the number of sources'); end; 64 | if(nd>1), [a,b,c] = size(strslet); assert(a==nd && b==2 && c==ns, 'Strslet must be of shape[nd,2,ns], where nd is number of densities, and ns is the number of sources'); end; 65 | if(nd>1), [a,b,c] = size(strsvec); assert(a==nd && b==2 && c==ns, 'Strsvec must be of shape[nd,2,ns], where nd is number of densities, and ns is the number of sources'); end; 66 | strslet = reshape(strslet,[2*nd,ns]); 67 | strsvec = reshape(strsvec,[2*nd,ns]); 68 | else 69 | ifstrslet = 0; 70 | ns_strs = 1; 71 | strslet = zeros(nd*2,1); 72 | strsvec = zeros(nd*2,1); 73 | end 74 | 75 | nd2 = 2*nd; 76 | nd4 = 4*nd; 77 | ier = 0; 78 | 79 | if ifstoklet == 1 && ifstrslet == 0 80 | mex_id_ = 'st2ddirectstokg(i int[x], i double[xx], i double[xx], i int[x], i double[xx], i int[x], io double[xx], io double[xx], io double[xx], i double[x])'; 81 | [pottarg, pretarg, gradtarg] = fmm2d(mex_id_, nd, sources, stoklet, ns, targ, nt, pottarg, pretarg, gradtarg, thresh, 1, 2, ns, nd2, ns_stok, 1, 2, nt, 1, nd2, nt, nd, nt, nd4, nt, 1); 82 | else 83 | istress = 1; 84 | mex_id_ = 'st2ddirectstokstrsg(i int[x], i double[xx], i int[x], i double[xx], i int[x], i double[xx], i double[xx], i int[x], i double[xx], i int[x], io double[xx], io double[xx], io double[xx], i double[x])'; 85 | [pottarg, pretarg, gradtarg] = fmm2d(mex_id_, nd, sources, ifstoklet, stoklet, istress, strslet, strsvec, ns, targ, nt, pottarg, pretarg, gradtarg, thresh, 1, 2, ns, 1, nd2, ns_stok, 1, nd2, ns_strs, nd2, ns_strs, 1, 2, nt, 1, nd2, nt, nd, nt, nd4, nt, 1); 86 | end 87 | 88 | U.pottarg = []; 89 | U.pretarg = []; 90 | U.gradtarg = []; 91 | if(ifppregtarg >= 1), U.pottarg = squeeze(reshape(pottarg,[nd,2,nt])); end; 92 | if(ifppregtarg >= 2), U.pretarg = pretarg; end; 93 | if(ifppregtarg >= 3), U.gradtarg = squeeze(reshape(gradtarg,[nd,2,2,nt])); end; 94 | end 95 | -------------------------------------------------------------------------------- /matlab/stfmm2dTest.m: -------------------------------------------------------------------------------- 1 | clear srcinfo 2 | 3 | ns = 4000; 4 | srcinfo.sources = rand(2,ns); 5 | srcinfo.stoklet = rand(2,ns); 6 | srcinfo.strslet = rand(2,ns); 7 | srcinfo.strsvec = rand(2,ns); 8 | 9 | nt = 3999; 10 | targ = rand(2,nt); 11 | 12 | eps = 1e-5; 13 | ntests = 2; 14 | ipass = zeros(ntests,1); 15 | errs = zeros(ntests,1); 16 | ntest = 10; 17 | 18 | stmp = srcinfo.sources(:,1:ntest); 19 | ttmp = targ(:,1:ntest); 20 | 21 | itest = 1; 22 | 23 | 24 | % Test source to source, target, stoklet, strslet, pot, pre, grad 25 | ifppreg = 3; 26 | ifppregtarg = 3; 27 | U1 = stfmm2d(eps,srcinfo,ifppreg,targ,ifppregtarg); 28 | U2 = st2ddir(srcinfo,stmp,ifppreg); 29 | U3 = st2ddir(srcinfo,ttmp,ifppregtarg); 30 | s1 = U1.pot(:,1:ntest); s1 = s1(:); 31 | s2 = U2.pottarg; s2 = s2(:); 32 | s3 = U1.pre(1:ntest); s3 = s3(:); 33 | s4 = U2.pretarg; s4 = s4(:); 34 | s5 = U1.grad(:,:,1:ntest); s5 = s5(:); 35 | s6 = U2.gradtarg; s6 = s6(:); 36 | t1 = U1.pottarg(:,1:ntest); t1 = t1(:); 37 | t2 = U3.pottarg; t2 = t2(:); 38 | t3 = U1.pretarg(1:ntest); t3 = t3(:); 39 | t4 = U3.pretarg; t4 = t4(:); 40 | t5 = U1.gradtarg(:,:,1:ntest); t5 = t5(:); 41 | t6 = U3.gradtarg; t6 = t6(:); 42 | 43 | err = norm(s1-s2)^2 + norm(s3-s4)^2 + norm(s5-s6)^2 + norm(t1-t2)^2 + norm(t3-t4)^2 + norm(t5-t6)^2; 44 | ra = norm(s2)^2 + norm(s4)^2 + norm(s6)^2 + norm(t2)^2 + norm(t4)^2 + norm(t6)^2; 45 | 46 | errs(1) = sqrt(err/ra); 47 | assert(errs(1)= 0.4.3", 4 | "cmake >= 3.19", 5 | "numpy >= 1.12.0", 6 | ] 7 | 8 | build-backend = "scikit_build_core.build" 9 | 10 | [project] 11 | name = "fmm2dpy" 12 | description = "Python bindings for the FMM2D library" 13 | readme = "README.md" 14 | requires-python = ">=3.8" 15 | dependencies = ["numpy >= 1.12.0"] 16 | dynamic = ["version"] 17 | 18 | [tool.scikit-build] 19 | # Protect the configuration against future changes in scikit-build-core 20 | minimum-version = "0.4" 21 | # Setuptools-style build caching in a local directory 22 | build-dir = "build/{wheel_tag}" 23 | 24 | cmake.targets = ["fmm2d", "hfmm2d_fortran", "lfmm2d_fortran", "bhfmm2d_fortran", "stfmm2d_fortran"] 25 | 26 | wheel.packages = ["python/fmm2dpy"] 27 | 28 | [tool.scikit-build.metadata.version] 29 | provider = "scikit_build_core.metadata.regex" 30 | input = "python/fmm2dpy/__init__.py" 31 | 32 | [tool.cibuildwheel] 33 | # Necessary to see build output from the actual compilation 34 | build-verbosity = 1 35 | -------------------------------------------------------------------------------- /python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (WIN32) 2 | install(TARGETS hfmm2d_fortran lfmm2d_fortran bhfmm2d_fortran stfmm2d_fortran DESTINATION fmm2dpy RUNTIME DESTINATION fmm2dpy) 3 | else () 4 | install(TARGETS hfmm2d_fortran lfmm2d_fortran bhfmm2d_fortran stfmm2d_fortran DESTINATION fmm2dpy) 5 | endif () 6 | -------------------------------------------------------------------------------- /python/examples/bhfmm_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import fmm2dpy as fmm 4 | import numpy as np 5 | 6 | 7 | # 8 | # This is a sample code to demonstrate how to use 9 | # the fmm libraries 10 | # 11 | 12 | # sample with one density, sources to sources, 13 | # charge interactions, and potential only 14 | # 15 | n = 100000 16 | nd = 1 17 | sources = np.random.uniform(0,1,(2,n)) 18 | eps = 10**(-5) 19 | 20 | charges = np.random.uniform(0,1,(2,n)) + 1j*np.random.uniform(0,1,(2,n)) 21 | dipoles = np.random.uniform(0,1,(3,n)) + 1j*np.random.uniform(0,1,(3,n)) 22 | out = fmm.bhfmm2d(eps=eps,sources=sources,charges=charges,dipoles=dipoles,pg=1) 23 | 24 | 25 | # sample with a vector of densities, sources to 26 | # sources and targets, dipole interactions, 27 | # potential and gradietns 28 | 29 | nd = 3 30 | nt = 1870 31 | targ = np.random.uniform(0,1,(2,nt)) 32 | dipoles = np.random.uniform(0,1,(nd,3,n)) + 1j*np.random.uniform(0,1,(nd,3,n)) 33 | out2 = fmm.bhfmm2d(eps=eps,sources=sources,dipoles=dipoles,\ 34 | targets=targ,nd=nd,pg=2,pgt=2) 35 | -------------------------------------------------------------------------------- /python/examples/cfmm_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import fmm2dpy as fmm 4 | import numpy as np 5 | 6 | 7 | # 8 | # This is a sample code to demonstrate how to use 9 | # the fmm libraries 10 | # 11 | 12 | # sample with one density, sources to sources, 13 | # charge interactions, and potential only 14 | # 15 | n = 2000000 16 | nd = 1 17 | sources = np.random.uniform(0,1,(2,n)) 18 | eps = 10**(-5) 19 | 20 | charges = np.random.uniform(0,1,n) + 1j*np.random.uniform(0,1,n) 21 | out = fmm.lfmm2d(eps=eps,sources=sources,charges=charges,pg=1) 22 | 23 | 24 | # sample with a vector of densities, sources to 25 | # sources and targets, dipole interactions, 26 | # potential and gradietns 27 | 28 | nd = 3 29 | nt = 1870 30 | targ = np.random.uniform(0,1,(2,nt)) 31 | dipstr = np.random.uniform(0,1,(nd,n)) + 1j*np.random.uniform(0,1,n) 32 | out2 = fmm.cfmm2d(eps=eps,sources=sources,dipstr=dipstr,\ 33 | targets=targ,nd=nd,pg=2,pgt=2) 34 | -------------------------------------------------------------------------------- /python/examples/lfmm_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import fmm2dpy as fmm 4 | import numpy as np 5 | 6 | 7 | # 8 | # This is a sample code to demonstrate how to use 9 | # the fmm libraries 10 | # 11 | 12 | # sample with one density, sources to sources, 13 | # charge interactions, and potential only 14 | # 15 | n = 2000000 16 | nd = 1 17 | sources = np.random.uniform(0,1,(2,n)) 18 | eps = 10**(-5) 19 | 20 | charges = np.random.uniform(0,1,n) + 1j*np.random.uniform(0,1,n) 21 | out = fmm.lfmm2d(eps=eps,sources=sources,charges=charges,pg=1) 22 | 23 | 24 | # sample with a vector of densities, sources to 25 | # sources and targets, dipole interactions, 26 | # potential and gradietns 27 | 28 | nd = 3 29 | nt = 1870 30 | targ = np.random.uniform(0,1,(2,nt)) 31 | dipstr = np.random.uniform(0,1,(nd,n)) + 1j*np.random.uniform(0,1,n) 32 | dipvecs = np.random.uniform(0,1,(nd,2,n)) 33 | out2 = fmm.lfmm2d(eps=eps,sources=sources,dipstr=dipstr,dipvec=dipvecs,\ 34 | targets=targ,nd=nd,pg=2,pgt=2) 35 | -------------------------------------------------------------------------------- /python/examples/rfmm_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import fmm2dpy as fmm 4 | import numpy as np 5 | 6 | 7 | # 8 | # This is a sample code to demonstrate how to use 9 | # the fmm libraries 10 | # 11 | 12 | # sample with one density, sources to sources, 13 | # charge interactions, and potential only 14 | # 15 | n = 2000000 16 | nd = 1 17 | sources = np.random.uniform(0,1,(2,n)) 18 | eps = 10**(-5) 19 | 20 | charges = np.random.uniform(0,1,n) 21 | out = fmm.rfmm2d(eps=eps,sources=sources,charges=charges,pg=1) 22 | 23 | 24 | # sample with a vector of densities, sources to 25 | # sources and targets, dipole interactions, 26 | # potential and gradietns 27 | 28 | nd = 3 29 | nt = 1870 30 | targ = np.random.uniform(0,1,(2,nt)) 31 | dipstr = np.random.uniform(0,1,(nd,n)) 32 | dipvecs = np.random.uniform(0,1,(nd,2,n)) 33 | out2 = fmm.rfmm2d(eps=eps,sources=sources,dipstr=dipstr,dipvec=dipvecs,\ 34 | targets=targ,nd=nd,pg=2,pgt=2) 35 | -------------------------------------------------------------------------------- /python/examples/stfmm_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import fmm2dpy as fmm 4 | import numpy as np 5 | 6 | 7 | # 8 | # This is a sample code to demonstrate how to use 9 | # the fmm libraries 10 | # 11 | 12 | # sample with one density, sources to sources, 13 | # stokeslet interactions, and potential+pressure+gradient 14 | # 15 | n = 20000 16 | nd = 1 17 | sources = np.random.uniform(0,1,(2,n)) 18 | eps = 10**(-5) 19 | 20 | stoklet = np.random.uniform(0,1,(2,n)) 21 | out = fmm.stfmm2d(eps=eps,sources=sources,stoklet=stoklet,ifppreg=3) 22 | 23 | 24 | # sample with a vector of densities, sources to 25 | # sources and targets, stokeslet + stresslet interactions, 26 | # potential + pressure 27 | 28 | nd = 2 29 | nt = 1870 30 | targ = np.random.uniform(0,1,(2,nt)) 31 | stoklet = np.random.uniform(0,1,(nd,2,n)) 32 | strsvec = np.random.uniform(0,1,(nd,2,n)) 33 | strslet = np.random.uniform(0,1,(nd,2,n)) 34 | out = fmm.stfmm2d(eps=eps,sources=sources,stoklet=stoklet,\ 35 | strslet=strslet,strsvec=strsvec,\ 36 | targets=targ,nd=nd,ifppreg=2,ifppregtarg=2) 37 | -------------------------------------------------------------------------------- /python/fmm2dpy/__init__.py: -------------------------------------------------------------------------------- 1 | from .fmm2d import hfmm2d,rfmm2d,lfmm2d,cfmm2d,bhfmm2d,stfmm2d,h2ddir,r2ddir,l2ddir,c2ddir,bh2ddir,st2ddir,comperr,Output 2 | __version__ = '1.1.0' 3 | -------------------------------------------------------------------------------- /python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "numpy"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | import string 3 | import os 4 | from numpy.distutils.core import setup 5 | from numpy.distutils.core import Extension 6 | from sys import platform 7 | 8 | pkg_name = "fmm2dpy" 9 | 10 | ## TODO: this should be automatically populated using "read directory, or whatever" 11 | ## TODO: fix problem with relative location for executable 12 | 13 | list_helm=['hfmm2dwrap.f','hfmm2dwrap_vec.f','helmkernels2d.f'] 14 | list_lap=['rfmm2dwrap.f','rfmm2dwrap_vec.f','rlapkernels2d.f','lfmm2dwrap.f','lfmm2dwrap_vec.f','lapkernels2d.f','cfmm2dwrap.f','cfmm2dwrap_vec.f','cauchykernels2d.f'] 15 | list_bh=['bhfmm2dwrap.f','bhkernels2d.f'] 16 | list_stk=['stfmm2d.f','stokkernels2d.f'] 17 | list_common=[] 18 | 19 | FLIBS = os.getenv('FMM_FLIBS') 20 | FLIBS = FLIBS.rstrip().split(' ') 21 | FLIBS = list(filter(None, FLIBS)) 22 | FLIBS.append('../lib-static/libfmm2d.a') 23 | FFLAGS = os.getenv('FMM_FFLAGS') 24 | FFLAGS = FFLAGS.rstrip().split(' ') 25 | FFLAGS = list(filter(None, FFLAGS)) 26 | 27 | 28 | 29 | c_opts = ['_c','_d','_cd'] 30 | c_opts2 = ['c','d','cd'] 31 | st_opts = ['_s','_t','_st'] 32 | p_optsh = ['_p','_g'] 33 | p_optsh2 = ['p','g'] 34 | 35 | p_optsl = ['_p','_g','_h'] 36 | p_optsl2 = ['p','g','h'] 37 | 38 | list_int_helm = [] 39 | list_int_helm_vec = [] 40 | list_int_helm_dir = [] 41 | 42 | list_int_lap = [] 43 | list_int_lap_vec = [] 44 | list_int_lap_dir = [] 45 | 46 | for st in st_opts: 47 | for cd in c_opts: 48 | for pg in p_optsh: 49 | list_int_helm.append('hfmm2d'+st+cd+pg) 50 | list_int_helm_vec.append('hfmm2d'+st+cd+pg+'_vec') 51 | for pg in p_optsl: 52 | list_int_lap.append('rfmm2d'+st+cd+pg) 53 | list_int_lap.append('lfmm2d'+st+cd+pg) 54 | list_int_lap.append('cfmm2d'+st+cd+pg) 55 | list_int_lap_vec.append('rfmm2d'+st+cd+pg+'_vec') 56 | list_int_lap_vec.append('lfmm2d'+st+cd+pg+'_vec') 57 | list_int_lap_vec.append('cfmm2d'+st+cd+pg+'_vec') 58 | 59 | list_int_bh = [] 60 | list_int_bh_dir = [] 61 | for cd in c_opts2: 62 | for pg in p_optsh2: 63 | list_int_helm_dir.append('h2d_direct'+cd+pg) 64 | list_int_bh_dir.append('bh2d_direct'+cd+pg) 65 | for pg in p_optsl2: 66 | list_int_lap_dir.append('r2d_direct'+cd+pg) 67 | list_int_lap_dir.append('l2d_direct'+cd+pg) 68 | list_int_lap_dir.append('c2d_direct'+cd+pg) 69 | list_int_bh.append('bhfmm2dwrap_guru') 70 | 71 | ext_helm = Extension( 72 | name='fmm2dpy.hfmm2d_fortran', 73 | sources=['../src/helmholtz/'+item for item in list_helm]+['../src/common/'+item for item in list_common], 74 | f2py_options=['only:']+list_int_helm+list_int_helm_vec+list_int_helm_dir+[':'], 75 | extra_f90_compile_args=FFLAGS, 76 | extra_f77_compile_args=FFLAGS, 77 | extra_link_args=FLIBS 78 | ) 79 | 80 | ext_lap = Extension( 81 | name='fmm2dpy.lfmm2d_fortran', 82 | sources=['../src/laplace/'+item for item in list_lap]+['../src/common/'+item for item in list_common], 83 | f2py_options=['only:']+list_int_lap+list_int_lap_vec+list_int_lap_dir+[':'], 84 | extra_f90_compile_args=FFLAGS, 85 | extra_f77_compile_args=FFLAGS, 86 | extra_link_args=FLIBS 87 | ) 88 | 89 | ext_bh = Extension( 90 | name='fmm2dpy.bhfmm2d_fortran', 91 | sources=['../src/biharmonic/'+item for item in list_bh]+['../src/common/'+item for item in list_common], 92 | f2py_options=['only:']+list_int_bh+list_int_bh_dir+[':'], 93 | extra_f90_compile_args=FFLAGS, 94 | extra_f77_compile_args=FFLAGS, 95 | extra_link_args=FLIBS 96 | ) 97 | 98 | ext_st = Extension( 99 | name='fmm2dpy.stfmm2d_fortran', 100 | sources=['../src/stokes/stfmm2d.f']+['../src/stokes/stokkernels2d.f'], 101 | f2py_options=['only:']+['stfmm2d']+['st2ddirectstokg']+['st2ddirectstokstrsg']+[':'], 102 | extra_link_args=FLIBS 103 | ) 104 | 105 | 106 | ## TODO: fill in the info below 107 | setup( 108 | name=pkg_name, 109 | python_requires='>=3.0.0', 110 | version="1.1.0", 111 | author="Travis Askham, Zydrunas Gimbutas, Leslie Greengard, Libin Lu, Michael O'Neil, Manas Rachh, and Vladimir Rokhlin", 112 | author_email="mrachh@flatironinstitute.org", 113 | description="This pacakge contains basic routines for Laplace and Helmholtz fast multipole methods in two dimensions", 114 | long_description=open('../README.md').read(), 115 | long_description_content_type='text/markdown', 116 | url="https://github.com/flatironinstitute/fmm2d", 117 | packages=['fmm2dpy'], 118 | install_requires=[ 119 | "numpy", 120 | "pytest" 121 | ], 122 | ext_modules=[ext_helm,ext_lap,ext_bh,ext_st], 123 | classifiers=[ 124 | "Programming Language :: Python :: 3", 125 | "License :: OSI Approved :: Apache Software License", 126 | "Operating System :: OS Independent", 127 | ] 128 | ) 129 | -------------------------------------------------------------------------------- /src/biharmonic/bh2dterms.f: -------------------------------------------------------------------------------- 1 | c----------------------------------------------------------------------------- 2 | c 3 | c bh2dterms - determine number of terms in mpole expansions 4 | c 5 | c bh2dterms_far - determine number of terms in mpole expansions 6 | c for separation by 2 7 | c 8 | c bh2dterms_list2 - build the number of terms table for all boxes 9 | c in list 2 10 | c 11 | c----------------------------------------------------------------------------- 12 | c 13 | c 14 | c 15 | subroutine bh2dterms(eps, nterms, ier) 16 | implicit real *8 (a-h,o-z) 17 | c 18 | c 19 | c Determine number of terms in mpole expansions for biharmonic equation 20 | c 21 | c The method is based on examining the decay of \rho^n / r^{n+1} 22 | c for \rho a worst case source and r a worst case target. 23 | c 24 | c----------------------------------------------------------------------------- 25 | c 26 | complex *16 zk, z1, z2, z3, jfun(0:2000), ht0, 27 | 1 ht1, ht2, ztmp, 28 | 1 hfun(0:2000) 29 | c 30 | ier = 0 31 | c 32 | ntmax = 1000 33 | c 34 | z1 = 1.5d0 35 | do i = 0,ntmax 36 | hfun(i) = 1.0d0/(z1**(i+1)) 37 | enddo 38 | ccc call prin2(' hfun is *',hfun,2*ntmax+2) 39 | c 40 | z2 = dsqrt(2d0)/2.d0 41 | do i = 0,ntmax 42 | jfun(i) = z2**i 43 | enddo 44 | c 45 | xtemp1 = cdabs(jfun(0)*hfun(0)) 46 | nterms = 1 47 | do j = 2, ntmax 48 | xtemp1 = cdabs(jfun(j)*hfun(j)) 49 | if(xtemp1 .lt. eps)then 50 | nterms = j 51 | return 52 | endif 53 | c 54 | enddo 55 | return 56 | end 57 | c 58 | c 59 | c 60 | c 61 | c 62 | subroutine bh2dterms_far(eps, nterms, ier) 63 | implicit real *8 (a-h,o-z) 64 | c 65 | c 66 | c Determine number of terms in mpole expansions for biharmonic 67 | c equation 68 | c 69 | c The method is based on examining the decay of \rho^n / r^{n+1} 70 | c for \rho a worst case source and r a worst case target. 71 | c 72 | c This routine assumes slightly larger separation of boxes: the 73 | c first unit box is located at the origin and the second box is 74 | c located at (3,0). 75 | c 76 | c----------------------------------------------------------------------------- 77 | c 78 | complex *16 zk, z1, z2, z3, jfun(0:2000), ht0, 79 | 1 ht1, ht2, ztmp, 80 | 1 hfun(0:2000) 81 | c 82 | ier = 0 83 | c 84 | ntmax = 1000 85 | c 86 | z1 = 2.5d0 87 | do i = 0,ntmax 88 | hfun(i) = 1.0d0/(z1**(i+1)) 89 | enddo 90 | ccc call prin2(' hfun is *',hfun,2*ntmax+2) 91 | c 92 | z2 = dsqrt(2d0)/2.d0 93 | do i = 0,ntmax 94 | jfun(i) = z2**i 95 | enddo 96 | ccc call prin2(' jfun is *',jfun,2*ntmax+2) 97 | c 98 | xtemp1 = cdabs(jfun(0)*hfun(0)) 99 | nterms = 1 100 | do j = 2, ntmax 101 | xtemp1 = cdabs(jfun(j)*hfun(j)) 102 | if(xtemp1 .lt. eps)then 103 | nterms = j 104 | return 105 | endif 106 | c 107 | enddo 108 | return 109 | end 110 | c 111 | c 112 | c 113 | c 114 | c 115 | subroutine bh2dterms_list2(eps, itable, ier) 116 | implicit real *8 (a-h,o-z) 117 | c 118 | c 119 | c Determine number of terms in mpole expansions for 120 | c biharmonic equation 121 | c 122 | c The method is based on examining the decay of \rho^n / r^{n+1} 123 | c for \rho a worst case source and r a worst case target. 124 | c 125 | c Build nterms table for all boxes in list 2 126 | c 127 | c 128 | c----------------------------------------------------------------------------- 129 | c 130 | complex *16 zk, z1, z2, z3, jfun(0:2000), ht0, 131 | 1 ht1, ht2, ztmp, 132 | 1 hfun(0:2000) 133 | c 134 | integer nterms_table(2:3,0:3) 135 | integer itable(-3:3,-3:3) 136 | c 137 | ier = 0 138 | c 139 | do 1800 ii=2,3 140 | do 1800 jj=0,3 141 | c 142 | dx=ii 143 | dy=jj 144 | c 145 | if( dx .gt. 0 ) dx=dx-.5 146 | if( dy .gt. 0 ) dy=dy-.5 147 | c 148 | rr=sqrt(dx*dx+dy*dy) 149 | ccc call prin2('rr=*',rr,1) 150 | ccc call prin2('rr=*',sqrt(3.0d0)/2*5,1) 151 | c 152 | ntmax = 1000 153 | c 154 | z1 = rr 155 | do i = 0,ntmax 156 | hfun(i) = 1.0d0/( z1**(i+1)) 157 | enddo 158 | ccc call prin2(' hfun is *',hfun,2*ntmax+2) 159 | c 160 | z2 = dsqrt(2d0)/2.d0 161 | do i = 0,ntmax 162 | jfun(i) = z2**i 163 | enddo 164 | c 165 | xtemp1 = cdabs(jfun(0)*hfun(0)) 166 | nterms = 1 167 | do j = 2, ntmax 168 | xtemp1 = cdabs(jfun(j)*hfun(j)) 169 | if(xtemp1 .lt. eps)then 170 | nterms = j 171 | goto 1600 172 | endif 173 | enddo 174 | 1600 continue 175 | c 176 | nterms_table(ii,jj)=nterms 177 | c 178 | 1800 continue 179 | c 180 | ccc call prinf('nterms=*',nterms_table,2*4*4) 181 | c 182 | c build the rank table for all boxes in list 2 183 | c 184 | do i=-3,3 185 | do j=-3,3 186 | itable(i,j)=0 187 | enddo 188 | enddo 189 | c 190 | do 2200 i=-3,3 191 | do 2200 j=-3,3 192 | c 193 | if( abs(i) .gt. 1 ) then 194 | itable(i,j)=nterms_table(abs(i),abs(j)) 195 | else if( abs(j) .gt. 1) then 196 | itable(i,j)=nterms_table(abs(j),abs(i)) 197 | endif 198 | c 199 | 2200 continue 200 | c 201 | return 202 | end 203 | c 204 | c 205 | c 206 | c 207 | c 208 | -------------------------------------------------------------------------------- /src/biharmonic/bhfmm2dwrap.f: -------------------------------------------------------------------------------- 1 | 2 | 3 | subroutine bhfmm2dwrap_guru(nd,eps,ns,sources,ifcharge,charge, 4 | 1 ifdipole,dip,iper,ifpgh,pot,grad, 5 | 2 hess,nt,targ,ifpghtarg,pottarg,gradtarg, 6 | 3 hesstarg,ier) 7 | cf2py intent(in) nd,eps,ns,sources,ifcharge,charge,ifdipole,dip 8 | cf2py intent(in) iper,ifpgh,nt,targ,ifpghtarg 9 | cf2py intent(out) pot,grad,hess,pottarg,gradtarg,hesstarg,ier 10 | c 11 | c---------------------------------------------- 12 | c 13 | c This subroutine evaluates biharmonic sums related to stokes 14 | c and elasticity due to point ``charges'' and ``dipoles'' 15 | c 16 | c 17 | c Notes: 18 | c * charges are complex, and dipoles are described by vectors 19 | c in C^2 20 | c * In the legacy interface, dipoles were input as two 21 | c complex arrays dip1 and dip2, as opposed to a single 22 | c complex array (nd,2,n) where n is the number of sources. 23 | c Similarly, the gradients in the legacy interface 24 | c were two complex arrays, grada, and gradaa; while 25 | c in the new interface, the gradient is a (nd,2,n) 26 | c complex array where (nd,1,n) is the derivative with 27 | c respect to z and the (nd,2,n) component is the derivative 28 | c with respect to z_bar 29 | c * In this subroutine and the rest the terms potential 30 | c and velocity are interchangably used 31 | c 32 | c 33 | c vel(z) = \sum charge1_j 2*\log|z-z_j| + 34 | c (charge2_j) (z-z_j)/(z-z_j)_bar+ 35 | c dip1/(z-z_j) + dip3/(z-z_j)_bar+ 36 | c dip2 (z-z_j)/(z-z_j)^2_bar 37 | c 38 | c The velocity for stokes is related to the goursat functions 39 | c as vel = \phi(z) + z (d/dz (\phi))_bar+\psi(z) 40 | c 41 | c The goursat functions are given by 42 | c 43 | c \phi(z) = \sum charge_j log(z-z_j)+ 44 | c dip1/(z-z_j) 45 | c 46 | c \psi(z) = \sum dippar2_bar/(z-z_j)+ 47 | c z_j_bar dippar1/(z-z_j)^2 + 48 | c 49 | c In all of the sums above, the terms for which |z-z_{j}| <= 2^-51|b| 50 | c where |b| is the size of the root box will be ignored. 51 | c 52 | c Gradient here has 53 | c 54 | c 55 | c INPUT PARAMETERS: 56 | c nd : number of expansions 57 | c eps : FMM precision requested 58 | c ns : number of sources 59 | c sources(2,ns) : source locations 60 | c ifcharge : flag for including charge interactions 61 | c charge interactions included if ifcharge =1 62 | c not included otherwise 63 | c charge(nd,2,ns) : charge strengths 64 | c charge(j,1,i) is the charge1 strength of the 65 | c jth charge density at source location i, and 66 | c charge(j,2,i) is the charge2 stregth of the 67 | c jth charge density at source location i 68 | c ifdipole : flag for including dipole interactions 69 | c dipole interactions included if ifcharge =1 70 | c not included otherwise 71 | c dip(nd,3,ns) : dipole strengths 72 | c dip(j,1,i) is dip1 for the jth dipole density 73 | c at source location i, dip(j,2,i) is dip2 74 | c for the jth dipole density at source location i, and 75 | c dip(j,3,i) is dip3 for the jth dipole density 76 | c at source locaation i 77 | c iper : flag for periodic implmentations. Currently unused 78 | c ifpgh : flag for computing pot/grad/hess 79 | c ifpgh = 1, only potential is computed 80 | c ifpgh = 2, potential and gradient are computed 81 | c ifpgh = 3, potential, gradient, and hessian 82 | c are computed (hessians not supported currently) 83 | c nt : number of targets 84 | c targ(2,nt) : target locations 85 | c ifpghtarg : flag for computing pottarg/gradtarg/hesstarg 86 | c ifpghtarg = 1, only potential is computed at targets 87 | c ifpghtarg = 2, potential and gradient are 88 | c computed at targets 89 | c ifpghtarg = 3, potential, gradient, and hessian are 90 | c computed at targets (hessians not supported 91 | c currently) 92 | c 93 | c OUTPUT PARAMETERS 94 | c pot(nd,*) : velocity at the source locations 95 | c grad(nd,3,*) : gradients (d/dz)_projz, (d/dz)_projzbar, d/dzbar at the source locations 96 | c hess(nd,3,*) : hessian at the source locations (currently unused) 97 | c pottarg(nd,*) : potential at the target locations 98 | c gradtarg(nd,3,*): gradient (d/dz)_projz, (d/dz)_projzbar, d/dzbar at the target locations 99 | c hesstarg(nd,3,*): hessian at the target locations (currently unused) 100 | c 101 | 102 | 103 | implicit none 104 | c 105 | cc calling sequence variables 106 | c 107 | integer nd 108 | real *8 omp_get_wtime 109 | real *8 eps 110 | integer ns,nt 111 | integer ifcharge,ifdipole 112 | integer iper,ier,ifpgh,ifpghtarg 113 | real *8 sources(2,ns),targ(2,nt) 114 | complex *16 charge(nd,2,ns),dip(nd,3,ns) 115 | 116 | complex *16 pot(nd,ns),grad(nd,3,ns), hess(nd,3,ns) 117 | complex *16 pottarg(nd,nt),gradtarg(nd,3,nt) 118 | complex *16 hesstarg(nd,3,nt) 119 | 120 | call bhfmm2d(nd,eps,ns,sources,ifcharge,charge, 121 | 1 ifdipole,dip,iper,ifpgh,pot,grad, 122 | 2 hess,nt,targ,ifpghtarg,pottarg,gradtarg, 123 | 3 hesstarg,ier) 124 | return 125 | end 126 | -------------------------------------------------------------------------------- /src/biharmonic/bhndiv2d.f: -------------------------------------------------------------------------------- 1 | subroutine bhndiv2d(eps,ns,nt,ifcharge,ifdipole,ifpgh, 2 | 1 ifpghtarg,ndiv,idivflag) 3 | c 4 | c 5 | c this subroutine estimates ndiv and idivflag 6 | c based on geometry parameters 7 | c 8 | c 9 | implicit none 10 | real *8 eps 11 | integer ns,nt,ifcharge,ifdipole,ifpgh,ifpghtarg,ndiv 12 | integer idivflag 13 | 14 | idivflag = 0 15 | 16 | 17 | if(eps.ge.0.5d-0) then 18 | ndiv = 3 19 | else if(eps.ge.0.5d-1) then 20 | ndiv = 5 21 | else if(eps.ge.0.5d-2) then 22 | ndiv = 8 23 | else if(eps.ge.0.5d-3) then 24 | ndiv = 10 25 | else if(eps.ge.0.5d-6) then 26 | ndiv = 15 27 | else if(eps.ge.0.5d-9) then 28 | ndiv = 20 29 | else if(eps.ge.0.5d-12) then 30 | ndiv = 25 31 | else if(eps.ge.0.5d-15) then 32 | ndiv = 45 33 | else 34 | ndiv = ns+nt 35 | endif 36 | 37 | 38 | return 39 | end 40 | -------------------------------------------------------------------------------- /src/common/cdjseval2d.f: -------------------------------------------------------------------------------- 1 | c 2 | c Computation of Bessel functions via recurrence 3 | c 4 | c********************************************************************** 5 | subroutine jbessel2d(nterms,z,rscale,fjs,ifder,fjder) 6 | implicit real *8 (a-h,o-z) 7 | c********************************************************************** 8 | c 9 | c PURPOSE: 10 | c 11 | c This subroutine evaluates the first NTERMS Bessel 12 | c functions and if required, their derivatives. 13 | c It incorporates a scaling parameter SCALE so that 14 | c 15 | c fjs_n(z)= j_n(z)/RSCALE^n 16 | c fjder_n(z)= \frac{\partial fjs_n(z)}{\partial z} 17 | c 18 | c NOTE: The scaling parameter RSCALE is meant to be used when 19 | c abs(z) < 1, in which case we recommend setting 20 | c RSCALE = abs(z). This prevents the fjs_n from 21 | c underflowing too rapidly. Otherwise, set RSCALE=1. 22 | c Do not set RSCALE = abs(z) if z could take on the 23 | c value zero. 24 | c In an FMM, when forming an expansion from a collection of 25 | c sources, set RSCALE = min( abs(k*r), 1) 26 | c where k is the Helmholtz parameter and r is the box dimension 27 | c at the relevant level. 28 | c 29 | c INPUT: 30 | c 31 | c nterms (integer): order of expansion of output array fjs 32 | c nterms should be greater than 1. 33 | c z (complex *16): argument of the Bessel functions 34 | c rscale (real *8): scaling factor (discussed above) 35 | c ifder (integer): flag indicating whether to calculate "fjder" 36 | c 0 NO 37 | c 1 YES 38 | c OUTPUT: 39 | c 40 | c fjs (complex *16): array of scaled Bessel functions. 41 | c fjder (complex *16): array of derivs of scaled Bessel functions. 42 | c 43 | c 44 | c INTERNAL VARIABLES 45 | c lextra lextra is buffer large enough to run the 46 | c recurrence from nterms upward until 47 | c the value of fjs has blown up by a factor 48 | c of 1.0d40 (a parameter hardwired as 49 | c upbound2 below). lextra should be much larger 50 | c than nterms. It is set below to 1000 51 | c If that is not sufficient, an error code is returned (ier=8). 52 | c 53 | c iscale integer workspace used to keep track of 54 | c internal scaling 55 | c 56 | c 57 | integer, allocatable :: iscale(:) 58 | complex *16, allocatable :: fjtemp(:) 59 | complex *16 wavek,fjs(0:nterms),fjder(0:nterms) 60 | complex *16 z,zinv,com,zscale,ztmp 61 | complex *16 psi,zmul,zsn,zmulinv 62 | complex *16 ima,ffn,ffnm1,ffnp1 63 | data ima/(0.0d0,1.0d0)/ 64 | c 65 | data upbound/1.0d+32/, upbound2/1.0d+40/, upbound2inv/1.0d-40/ 66 | data tiny/1.0d-200/,done/1.0d0/,zero/0.0d0/ 67 | c 68 | c ... Initializing ... 69 | c 70 | ier=0 71 | ccc call prinf(' ifder is *',ifder,1) 72 | c 73 | c set to asymptotic values if argument is sufficiently small 74 | c 75 | if (abs(z).lt.tiny) then 76 | fjs(0) = done 77 | do i = 1, nterms 78 | fjs(i) = zero 79 | enddo 80 | c 81 | if (ifder.eq.1) then 82 | do i=0,nterms 83 | fjder(i)=zero 84 | enddo 85 | fjder(1)=done/(2*rscale) 86 | endif 87 | c 88 | RETURN 89 | endif 90 | c 91 | c ... Step 1: carry out upward recursion starting at nterms until the 92 | c magnitude has grown by uppound2 = 10^40. The top value of 93 | c the index is stored as NTOP. That becomes the point from which 94 | c the downward recurrence begins. 95 | c 96 | ntop=nterms+nextra 97 | zinv=done/z 98 | ffn = done 99 | ffnm1 = zero 100 | c 101 | nextra = 10000 102 | do 1200 i=nterms,nterms+nextra 103 | dcoef=2*i 104 | ztmp=dcoef*zinv*ffn-ffnm1 105 | ffnp1=ztmp 106 | c 107 | dd = dreal(ztmp)**2 + dimag(ztmp)**2 108 | if (dd .gt. upbound2) then 109 | ntop=i+1 110 | goto 1300 111 | endif 112 | ffnm1 = ffn 113 | ffn = ffnp1 114 | 1200 continue 115 | 1300 continue 116 | allocate(iscale(0:ntop)) 117 | allocate(fjtemp(0:ntop)) 118 | c 119 | c ... Step 2: Recursion back down to generate the unscaled jfuns: 120 | c This is the stable but growing direction for the recurrence. 121 | c To avoid overflow, if the magnitude exceeds UPBOUND2, 122 | c we rescale and continue the recursion (saving the order 123 | c at which rescaling occurred in array iscale for subsequent 124 | c correction). 125 | c 126 | do i=0,ntop 127 | iscale(i)=0 128 | enddo 129 | c 130 | fjtemp(ntop)=zero 131 | fjtemp(ntop-1)=done 132 | do i=ntop-1,1,-1 133 | dcoef=2*i 134 | ztmp=dcoef*zinv*fjtemp(i)-fjtemp(i+1) 135 | fjtemp(i-1)=ztmp 136 | c 137 | dd = dreal(ztmp)**2 + dimag(ztmp)**2 138 | if (dd.gt.upbound2) then 139 | fjtemp(i) = fjtemp(i)*upbound2inv 140 | fjtemp(i-1) = fjtemp(i-1)*upbound2inv 141 | iscale(i) = 1 142 | endif 143 | enddo 144 | c 145 | c ... Step 3: go back up to the top and make sure that all 146 | c Bessel functions are scaled by the same factor 147 | c (i.e. the net total of times rescaling was invoked 148 | c on the way down in the previous loop). 149 | c At the same time, add scaling to fjs array. 150 | c 151 | ncntr=0 152 | scalinv=done/rscale 153 | sctot = 1.0d0 154 | do i=1,ntop 155 | sctot = sctot*scalinv 156 | if(iscale(i-1).eq.1) sctot=sctot*upbound2inv 157 | fjtemp(i)=fjtemp(i)*sctot 158 | enddo 159 | c 160 | c ... Determine the normalization parameter: 161 | c 162 | c From Abramowitz and Stegun (9.1.47) and (9.1.48), Euler's identity 163 | c 164 | psi = 0d0 165 | c 166 | if (dimag(z) .lt. 0) zmul = +ima 167 | if (dimag(z) .ge. 0) zmul = -ima 168 | zsn = zmul**(mod(ntop,4)) 169 | c 170 | zmulinv=1/zmul 171 | do i = ntop,1,-1 172 | psi = rscale*psi+fjtemp(i)*zsn 173 | zsn = zsn*zmulinv 174 | enddo 175 | psi = 2*psi*rscale+fjtemp(0) 176 | c 177 | if (dimag(z) .lt. 0) zscale = cdexp(+ima*z) / psi 178 | if (dimag(z) .ge. 0) zscale = cdexp(-ima*z) / psi 179 | c 180 | c 181 | c ... Scale the jfuns by zscale: 182 | c 183 | ztmp=zscale 184 | do i=0,nterms 185 | fjs(i)=fjtemp(i)*ztmp 186 | enddo 187 | c 188 | c ... Finally, calculate the derivatives if desired: 189 | c 190 | if (ifder.eq.1) then 191 | fjs(nterms+1)=fjtemp(nterms+1)*ztmp 192 | c 193 | fjder(0)=-fjs(1)*rscale 194 | dc1=0.5d0 195 | dc2=done-dc1 196 | dc1=dc1*scalinv 197 | dc2=dc2*rscale 198 | do i=1,nterms 199 | fjder(i)=dc1*fjs(i-1)-dc2*fjs(i+1) 200 | enddo 201 | endif 202 | return 203 | end 204 | c 205 | -------------------------------------------------------------------------------- /src/common/cumsum.f: -------------------------------------------------------------------------------- 1 | c Copyright (C) 2020-2021: The Simons Fonudation, Inc., Travis Askham, 2 | c Michael O'Neil, and Felipe Vico. 3 | c 4 | c This file contains the following user callable 5 | c routines: 6 | c 7 | c * cumsum: 8 | c computes the cumulative sum (aka prefix 9 | c sum or scan) of an array of integers. This code 10 | c does some memory management and basic decision 11 | c making around parallelism, which is hidden from 12 | c the caller 13 | c 14 | c Advanced user interfaces: 15 | c****************************** 16 | c Note for developers: the prefix sum for integer 17 | c arrays on a shared memory machine can be memory 18 | c bound and performance changes significantly depending 19 | c on the speed and size of the L1,L2, and L3 cache 20 | c on chip. Thus, the performance of the parallel code 21 | c typically exhibits non-monotonic behavior. The efficiency 22 | c increases with the length of the vectors as the 23 | c overhead is ammortized but then the memory bound 24 | c effects kicks in for larger vectors. The best-case 25 | c improvement is nthreads/2, though it is observed 26 | c only for the appropriate length vectors. 27 | c****************************** 28 | c 29 | c cumsum1 - same as cumsum but forces the serial 30 | c code 31 | c 32 | c cumsum_para - openmp implementation of parallel 33 | c cumulative sum 34 | c 35 | c 36 | 37 | 38 | 39 | subroutine cumsum(n,a,b) 40 | c 41 | c-------------------------- 42 | c This subroutine computes the cumulative sum 43 | c (aka prefix sum aka scan) of the vector a and 44 | c returns in the result in b. i.e. 45 | c 46 | c b(i) = sum_{j\leq i} a(j) for i = 1,...,n 47 | c 48 | c This is the memory management routine with 49 | c the work done by either cumsum1 in serial or 50 | c cumsum_para in parallel 51 | c 52 | c Input arguments: 53 | c 54 | c - n: integer 55 | c length of a and b 56 | c - a: integer(n) 57 | c the array to perform cumulative sum on 58 | c 59 | c Output arguments: 60 | c 61 | c - b: integer(n) 62 | c the resulting cumulative sum array 63 | c-------------------------- 64 | c 65 | c 66 | implicit none 67 | integer, intent(in) :: n,a(n) 68 | integer, intent(out) :: b(n) 69 | 70 | integer lend, nsmall, maxth, offset 71 | parameter (lend = 200) 72 | integer d(lend) 73 | integer, allocatable :: d2(:) 74 | c$ integer omp_get_max_threads 75 | data nsmall / 10000 / 76 | 77 | c if small problem, don't do parallel 78 | if (n .lt. nsmall) goto 300 79 | 80 | c get upper bound of number of threads on hand 81 | 82 | maxth = 1 83 | c$ maxth = omp_get_max_threads() 84 | 85 | c no benefit to parallelize if only 2 threads 86 | if (maxth .le. 2) goto 300 87 | 88 | c if not a ton of processors, use d on stack 89 | if (maxth .le. lend) goto 200 90 | 91 | c if tons of processors, allocate d2 92 | allocate(d2(maxth)) 93 | call cumsum_para(n,a,b,maxth,d2) 94 | return 95 | 96 | 200 continue 97 | 98 | call cumsum_para(n,a,b,lend,d) 99 | return 100 | 101 | 300 continue 102 | 103 | call cumsum1(n,a,b) 104 | return 105 | 106 | end 107 | c 108 | c 109 | subroutine cumsum1(n,a,b) 110 | c 111 | c-------------------------- 112 | c This subroutine computes the cumulative sum 113 | c (aka prefix sum aka scan) of the vector a and 114 | c returns in the result in b. i.e. 115 | c 116 | c b(i) = sum_{j\leq i} a(j) for i = 1,...,n 117 | c 118 | c This is the serial version of the code. 119 | c 120 | c Input arguments: 121 | c 122 | c - n: integer 123 | c length of a and b 124 | c - a: integer(n) 125 | c the array to perform cumulative sum on 126 | c 127 | c Output arguments: 128 | c 129 | c - b: integer(n) 130 | c the resulting cumulative sum array 131 | c-------------------------- 132 | c 133 | 134 | implicit none 135 | integer, intent(in) :: n,a(n) 136 | integer, intent(out) :: b(n) 137 | 138 | integer i,isum 139 | 140 | isum = 0 141 | 142 | do i=1,n 143 | isum = isum + a(i) 144 | b(i) = isum 145 | enddo 146 | 147 | return 148 | end 149 | c 150 | 151 | subroutine cumsum_para(n,a,b,nd,d) 152 | c 153 | c 154 | c-------------------------- 155 | c This subroutine computes the cumulative sum 156 | c (aka prefix sum aka scan) of the vector a and 157 | c returns in the result in b. i.e. 158 | c 159 | c b(i) = sum_{j\leq i} a(j) for i = 1,...,n 160 | c 161 | c This is the openmp parallel version of the code 162 | c 163 | c Input arguments: 164 | c 165 | c - n: integer 166 | c length of a and b 167 | c - a: integer(n) 168 | c the array to perform cumulative sum on 169 | c - nd: integer 170 | c length of the work array d, nd should be larger 171 | c than the number of threads to be used 172 | c 173 | c Output arguments: 174 | c 175 | c - b: integer(n) 176 | c the resulting cumulative sum array 177 | c - d: integer(nd) 178 | c work array of length nd, nd should be larger than 179 | c the number of threads to be used 180 | c-------------------------- 181 | c 182 | c WARNING: this subroutine depends on the properties 183 | c of the "static" schedule in the OPENMP 184 | c specification. Specifically, the static schedule 185 | c with no chunk_size specified assigns at most one 186 | c block of iterates to each thread in thread order. 187 | c The assignment of indices is the same for any do 188 | c loops of the same cardinality within a parallel 189 | c region. Changing the schedule will make the code non 190 | c conforming. 191 | c 192 | implicit none 193 | integer, intent(in) :: n,a(n),nd 194 | integer, intent(out) :: b(n),d(nd) 195 | 196 | integer i,isum,offset 197 | integer nth, id, inext 198 | c$ integer omp_get_thread_num, omp_get_num_threads 199 | 200 | 201 | c$OMP PARALLEL DEFAULT(none) SHARED(a,b,n,d) 202 | c$OMP$ PRIVATE(i,isum,offset,id,inext,nth) 203 | 204 | id = 1 205 | c$ id = omp_get_thread_num()+1 206 | 207 | c compute cumulative sums of portions (parallel) 208 | 209 | 210 | isum = 0 211 | c$OMP DO SCHEDULE(static) 212 | do i = 1,n 213 | isum = isum+a(i) 214 | b(i) = isum 215 | enddo 216 | c$OMP END DO no wait 217 | d(id) = isum 218 | 219 | c$OMP BARRIER 220 | 221 | c accumulate the ends of the partial sums (each thread) 222 | 223 | offset = 0 224 | do i = 1,id-1 225 | offset = offset + d(i) 226 | enddo 227 | 228 | c$OMP DO SCHEDULE(static) 229 | do i = 1,n 230 | b(i) = b(i) + offset 231 | enddo 232 | c$OMP END DO no wait 233 | 234 | c$OMP END PARALLEL 235 | 236 | return 237 | end 238 | c 239 | 240 | -------------------------------------------------------------------------------- /src/common/dlaran.f: -------------------------------------------------------------------------------- 1 | DOUBLE PRECISION FUNCTION DLARAN( ISEED ) 2 | * 3 | * -- LAPACK auxiliary routine (version 3.0) -- 4 | * Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., 5 | * Courant Institute, Argonne National Lab, and Rice University 6 | * February 29, 1992 7 | * 8 | * .. Array Arguments .. 9 | INTEGER ISEED( 4 ) 10 | * .. 11 | * 12 | * Purpose 13 | * ======= 14 | * 15 | * DLARAN returns a random real number from a uniform (0,1) 16 | * distribution. 17 | * 18 | * Arguments 19 | * ========= 20 | * 21 | * ISEED (input/output) INTEGER array, dimension (4) 22 | * On entry, the seed of the random number generator; the array 23 | * elements must be between 0 and 4095, and ISEED(4) must be 24 | * odd. 25 | * On exit, the seed is updated. 26 | * 27 | * Further Details 28 | * =============== 29 | * 30 | * This routine uses a multiplicative congruential method with modulus 31 | * 2**48 and multiplier 33952834046453 (see G.S.Fishman, 32 | * 'Multiplicative congruential random number generators with modulus 33 | * 2**b: an exhaustive analysis for b = 32 and a partial analysis for 34 | * b = 48', Math. Comp. 189, pp 331-344, 1990). 35 | * 36 | * 48-bit integers are stored in 4 integer array elements with 12 bits 37 | * per element. Hence the routine is portable across machines with 38 | * integers of 32 bits or more. 39 | * 40 | * ===================================================================== 41 | * 42 | * .. Parameters .. 43 | INTEGER M1, M2, M3, M4 44 | PARAMETER ( M1 = 494, M2 = 322, M3 = 2508, M4 = 2549 ) 45 | DOUBLE PRECISION ONE 46 | PARAMETER ( ONE = 1.0D+0 ) 47 | INTEGER IPW2 48 | DOUBLE PRECISION R 49 | PARAMETER ( IPW2 = 4096, R = ONE / IPW2 ) 50 | * .. 51 | * .. Local Scalars .. 52 | INTEGER IT1, IT2, IT3, IT4 53 | * .. 54 | * .. Intrinsic Functions .. 55 | INTRINSIC DBLE, MOD 56 | * .. 57 | * .. Executable Statements .. 58 | * 59 | * multiply the seed by the multiplier modulo 2**48 60 | * 61 | IT4 = ISEED( 4 )*M4 62 | IT3 = IT4 / IPW2 63 | IT4 = IT4 - IPW2*IT3 64 | IT3 = IT3 + ISEED( 3 )*M4 + ISEED( 4 )*M3 65 | IT2 = IT3 / IPW2 66 | IT3 = IT3 - IPW2*IT2 67 | IT2 = IT2 + ISEED( 2 )*M4 + ISEED( 3 )*M3 + ISEED( 4 )*M2 68 | IT1 = IT2 / IPW2 69 | IT2 = IT2 - IPW2*IT1 70 | IT1 = IT1 + ISEED( 1 )*M4 + ISEED( 2 )*M3 + ISEED( 3 )*M2 + 71 | $ ISEED( 4 )*M1 72 | IT1 = MOD( IT1, IPW2 ) 73 | * 74 | * return updated seed 75 | * 76 | ISEED( 1 ) = IT1 77 | ISEED( 2 ) = IT2 78 | ISEED( 3 ) = IT3 79 | ISEED( 4 ) = IT4 80 | * 81 | * convert 48-bit integer to a real number in the interval (0,1) 82 | * 83 | DLARAN = R*( DBLE( IT1 )+R*( DBLE( IT2 )+R*( DBLE( IT3 )+R* 84 | $ ( DBLE( IT4 ) ) ) ) ) 85 | RETURN 86 | * 87 | * End of DLARAN 88 | * 89 | END 90 | -------------------------------------------------------------------------------- /src/common/fmmcommon2d.f: -------------------------------------------------------------------------------- 1 | c---------------------------------------------------------------- 2 | 3 | subroutine ireorderf(ndim,n,arr,arrsort,iarr) 4 | c 5 | cc this subroutine sorts the array arr and stores 6 | c it in arrsort using the sorting order defined by 7 | c iarr 8 | c 9 | c arrsort(j,i) = arr(j,iarr(i)), j =1,2,\ldots ndim 10 | c i=1,2,\ldots n 11 | c 12 | 13 | implicit none 14 | integer ndim,idim,i,n 15 | integer arr(ndim,n),arrsort(ndim,n) 16 | integer iarr(n) 17 | 18 | C$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(i,idim) 19 | do i=1,n 20 | do idim=1,ndim 21 | arrsort(idim,i) = arr(idim,iarr(i)) 22 | enddo 23 | enddo 24 | C$OMP END PARALLEL DO 25 | 26 | return 27 | end 28 | c---------------------------------------------------------------- 29 | 30 | subroutine dreorderf(ndim,n,arr,arrsort,iarr) 31 | c 32 | cc this subroutine sorts the array arr and stores 33 | c it in arrsort using the sorting order defined by 34 | c iarr 35 | c 36 | c arrsort(j,i) = arr(j,iarr(i)), j =1,2,\ldots ndim 37 | c i=1,2,\ldots n 38 | c 39 | 40 | implicit none 41 | integer ndim,idim,i,n 42 | double precision arr(ndim,n),arrsort(ndim,n) 43 | integer iarr(n) 44 | 45 | C$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(i,idim) 46 | do i=1,n 47 | do idim=1,ndim 48 | arrsort(idim,i) = arr(idim,iarr(i)) 49 | enddo 50 | enddo 51 | C$OMP END PARALLEL DO 52 | 53 | return 54 | end 55 | c-------------------------------------------------- 56 | subroutine dreorderi(ndim,n,arr,arrsort,iarr) 57 | c 58 | cc this subroutine sorts the array arr and stores 59 | c it in arrsort using the inverse of the 60 | c sorting order defined by 61 | c iarr. 62 | c 63 | c Note that this subroutine is the inverse of 64 | c dreorderf 65 | c 66 | c arrsort(j,iarr(i)) = arr(j,i), j =1,2,\ldots ndim 67 | c i=1,2,\ldots n 68 | c 69 | 70 | implicit none 71 | integer i,idim,ndim,n 72 | double precision arr(ndim,1),arrsort(ndim,1) 73 | integer iarr(1) 74 | 75 | C$OMP PARALLEL DO DEFAULT(SHARED) PRIVATE(i,idim) 76 | do i=1,n 77 | do idim=1,ndim 78 | arrsort(idim,iarr(i)) = arr(idim,i) 79 | enddo 80 | enddo 81 | C$OMP END PARALLEL DO 82 | 83 | return 84 | end 85 | c---------------------------------------------------------- 86 | 87 | c 88 | c------------------------------------------------------- 89 | subroutine geterrstr(ifcharge,ifdipole,ifpgh,ifpghtarg,str1,len1) 90 | implicit real *8 (a-h,o-z) 91 | character(len=*) str1 92 | character(len=13) str2 93 | character(len=14) str3 94 | character(len=19) str4 95 | character(len=30) str5 96 | 97 | str2 = "Failed src to" 98 | len1 = 13 99 | if(ifpgh.gt.0.and.ifpghtarg.eq.0) then 100 | str3 = " src," 101 | len1 = len1+5 102 | endif 103 | if(ifpgh.eq.0.and.ifpghtarg.gt.0) then 104 | str3 = " targ," 105 | len1 = len1+6 106 | endif 107 | if(ifpgh.gt.0.and.ifpghtarg.gt.0) then 108 | str3 = " src and targ," 109 | len1 = len1+14 110 | endif 111 | 112 | if(ifcharge.eq.1.and.ifdipole.eq.0) then 113 | str4=" charge," 114 | len1 = len1+8 115 | endif 116 | 117 | if(ifcharge.eq.0.and.ifdipole.eq.1) then 118 | str4=" dipole," 119 | len1 = len1+8 120 | endif 121 | 122 | if(ifcharge.eq.1.and.ifdipole.eq.1) then 123 | str4=" charge and dipole," 124 | len1 = len1+19 125 | endif 126 | 127 | if(ifpgh.eq.1.or.ifpghtarg.eq.1) then 128 | str5=" pot test" 129 | len1 = len1 + 9 130 | endif 131 | 132 | if(ifpgh.eq.2.or.ifpghtarg.eq.2) then 133 | str5=" pot and grad test" 134 | len1 = len1 + 18 135 | endif 136 | 137 | if(ifpgh.eq.3.or.ifpghtarg.eq.3) then 138 | str5=" pot, grad, and hess test" 139 | len1 = len1+25 140 | endif 141 | 142 | str1 = str2//trim(str3)//trim(str4)//trim(str5) 143 | 144 | return 145 | end 146 | 147 | c 148 | c 149 | c 150 | subroutine init_carray(carray,ldc) 151 | implicit real *8 (a-h,o-z) 152 | real *8 carray(0:ldc,0:ldc) 153 | 154 | do l = 0,ldc 155 | carray(l,0) = 1.0d0 156 | enddo 157 | do m=1,ldc 158 | carray(m,m) = 1.0d0 159 | do l=m+1,ldc 160 | carray(l,m)=carray(l-1,m)+carray(l-1,m-1) 161 | enddo 162 | enddo 163 | c 164 | return 165 | end 166 | 167 | -------------------------------------------------------------------------------- /src/common/hkrand.f: -------------------------------------------------------------------------------- 1 | c 2 | c 3 | real *8 function hkrand(iseed_hk) 4 | implicit real *8 (a-h,o-z) 5 | dimension iseed(4) 6 | data iseed/0,0,0,1/ 7 | save 8 | c 9 | if( iseed_hk .ne. 0 ) then 10 | iseed(1)=0 11 | iseed(2)=0 12 | iseed(3)=0 13 | iseed(4)=mod(2*iseed_hk+1,4096) 14 | endif 15 | c 16 | hkrand=dlaran(iseed) 17 | c 18 | return 19 | end 20 | -------------------------------------------------------------------------------- /src/common/next235.f: -------------------------------------------------------------------------------- 1 | ************************************************************************ 2 | function next235(base) 3 | implicit none 4 | integer :: next235, numdiv 5 | double precision :: base 6 | c ---------------------------------------------------------------------- 7 | c integer function next235 returns a multiple of 2, 3, and 5 8 | c 9 | c next235 = 2^p 3^q 5^r >= base where p>=1, q>=0, r>=0 10 | ************************************************************************ 11 | next235 = 2 * int(base/2d0+.9999d0) 12 | if (next235.le.0) next235 = 2 13 | 14 | 100 numdiv = next235 15 | do while (numdiv/2*2 .eq. numdiv) 16 | numdiv = numdiv /2 17 | enddo 18 | do while (numdiv/3*3 .eq. numdiv) 19 | numdiv = numdiv /3 20 | enddo 21 | do while (numdiv/5*5 .eq. numdiv) 22 | numdiv = numdiv /5 23 | enddo 24 | if (numdiv .eq. 1) return 25 | next235 = next235 + 2 26 | goto 100 27 | end 28 | 29 | -------------------------------------------------------------------------------- /src/helmholtz/h2dcommon.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2010-2011: Leslie Greengard and Zydrunas Gimbutas 2 | cc Contact: greengard@cims.nyu.edu 3 | c 4 | c Modified: (C) 2019, Leslie Greengard 5 | cc 6 | cc This program is free software; you can redistribute it and/or modify 7 | cc it under the terms of the GNU General Public License as published by 8 | cc the Free Software Foundation; either version 2 of the License, or 9 | cc (at your option) any later version. This program is distributed in 10 | cc the hope that it will be useful, but WITHOUT ANY WARRANTY; without 11 | cc even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 | cc PARTICULAR PURPOSE. See the GNU General Public License for more 13 | cc details. You should have received a copy of the GNU General Public 14 | cc License along with this program; 15 | cc if not, see . 16 | ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc 17 | c 18 | c This file contains the basic subroutines for 19 | c forming and evaluating multipole (partial wave) expansions 20 | c in two dimensions. 21 | c 22 | c Remarks on scaling conventions. 23 | c 24 | c 1) Hankel and Bessel functions are consistently scaled as 25 | c hvec(n)= H_n(z)*rscale^(n) 26 | c jvec(n)= J_n(z)/rscale^(n) 27 | c 28 | c rscale should be of the order of |z| if |z| < 1. Otherwise, 29 | c rscale should be set to 1. 30 | c 31 | c 2) The potential scaling is that required of the delta function 32 | c response: pot = H_0(k*r)*(eye/4) 33 | c 34 | c----------------------------------------------------------------------- 35 | c 36 | c 37 | c 38 | c 39 | c 40 | c********************************************************************** 41 | subroutine h2cart2polar(zat,r,theta) 42 | implicit none 43 | c********************************************************************** 44 | c 45 | c Convert from Cartesian to polar coordinates. 46 | c----------------------------------------------------------------------- 47 | c INPUT: 48 | c 49 | c zat : Cartesian vector 50 | c----------------------------------------------------------------------- 51 | c OUTPUT: 52 | c 53 | c r : |zat| 54 | c theta : angle of (zat(1),zat(2)) subtended with 55 | c respect to x-axis 56 | c----------------------------------------------------------------------- 57 | real *8 zat(2),r,theta 58 | c 59 | r= sqrt(zat(1)**2+zat(2)**2) 60 | if( abs(zat(1)) .eq. 0 .and. abs(zat(2)) .eq. 0 ) then 61 | theta = 0 62 | else 63 | theta = datan2(zat(2),zat(1)) 64 | endif 65 | return 66 | end 67 | c 68 | c 69 | c 70 | c********************************************************************** 71 | subroutine h2dall(nterms,z,rscale,hvec,ifder,hder) 72 | implicit none 73 | c********************************************************************** 74 | c 75 | c This subroutine computes scaled versions of the Hankel 76 | c functions H_n of orders 0 to nterms. 77 | c 78 | c hvec(n)= H_n(z)*rscale^(n) 79 | c 80 | c The parameter SCALE is useful when |z| < 1, in which case 81 | c it damps out the rapid growth of H_n as n increases. In such 82 | c cases, we recommend setting 83 | c 84 | c rscale approx |z| 85 | c 86 | c or something close. If |z| > 1, set scale = 1. 87 | c 88 | c If the flag IFDER is set to one, it also computes the 89 | c derivatives of h_n. 90 | c 91 | c hder(n)= H_n'(z)*rscale^(n) 92 | c 93 | c NOTE: If |z| < 1.0d-200, the subroutine returns zero. 94 | c 95 | c----------------------------------------------------------------------- 96 | c INPUT: 97 | c 98 | c nterms : highest order of the Hankel functions to be computed. 99 | c z : argument of the Hankel functions. 100 | c rscale : scaling parameter discussed above 101 | c ifder : 1 => compute hder array, otherwise do not 102 | c----------------------------------------------------------------------- 103 | c OUTPUT: 104 | c 105 | c hvec : the vector of Hankel functions 106 | c hder : the derivatives of the Hankel functions 107 | c----------------------------------------------------------------------- 108 | integer i,ifexpon,ifder,nterms 109 | real *8 thresh,done,rscale,scal2,dtmp 110 | complex *16 hvec(0:*),hder(0:*) 111 | complex *16 zk2,z,zinv,ztmp,fhextra,h0,h1 112 | c 113 | data thresh/1.0d-200/,done/1.0d0/ 114 | c 115 | c If |z| < thresh, return zeros. 116 | c 117 | if (abs(z).lt.thresh) then 118 | do i=0,nterms 119 | hvec(i)=0 120 | hder(i)=0 121 | enddo 122 | return 123 | endif 124 | c 125 | c Otherwise, get H_0 and H_1 via hank103 and the rest via 126 | c recursion. 127 | c 128 | ifexpon=1 129 | call hank103(z,h0,h1,ifexpon) 130 | hvec(0)=h0 131 | hvec(1)=h1*rscale 132 | c 133 | c 134 | c From Abramowitz and Stegun (9.1.27) 135 | c 136 | c H_{n-1}(z) + H_{n+1}(z) = 2*n/z * H_n(z) 137 | c 138 | c With scaling: 139 | c 140 | c H_{n-1}(z) *rscale + H_{n+1}(z)/rscale = 2*n/z * H_n(z) 141 | c H_{n+1}(z) = rscale*(2*n/z*H_n(z) - H_{n-1}(z)*rscale) 142 | c 143 | scal2=rscale*rscale 144 | zinv=rscale/z 145 | do i=1,nterms-1 146 | dtmp=2*i 147 | ztmp=zinv*dtmp 148 | hvec(i+1)=ztmp*hvec(i)-scal2*hvec(i-1) 149 | enddo 150 | c 151 | c 152 | c From Abramowitz and Stegun (9.1.27) 153 | c 154 | c H_{n}'(z)= H_{n-1}(z) - (n)/z * H_n(z) 155 | c 156 | c With scaling: 157 | c 158 | c hder(n)=scale* hvec(n-1) - n/z * hvec(n) 159 | c 160 | if (ifder.eq.1) then 161 | c 162 | hder(0)=-hvec(1)/rscale 163 | zinv=1.0d0/z 164 | do i=1,nterms 165 | dtmp=(i) 166 | ztmp=zinv*dtmp 167 | hder(i)=rscale*hvec(i-1)-ztmp*hvec(i) 168 | enddo 169 | c 170 | endif 171 | c 172 | return 173 | end 174 | c 175 | c 176 | c 177 | c 178 | c 179 | C*********************************************************************** 180 | subroutine h2dmpzero(nd,mpole,nterms) 181 | implicit none 182 | C*********************************************************************** 183 | c 184 | c This subroutine sets a multipole expansion to zero. 185 | c----------------------------------------------------------------------- 186 | c INPUT: 187 | c 188 | c nd : number of expansions 189 | c nterms : order of multipole expansion 190 | C--------------------------------------------------------------------- 191 | c OUTPUT: 192 | c 193 | c mpole : coeffs for the expansion set to zero. 194 | C--------------------------------------------------------------------- 195 | integer n,nterms,nd,idim 196 | complex *16 mpole(nd,-nterms:nterms) 197 | c 198 | do n=-nterms,nterms 199 | do idim=1,nd 200 | mpole(idim,n)=0.0d0 201 | enddo 202 | enddo 203 | return 204 | end 205 | c 206 | c 207 | c---------------------------------------------------------------- 208 | c 209 | c 210 | C*********************************************************************** 211 | subroutine h2dsigzero(nd,sig,nsig) 212 | implicit none 213 | C*********************************************************************** 214 | c 215 | c This subroutine sets a signature expansion to zero. 216 | c----------------------------------------------------------------------- 217 | c INPUT: 218 | c 219 | c nd : number of expansions 220 | c nsig : order of multipole expansion 221 | C--------------------------------------------------------------------- 222 | c OUTPUT: 223 | c 224 | c sigmpole : coeffs for the expansion set to zero. 225 | C--------------------------------------------------------------------- 226 | integer n,nsig,nd,idim 227 | complex *16 sig(nd,nsig) 228 | c 229 | do n=1,nsig 230 | do idim=1,nd 231 | sig(idim,n)=0.0d0 232 | enddo 233 | enddo 234 | return 235 | end 236 | c 237 | c 238 | -------------------------------------------------------------------------------- /src/helmholtz/hndiv2d.f: -------------------------------------------------------------------------------- 1 | subroutine hndiv2d(eps,ns,nt,ifcharge,ifdipole,ifpgh, 2 | 1 ifpghtarg,ndiv,idivflag) 3 | c 4 | c 5 | c this subroutine estimates ndiv and idivflag 6 | c based on geometry parameters 7 | c 8 | c 9 | implicit none 10 | real *8 eps 11 | integer ns,nt,ifcharge,ifdipole,ifpgh,ifpghtarg,ndiv 12 | integer idivflag 13 | 14 | idivflag = 0 15 | 16 | 17 | if(eps.ge.0.5d-0) then 18 | ndiv = 3 19 | else if(eps.ge.0.5d-1) then 20 | ndiv = 5 21 | else if(eps.ge.0.5d-2) then 22 | ndiv = 8 23 | else if(eps.ge.0.5d-3) then 24 | ndiv = 10 25 | else if(eps.ge.0.5d-6) then 26 | ndiv = 15 27 | else if(eps.ge.0.5d-9) then 28 | ndiv = 20 29 | else if(eps.ge.0.5d-12) then 30 | ndiv = 25 31 | else if(eps.ge.0.5d-15) then 32 | ndiv = 45 33 | else 34 | ndiv = ns+nt 35 | endif 36 | 37 | 38 | return 39 | end 40 | -------------------------------------------------------------------------------- /src/helmholtz_c.f03: -------------------------------------------------------------------------------- 1 | module c_helmholtz 2 | use iso_c_binding 3 | contains 4 | subroutine c_hfmm2d_s_c_p(eps, zk, ns, sources, charge, pot, ier) & 5 | bind(c, name='hfmm2d_s_c_p') 6 | implicit none 7 | real(c_double), value :: eps 8 | complex(c_double_complex), value, intent(in) :: zk 9 | integer(c_int64_t), value :: ns 10 | real(c_double), intent(in) :: sources(2, ns) 11 | complex(c_double_complex), intent(in) :: charge(ns) 12 | complex(c_double_complex), intent(out) :: pot(ns) 13 | integer(c_int64_t), intent(out) :: ier 14 | call hfmm2d_s_c_p(eps, zk, ns, sources, charge, pot, ier) 15 | end subroutine c_hfmm2d_s_c_p 16 | end module c_helmholtz 17 | -------------------------------------------------------------------------------- /src/laplace/lndiv2d.f: -------------------------------------------------------------------------------- 1 | subroutine lndiv2d(eps,ns,nt,ifcharge,ifdipole,ifpgh, 2 | 1 ifpghtarg,ndiv,idivflag) 3 | c 4 | c 5 | c this subroutine estimates ndiv and idivflag 6 | c based on geometry parameters 7 | c 8 | c 9 | implicit none 10 | real *8 eps 11 | integer ns,nt,ifcharge,ifdipole,ifpgh,ifpghtarg,ndiv 12 | integer idivflag 13 | 14 | idivflag = 0 15 | 16 | 17 | if(eps.ge.0.5d-0) then 18 | ndiv = 3 19 | else if(eps.ge.0.5d-1) then 20 | ndiv = 5 21 | else if(eps.ge.0.5d-2) then 22 | ndiv = 8 23 | else if(eps.ge.0.5d-3) then 24 | ndiv = 10 25 | else if(eps.ge.0.5d-6) then 26 | ndiv = 15 27 | else if(eps.ge.0.5d-9) then 28 | ndiv = 20 29 | else if(eps.ge.0.5d-12) then 30 | ndiv = 25 31 | else if(eps.ge.0.5d-15) then 32 | ndiv = 45 33 | else 34 | ndiv = ns+nt 35 | endif 36 | 37 | 38 | return 39 | end 40 | -------------------------------------------------------------------------------- /src/laplace/rfmm2d_ndiv.f: -------------------------------------------------------------------------------- 1 | cc Copyright (C) 2018-2019: Leslie Greengard, Zydrunas Gimbutas, 2 | cc and Manas Rachh 3 | cc Contact: greengard@cims.nyu.edu 4 | cc 5 | cc 6 | cc This program is free software; you can redistribute it and/or modify 7 | cc it under the terms of the GNU General Public License as published by 8 | cc the Free Software Foundation; either version 2 of the License, or 9 | cc (at your option) any later version. This program is distributed in 10 | cc the hope that it will be useful, but WITHOUT ANY WARRANTY; without 11 | cc even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 | cc PARTICULAR PURPOSE. See the GNU General Public License for more 13 | cc details. You should have received a copy of the GNU General Public 14 | cc License along with this program; 15 | cc if not, see . 16 | ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc 17 | c 18 | cc 2021/07/07: convert to proper Laplace FMM, calls Cauchy FMM 19 | cc Travis Askham 20 | c 21 | c 22 | c This is the Laplace FMM with real-valued charges and 23 | c dipole strengths. 24 | c 25 | c 26 | 27 | subroutine rfmm2d_ndiv(nd,eps,ns,sources,ifcharge,charge, 28 | 1 ifdipole,dipstr,dipvec,iper,ifpgh,pot,grad,hess, 29 | 2 nt,targ,ifpghtarg,pottarg,gradtarg, 30 | 3 hesstarg,ndiv,idivflag,ifnear,timeinfo,ier) 31 | c---------------------------------------------- 32 | c INPUT PARAMETERS: 33 | c nd : number of expansions 34 | c eps : FMM precision requested 35 | c ns : number of sources 36 | c sources(2,ns) : source locations 37 | c ifcharge : flag for including charge interactions 38 | c charge interactions included if ifcharge =1 39 | c not included otherwise 40 | c charge(nd,ns) : charge strengths 41 | c ifdipole : flag for including dipole interactions 42 | c dipole interactions included if ifcharge =1 43 | c not included otherwise 44 | c dipstr(nd,ns) : dipole strengths 45 | c dipvec(nd,2,ns) : dipole strengths 46 | c iper : flag for periodic implmentations. Currently unused 47 | c ifpgh : flag for computing pot/grad/hess 48 | c ifpgh = 1, only potential is computed 49 | c ifpgh = 2, potential and gradient are computed 50 | c ifpgh = 3, potential, gradient, and hessian 51 | c are computed 52 | c nt : number of targets 53 | c targ(2,nt) : target locations 54 | c ifpghtarg : flag for computing pottarg/gradtarg/hesstarg 55 | c ifpghtarg = 1, only potential is computed at targets 56 | c ifpghtarg = 2, potential and gradient are 57 | c computed at targets 58 | c ifpghtarg = 3, potential, gradient, and hessian are 59 | c computed at targets 60 | c ndiv : subdivision criterion, number of points of box 61 | c idivflag : subdivision criterion, whether to use sources, targets 62 | c 63 | c OUTPUT PARAMETERS 64 | c pot(nd,*) : potential at the source locations 65 | c grad(nd,2,*) : gradients at the source locations 66 | c hess(nd,3,*) : hessian at the source locations 67 | c pottarg(nd,*) : potential at the target locations 68 | c gradtarg(nd,2,*): gradient at the target locations 69 | c hesstarg(nd,3,*): hessian at the target locations 70 | c 71 | c timeinfo : time distribution 72 | c ier : error code 73 | 74 | 75 | implicit none 76 | c 77 | cc calling sequence variables 78 | c 79 | integer nd 80 | real *8 omp_get_wtime 81 | real *8 eps 82 | integer ns,nt,iper 83 | real *8 sources(2,ns),targ(2,nt) 84 | real *8 charge(nd,*),dipstr(nd,*) 85 | real *8 dipvec(nd,2,*) 86 | 87 | real *8 pot(nd,*),grad(nd,2,*),hess(nd,3,*) 88 | real *8 pottarg(nd,*),gradtarg(nd,2,*),hesstarg(nd,3,*) 89 | 90 | integer ifcharge,ifdipole 91 | integer ifpgh,ifpghtarg,ifprint,ier 92 | real *8 time1,time2,pi,done 93 | 94 | complex *16, allocatable, dimension(:,:) :: pot1,grad1,hess1, 95 | 1 pottarg1,gradtarg1,hesstarg1,charge1,dipstr1 96 | 97 | integer i,j,nd2 98 | integer ndiv,idivflag,ifnear 99 | real *8 timeinfo(8) 100 | 101 | complex *16 :: eye, ztmp 102 | data eye /(0.0d0,1.0d0)/ 103 | 104 | c allocate variables for cfmm call 105 | 106 | if (ifcharge .eq. 1) then 107 | allocate(charge1(nd,ns)) 108 | else 109 | allocate(charge1(nd,1)) 110 | endif 111 | 112 | if (ifdipole .eq. 1) then 113 | allocate(dipstr1(nd,ns)) 114 | else 115 | allocate(dipstr1(nd,1)) 116 | endif 117 | 118 | if (ifpgh .eq. 1) then 119 | allocate(pot1(nd,ns),grad1(nd,1),hess1(nd,1)) 120 | endif 121 | if (ifpgh .eq. 2) then 122 | allocate(pot1(nd,ns),grad1(nd,ns),hess1(nd,1)) 123 | endif 124 | if (ifpgh .eq. 3) then 125 | allocate(pot1(nd,ns),grad1(nd,ns),hess1(nd,ns)) 126 | endif 127 | 128 | if (ifpghtarg .eq. 1) then 129 | allocate(pottarg1(nd,nt),gradtarg1(nd,1),hesstarg1(nd,1)) 130 | endif 131 | if (ifpghtarg .eq. 2) then 132 | allocate(pottarg1(nd,nt),gradtarg1(nd,nt), 133 | 1 hesstarg1(nd,1)) 134 | endif 135 | if (ifpghtarg .eq. 3) then 136 | allocate(pottarg1(nd,nt),gradtarg1(nd,nt), 137 | 1 hesstarg1(nd,nt)) 138 | endif 139 | 140 | c real and complex parts must be split 141 | 142 | if (ifcharge .eq. 1) then 143 | do i = 1,ns 144 | do j = 1,nd 145 | charge1(j,i) = charge(j,i) 146 | enddo 147 | enddo 148 | endif 149 | 150 | if (ifdipole .eq. 1) then 151 | do i = 1,ns 152 | do j = 1,nd 153 | ztmp = -(dipvec(j,1,i)+eye*dipvec(j,2,i)) 154 | dipstr1(j,i) = dipstr(j,i)*ztmp 155 | enddo 156 | enddo 157 | endif 158 | 159 | c cfmm does the work 160 | 161 | call cfmm2d_ndiv(nd,eps,ns,sources,ifcharge,charge1, 162 | 1 ifdipole,dipstr1,iper,ifpgh,pot1,grad1,hess1, 163 | 2 nt,targ,ifpghtarg,pottarg1,gradtarg1, 164 | 3 hesstarg1,ndiv,idivflag,ifnear,timeinfo,ier) 165 | 166 | c unpack the d/dz, d^2/dz^2 as grad/hess and 167 | c combine real and imaginary parts 168 | 169 | if (ifpgh .eq. 1 .or. ifpgh .eq. 2 .or. ifpgh .eq. 3) then 170 | do i = 1,ns 171 | do j = 1,nd 172 | pot(j,i) = dble(pot1(j,i)) 173 | enddo 174 | enddo 175 | endif 176 | if (ifpgh .eq. 2 .or. ifpgh .eq. 3) then 177 | do i = 1,ns 178 | do j = 1,nd 179 | grad(j,1,i) = dble(grad1(j,i)) 180 | grad(j,2,i) = -imag(grad1(j,i)) 181 | enddo 182 | enddo 183 | endif 184 | if (ifpgh .eq. 3) then 185 | do i = 1,ns 186 | do j = 1,nd 187 | hess(j,1,i) = dble(hess1(j,i)) 188 | hess(j,2,i) = -imag(hess1(j,i)) 189 | hess(j,3,i) = -hess(j,1,i) 190 | enddo 191 | enddo 192 | endif 193 | 194 | if (ifpghtarg .eq. 1 .or. ifpghtarg .eq. 2 195 | 1 .or. ifpghtarg .eq. 3) then 196 | do i = 1,nt 197 | do j = 1,nd 198 | pottarg(j,i) = dble(pottarg1(j,i)) 199 | enddo 200 | enddo 201 | endif 202 | if (ifpghtarg .eq. 2 .or. ifpghtarg .eq. 3) then 203 | do i = 1,nt 204 | do j = 1,nd 205 | gradtarg(j,1,i) = dble(gradtarg1(j,i)) 206 | gradtarg(j,2,i) = -imag(gradtarg1(j,i)) 207 | enddo 208 | enddo 209 | endif 210 | if (ifpghtarg .eq. 3) then 211 | do i = 1,nt 212 | do j = 1,nd 213 | hesstarg(j,1,i) = dble(hesstarg1(j,i)) 214 | hesstarg(j,2,i) = -imag(hesstarg1(j,i)) 215 | hesstarg(j,3,i) = -hesstarg(j,1,i) 216 | enddo 217 | enddo 218 | endif 219 | 220 | return 221 | end 222 | c 223 | -------------------------------------------------------------------------------- /src/modified-biharmonic/jinjaroot.yaml: -------------------------------------------------------------------------------- 1 | mbhevalRouts: 2 | - 3 | out: p 4 | - 5 | out: g 6 | - 7 | out: h 8 | 9 | mbhDirectRouts: 10 | - 11 | name: mbh2d_directcp_vec 12 | ker: c 13 | out: p 14 | - 15 | name: mbh2d_directdp_vec 16 | ker: d 17 | out: p 18 | - 19 | name: mbh2d_directcdp_vec 20 | ker: cd 21 | out: p 22 | - 23 | name: mbh2d_directqp_vec 24 | ker: q 25 | out: p 26 | - 27 | name: mbh2d_directcqp_vec 28 | ker: cq 29 | out: p 30 | - 31 | name: mbh2d_directdqp_vec 32 | ker: dq 33 | out: p 34 | - 35 | name: mbh2d_directcdqp_vec 36 | ker: cdq 37 | out: p 38 | - 39 | name: mbh2d_directop_vec 40 | ker: o 41 | out: p 42 | - 43 | name: mbh2d_directcop_vec 44 | ker: co 45 | out: p 46 | - 47 | name: mbh2d_directdop_vec 48 | ker: do 49 | out: p 50 | - 51 | name: mbh2d_directcdop_vec 52 | ker: cdo 53 | out: p 54 | - 55 | name: mbh2d_directqop_vec 56 | ker: qo 57 | out: p 58 | - 59 | name: mbh2d_directcqop_vec 60 | ker: cqo 61 | out: p 62 | - 63 | name: mbh2d_directdqop_vec 64 | ker: dqo 65 | out: p 66 | - 67 | name: mbh2d_directcdqop_vec 68 | ker: cdqo 69 | out: p 70 | - 71 | name: mbh2d_directcg_vec 72 | ker: c 73 | out: g 74 | - 75 | name: mbh2d_directdg_vec 76 | ker: d 77 | out: g 78 | - 79 | name: mbh2d_directcdg_vec 80 | ker: cd 81 | out: g 82 | - 83 | name: mbh2d_directqg_vec 84 | ker: q 85 | out: g 86 | - 87 | name: mbh2d_directcqg_vec 88 | ker: cq 89 | out: g 90 | - 91 | name: mbh2d_directdqg_vec 92 | ker: dq 93 | out: g 94 | - 95 | name: mbh2d_directcdqg_vec 96 | ker: cdq 97 | out: g 98 | - 99 | name: mbh2d_directog_vec 100 | ker: o 101 | out: g 102 | - 103 | name: mbh2d_directcog_vec 104 | ker: co 105 | out: g 106 | - 107 | name: mbh2d_directdog_vec 108 | ker: do 109 | out: g 110 | - 111 | name: mbh2d_directcdog_vec 112 | ker: cdo 113 | out: g 114 | - 115 | name: mbh2d_directqog_vec 116 | ker: qo 117 | out: g 118 | - 119 | name: mbh2d_directcqog_vec 120 | ker: cqo 121 | out: g 122 | - 123 | name: mbh2d_directdqog_vec 124 | ker: dqo 125 | out: g 126 | - 127 | name: mbh2d_directcdqog_vec 128 | ker: cdqo 129 | out: g 130 | - 131 | name: mbh2d_directch_vec 132 | ker: c 133 | out: h 134 | - 135 | name: mbh2d_directdh_vec 136 | ker: d 137 | out: h 138 | - 139 | name: mbh2d_directcdh_vec 140 | ker: cd 141 | out: h 142 | - 143 | name: mbh2d_directqh_vec 144 | ker: q 145 | out: h 146 | - 147 | name: mbh2d_directcqh_vec 148 | ker: cq 149 | out: h 150 | - 151 | name: mbh2d_directdqh_vec 152 | ker: dq 153 | out: h 154 | - 155 | name: mbh2d_directcdqh_vec 156 | ker: cdq 157 | out: h 158 | - 159 | name: mbh2d_directoh_vec 160 | ker: o 161 | out: h 162 | - 163 | name: mbh2d_directcoh_vec 164 | ker: co 165 | out: h 166 | - 167 | name: mbh2d_directdoh_vec 168 | ker: do 169 | out: h 170 | - 171 | name: mbh2d_directcdoh_vec 172 | ker: cdo 173 | out: h 174 | - 175 | name: mbh2d_directqoh_vec 176 | ker: qo 177 | out: h 178 | - 179 | name: mbh2d_directcqoh_vec 180 | ker: cqo 181 | out: h 182 | - 183 | name: mbh2d_directdqoh_vec 184 | ker: dqo 185 | out: h 186 | - 187 | name: mbh2d_directcdqoh_vec 188 | ker: cdqo 189 | out: h 190 | -------------------------------------------------------------------------------- /src/modified-biharmonic/jinjaroot.yaml.py: -------------------------------------------------------------------------------- 1 | 2 | fname="jinjaroot.yaml" 3 | 4 | file = open(fname,"w") 5 | 6 | file.write("mbhevalRouts:\n") 7 | file.write(" -\n") 8 | file.write(" out: p\n") 9 | file.write(" -\n") 10 | file.write(" out: g\n") 11 | file.write(" -\n") 12 | file.write(" out: h\n\n") 13 | 14 | file.write("mbhDirectRouts:\n") 15 | 16 | outs=["p","g","h"] 17 | 18 | for out in outs: 19 | for i in range(16): 20 | i1 = i % 2 21 | i2 = (i // 2) % 2 22 | i3 = (i // 4) % 2 23 | i4 = (i // 8) % 2 24 | ker = "" 25 | if (i1 == 1): ker += "c" 26 | if (i2 == 1): ker += "d" 27 | if (i3 == 1): ker += "q" 28 | if (i4 == 1): ker += "o" 29 | 30 | if ker != "": 31 | name = "mbh2d_direct"+ker+out+"_vec" 32 | file.write(" -\n") 33 | file.write(" name: " + name + "\n") 34 | file.write(" ker: " + ker + "\n") 35 | file.write(" out: " + out + "\n") 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/biharmonic/run_bhtest.sh: -------------------------------------------------------------------------------- 1 | rm -rf print_testres.txt 2 | ./int2-test-bhfmm2d 3 | mv print_testres.txt ../../print_testresbh.txt 4 | rm -rf fort.13 5 | -------------------------------------------------------------------------------- /test/biharmonic/test_bhfmm2d.f: -------------------------------------------------------------------------------- 1 | implicit real *8 (a-h,o-z) 2 | real *8, allocatable :: sources(:,:),targ(:,:) 3 | complex *16, allocatable :: charges(:,:),dip(:,:) 4 | complex *16, allocatable :: pot(:),grad(:,:),hess(:,:) 5 | complex *16, allocatable :: pottarg(:),gradtarg(:,:) 6 | complex *16, allocatable :: hesstarg(:,:) 7 | 8 | complex *16, allocatable :: potex(:),gradex(:,:) 9 | complex *16, allocatable :: hessex(:,:) 10 | complex *16, allocatable :: pottargex(:),gradtargex(:,:), 11 | 1 hesstargex(:,:) 12 | 13 | real *8 expc(100),texps(100),scj(100) 14 | 15 | integer ipass(27) 16 | 17 | complex *16 ima 18 | data ima/(0.0d0,1.0d0)/ 19 | 20 | call prini(6,13) 21 | 22 | ntests=1 23 | do i = 1,ntests 24 | ipass(i) = 0 25 | enddo 26 | 27 | done = 1 28 | pi = atan(done)*4 29 | 30 | nsrc = 9998 31 | ntarg = 9999 32 | 33 | allocate(sources(2,nsrc),charges(2,nsrc),dip(3,nsrc)) 34 | allocate(targ(2,ntarg)) 35 | allocate(pot(nsrc),grad(3,nsrc),hess(3,nsrc)) 36 | allocate(pottarg(ntarg),gradtarg(3,ntarg),hesstarg(3,ntarg)) 37 | 38 | do i=1,nsrc 39 | 40 | sources(1,i) = hkrand(0) 41 | sources(2,i) = hkrand(0) 42 | 43 | charges(1,i) = hkrand(0) + ima*hkrand(0) 44 | charges(2,i) = hkrand(0) + ima*hkrand(0) 45 | dip(1,i) = hkrand(0) + ima*hkrand(0) 46 | dip(2,i) = hkrand(0) + ima*hkrand(0) 47 | dip(3,i) = hkrand(0) + ima*hkrand(0) 48 | enddo 49 | 50 | 51 | do i=1,ntarg 52 | targ(1,i) = hkrand(0) 53 | targ(2,i) = hkrand(0) 54 | enddo 55 | 56 | nts = min(20,nsrc) 57 | ntt = min(20,ntarg) 58 | 59 | allocate(potex(nts),gradex(3,nts),hessex(3,nts)) 60 | allocate(pottargex(ntt),gradtargex(3,ntt),hesstargex(3,ntt)) 61 | 62 | eps = 0.5d-6 63 | 64 | ifcharge = 0 65 | ifdipole = 1 66 | iper = 0 67 | ifpgh = 2 68 | ifpghtarg = 2 69 | nd = 1 70 | call bhfmm2d(nd,eps,nsrc,sources,ifcharge,charges, 71 | 1 ifdipole,dip,iper,ifpgh,pot,grad,hess, 72 | 2 ntarg,targ,ifpghtarg,pottarg,gradtarg, 73 | 3 hesstarg,ier) 74 | 75 | 76 | c 77 | cc test against exact potential 78 | c 79 | call dzero(potex,2*nts) 80 | call dzero(pottargex,2*ntt) 81 | call dzero(gradex,6*nts) 82 | call dzero(gradtargex,6*ntt) 83 | 84 | thresh = 1.0d-14 85 | 86 | call bhfmm2dpart_direct(1,1,nsrc,1,nts,sources,ifcharge, 87 | 1 charges,ifdipole,dip,sources,ifpgh,potex, 88 | 2 gradex,hessex,thresh) 89 | 90 | call bhfmm2dpart_direct(1,1,nsrc,1,ntt,sources,ifcharge, 91 | 1 charges,ifdipole,dip,targ,ifpghtarg,pottargex, 92 | 2 gradtargex,hesstargex,thresh) 93 | 94 | 95 | errps = 0 96 | errpt = 0 97 | 98 | errgs = 0 99 | errgt = 0 100 | 101 | errhs = 0 102 | errht = 0 103 | if(ifpgh.ge.1) call derr(potex,pot,2*nts,errps) 104 | if(ifpghtarg.ge.1) call derr(pottargex,pottarg,2*ntt,errpt) 105 | 106 | 107 | if(ifpgh.ge.2) call derr(gradex,grad,6*nts,errgs) 108 | if(ifpghtarg.ge.2) call derr(gradtargex,gradtarg,6*ntt,errgt) 109 | 110 | call errprintbh(errps,errgs,errhs,errpt,errgt, 111 | 1 errht) 112 | if (errps .lt. eps .and. errgs .lt. eps 113 | 1 .and. errhs .lt. eps .and. 114 | 1 errpt .lt. eps .and. errgt .lt. eps 115 | 1 .and. errht .lt. eps) 116 | 1 ipass(1) = 1 117 | 118 | print *, "ipass=",ipass(1) 119 | ntests = 1 120 | 121 | npass = 0 122 | do i = 1,ntests 123 | npass = npass + ipass(i) 124 | enddo 125 | 126 | 127 | 128 | open(unit=33,file='print_testres.txt',access='append') 129 | write(33,'(a,i2,a,i2,a)') 'Successfully completed ',npass, 130 | 1 ' out of ',ntests,' tests in bhfmm2d testing suite' 131 | close(33) 132 | 133 | 134 | 135 | 136 | stop 137 | end 138 | c----------------------------------------------------- 139 | subroutine dzero(vec,n) 140 | implicit real *8 (a-h,o-z) 141 | real *8 vec(*) 142 | 143 | do i=1,n 144 | vec(i) = 0 145 | enddo 146 | 147 | return 148 | end 149 | c------------------------------------ 150 | subroutine derr(vec1,vec2,n,erra) 151 | implicit real *8 (a-h,o-z) 152 | real *8 vec1(*),vec2(*) 153 | 154 | ra = 0 155 | erra = 0 156 | do i=1,n 157 | ra = ra + vec1(i)**2 158 | erra = erra + (vec1(i)-vec2(i))**2 159 | enddo 160 | 161 | erra = sqrt(erra/ra) 162 | 163 | return 164 | end 165 | c---------------------------------- 166 | subroutine errprintbh(errps,errgs,errhs,errpt,errgt,errht) 167 | implicit real *8 (a-h,o-z) 168 | 1100 format(3(2x,e11.5)) 169 | 170 | 171 | write(6,*) 'error in sources' 172 | write(6,*) 'pot err, grad err, hess err' 173 | write(6,1100) errps,errgs,errhs 174 | write(6,*) 175 | write(6,*) 176 | write(6,* ) 'error in targets' 177 | write(6,*) 'pot err, grad err, hess err' 178 | write(6,1100) errpt,errgt,errht 179 | write(6,*) 180 | write(6,*) 181 | write(6,*)'===================' 182 | 183 | return 184 | end 185 | 186 | -------------------------------------------------------------------------------- /test/biharmonic/test_bhfmm2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-bhfmm2d 2 | 3 | HOST = gcc 4 | #HOST = gcc-openmp 5 | 6 | # FC - fortran compiler 7 | # FFLAGS - fortran compiler flags 8 | 9 | ifeq ($(HOST),gcc) 10 | FC=gfortran 11 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 12 | endif 13 | 14 | ifeq ($(HOST),gcc-openmp) 15 | FC = gfortran 16 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 17 | endif 18 | 19 | # Test objects 20 | # 21 | 22 | BHFMM = ../../src/biharmonic 23 | COM = ../../src/common 24 | 25 | 26 | .PHONY: all clean list 27 | 28 | 29 | OBJECTS = test_bhfmm2d.o \ 30 | $(COM)/prini.o \ 31 | $(COM)/hkrand.o \ 32 | $(COM)/dlaran.o \ 33 | $(COM)/pts_tree2d.o \ 34 | $(COM)/tree_routs2d.o \ 35 | $(COM)/cumsum.o \ 36 | $(BHFMM)/bhfmm2d.o \ 37 | $(COM)/fmmcommon2d.o \ 38 | $(BHFMM)/bhrouts2d.o \ 39 | $(BHFMM)/bhkernels2d.o \ 40 | $(BHFMM)/bhndiv2d.o \ 41 | $(BHFMM)/bh2dterms.o 42 | 43 | 44 | # 45 | 46 | %.o : %.f %.h 47 | $(FC) $(FFLAGS) $< -o $@ 48 | 49 | all: $(OBJECTS) 50 | rm -f $(PROJECT) 51 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 52 | ./$(PROJECT) 53 | 54 | clean: 55 | rm -f $(OBJECTS) 56 | rm -f $(PROJECT) 57 | 58 | list: $(SOURCES) 59 | $(warning Requires: $^) 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /test/biharmonic/test_bhrouts2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-bhrouts2d 2 | 3 | HOST = gcc 4 | #HOST = gcc-openmp 5 | #HOST = intel 6 | 7 | # FC - fortran compiler 8 | # FFLAGS - fortran compiler flags 9 | 10 | ifeq ($(HOST),gcc) 11 | FC=gfortran 12 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 13 | endif 14 | 15 | ifeq ($(HOST),gcc-openmp) 16 | FC = gfortran 17 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 18 | endif 19 | 20 | ifeq ($(HOST),intel) 21 | FC = ifort 22 | FFLAGS=-fPIC -O2 -qopenmp 23 | endif 24 | 25 | # Test objects 26 | # 27 | 28 | BHFMM = ../../src/biharmonic 29 | COM = ../../src/common 30 | 31 | 32 | .PHONY: all clean list 33 | 34 | 35 | OBJECTS = test_bhrouts2d.o \ 36 | $(COM)/prini.o \ 37 | $(COM)/hkrand.o \ 38 | $(COM)/dlaran.o \ 39 | $(COM)/fmmcommon2d.o \ 40 | $(BHFMM)/bhrouts2d.o \ 41 | $(BHFMM)/bhkernels2d.o \ 42 | $(BHFMM)/bh2dterms.o 43 | 44 | 45 | # 46 | 47 | %.o : %.f %.h 48 | $(FC) $(FFLAGS) $< -o $@ 49 | 50 | all: $(OBJECTS) 51 | rm -f $(PROJECT) 52 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 53 | ./$(PROJECT) 54 | 55 | clean: 56 | rm -f $(OBJECTS) 57 | rm -f $(PROJECT) 58 | 59 | list: $(SOURCES) 60 | $(warning Requires: $^) 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /test/helmholtz/run_helmtest.sh: -------------------------------------------------------------------------------- 1 | rm -rf print_testres.txt 2 | ./int2-test-hfmm2d 3 | ./int2-test-hfmm2d-hf 4 | ./int2-test-hfmm2d-vec 5 | ./int2-test-hfmm2d-mps 6 | mv print_testres.txt ../../print_testreshelm.txt 7 | rm -rf fort.13 8 | -------------------------------------------------------------------------------- /test/helmholtz/test_hfmm2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-hfmm2d 2 | 3 | HOST = gcc 4 | #HOST = gcc-openmp 5 | #HOST = intel 6 | 7 | # FC - fortran compiler 8 | # FFLAGS - fortran compiler flags 9 | 10 | ifeq ($(HOST),gcc) 11 | FC=gfortran 12 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 13 | endif 14 | 15 | ifeq ($(HOST),gcc-openmp) 16 | FC = gfortran 17 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 18 | endif 19 | 20 | ifeq ($(HOST),intel) 21 | FC = ifort 22 | FFLAGS=-fPIC -O2 -qopenmp 23 | endif 24 | 25 | # Test objects 26 | # 27 | 28 | HFMM = ../../src/helmholtz 29 | COM = ../../src/common 30 | 31 | 32 | .PHONY: all clean list 33 | 34 | 35 | OBJECTS = test_hfmm2d.o \ 36 | $(COM)/prini.o \ 37 | $(COM)/hkrand.o \ 38 | $(COM)/dlaran.o \ 39 | $(COM)/pts_tree2d.o \ 40 | $(COM)/tree_routs2d.o \ 41 | $(COM)/cumsum.o \ 42 | $(HFMM)/hfmm2d.o \ 43 | $(HFMM)/hfmm2dwrap.o \ 44 | $(HFMM)/hfmm2dwrap_vec.o \ 45 | $(COM)/fmmcommon2d.o \ 46 | $(COM)/cdjseval2d.o \ 47 | $(COM)/dfft_threadsafe.o \ 48 | $(COM)/next235.o \ 49 | $(HFMM)/helmrouts2d.o \ 50 | $(HFMM)/helmkernels2d.o \ 51 | $(COM)/hank103.o \ 52 | $(HFMM)/h2dcommon.o \ 53 | $(HFMM)/hndiv2d.o \ 54 | $(HFMM)/wideband2d.o \ 55 | $(HFMM)/h2dterms.o 56 | 57 | 58 | # 59 | 60 | %.o : %.f %.h 61 | $(FC) $(FFLAGS) $< -o $@ 62 | 63 | all: $(OBJECTS) 64 | rm -f $(PROJECT) 65 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 66 | ./$(PROJECT) 67 | 68 | clean: 69 | rm -f $(OBJECTS) 70 | rm -f $(PROJECT) 71 | 72 | list: $(SOURCES) 73 | $(warning Requires: $^) 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /test/helmholtz/test_hfmm2d_hf.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-hfmm2d 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | HOST = gcc-openmp-x86 6 | #HOST = intel 7 | 8 | # FC - fortran compiler 9 | # FFLAGS - fortran compiler flags 10 | 11 | ifeq ($(HOST),gcc) 12 | FC=gfortran 13 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 14 | endif 15 | 16 | ifeq ($(HOST),gcc-openmp) 17 | FC = gfortran 18 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 19 | endif 20 | 21 | ifeq ($(HOST),gcc-openmp-x86) 22 | FC = gfortran 23 | FFLAGS=-fPIC -O3 -funroll-loops -march=x86-64 -fopenmp -std=legacy 24 | endif 25 | 26 | ifeq ($(HOST),intel) 27 | FC = ifort 28 | FFLAGS=-fPIC -O2 -qopenmp 29 | endif 30 | 31 | # Test objects 32 | # 33 | 34 | HFMM = ../../src/helmholtz 35 | COM = ../../src/common 36 | 37 | 38 | .PHONY: all clean list 39 | 40 | 41 | OBJECTS = test_hfmm2d_hf.o \ 42 | $(COM)/prini.o \ 43 | $(COM)/hkrand.o \ 44 | $(COM)/dlaran.o \ 45 | $(COM)/pts_tree2d.o \ 46 | $(COM)/tree_routs2d.o \ 47 | $(COM)/cumsum.o \ 48 | $(HFMM)/hfmm2d.o \ 49 | $(HFMM)/hfmm2dwrap.o \ 50 | $(HFMM)/hfmm2dwrap_vec.o \ 51 | $(COM)/fmmcommon2d.o \ 52 | $(COM)/cdjseval2d.o \ 53 | $(COM)/dfft_threadsafe.o \ 54 | $(COM)/next235.o \ 55 | $(HFMM)/helmrouts2d.o \ 56 | $(HFMM)/helmkernels2d.o \ 57 | $(COM)/hank103.o \ 58 | $(HFMM)/h2dcommon.o \ 59 | $(HFMM)/hndiv2d.o \ 60 | $(HFMM)/wideband2d.o \ 61 | $(HFMM)/h2dterms.o 62 | 63 | 64 | # 65 | 66 | %.o : %.f %.h 67 | $(FC) $(FFLAGS) $< -o $@ 68 | 69 | all: $(OBJECTS) 70 | rm -f $(PROJECT) 71 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 72 | ./$(PROJECT) 73 | 74 | clean: 75 | rm -f $(OBJECTS) 76 | rm -f $(PROJECT) 77 | 78 | list: $(SOURCES) 79 | $(warning Requires: $^) 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /test/helmholtz/test_hfmm2d_mps.f90: -------------------------------------------------------------------------------- 1 | program test_hfmm3d_mp2loc 2 | implicit double precision (a-h,o-z) 3 | 4 | character(len=72) str1 5 | 6 | integer :: ns, nt, nc 7 | integer :: i,j,k,ntest,nd,idim 8 | integer :: ifcharge,ifdipole,ifpgh,ifpghtarg 9 | integer :: ipass(18),len1,ntests,isum 10 | integer, allocatable :: nterms(:), impole(:) 11 | 12 | double precision :: eps, err, hkrand, dnorms(1000), force(10) 13 | double precision, allocatable :: source(:,:), targ(:,:) 14 | double precision, allocatable :: centers(:,:) 15 | double precision, allocatable :: wlege(:), rscales(:) 16 | 17 | double complex :: eye, zk, ima 18 | double complex, allocatable :: charge(:,:),dipstr(:,:) 19 | double precision, allocatable :: dipvec(:,:,:) 20 | double complex, allocatable :: pot(:,:), pot2(:,:), pottarg(:,:) 21 | double complex, allocatable :: grad(:,:,:),gradtarg(:,:,:) 22 | double complex, allocatable :: hess(:,:,:),hesstarg(:,:,:) 23 | double complex, allocatable :: mpole(:), local(:) 24 | 25 | 26 | data eye/(0.0d0,1.0d0)/ 27 | ima = (0,1) 28 | done = 1 29 | pi = 4*atan(done) 30 | 31 | ! 32 | ! initialize printing routine 33 | ! 34 | call prini(6,13) 35 | 36 | nd = 1 37 | 38 | 39 | n1 = 10 40 | ns = n1**2 41 | nc = ns 42 | 43 | 44 | nt = 22 45 | 46 | allocate(source(2,ns),targ(2,nt), centers(2,nc)) 47 | allocate(charge(nd,ns),dipvec(nd,2,ns),dipstr(nd,ns)) 48 | allocate(pot(nd,ns), pot2(nd,ns)) 49 | allocate(grad(nd,2,ns)) 50 | allocate(hess(nd,3,ns)) 51 | 52 | allocate(pottarg(nd,nt)) 53 | allocate(gradtarg(nd,2,nt)) 54 | allocate(hesstarg(nd,3,nt)) 55 | eps = 0.5d-9 56 | 57 | write(*,*) "==========================================" 58 | write(*,*) "Testing suite for hfmm2d_mps" 59 | write(*,'(a,e12.5)') "Requested precision = ",eps 60 | 61 | boxsize = 1 62 | dlam = 1/boxsize 63 | zk = 2*pi/dlam 64 | 65 | call prin2('boxsize in wavelengths = *', boxsize, 1) 66 | call prin2('dlam = *', dlam, 1) 67 | call prin2('zk = *', zk, 2) 68 | 69 | ! 70 | ! generate sources uniformly in the unit cube 71 | ! 72 | h = 1.0d0/(n1+1) 73 | ijk = 0 74 | do i = 1,n1 75 | do j = 1,n1 76 | ijk = ijk + 1 77 | source(1,ijk) = h*i 78 | source(2,ijk) = h*j 79 | end do 80 | end do 81 | 82 | 83 | dnorm = 0 84 | dnormd = 0 85 | do i=1,ns 86 | !source(1,i) = hkrand(0)**2 87 | !source(2,i) = hkrand(0)**2 88 | !source(3,i) = hkrand(0)**2 89 | 90 | do idim=1,nd 91 | 92 | charge(idim,i) = hkrand(0) + eye*hkrand(0) 93 | dipstr(idim,i) = hkrand(0) + eye*hkrand(0) 94 | dnorm = dnorm + abs(charge(idim,i))**2 95 | dnormd = dnormd + abs(dipstr(idim,i))**2 96 | 97 | dipvec(idim,1,i) = hkrand(0) 98 | dipvec(idim,2,i) = hkrand(0) 99 | 100 | pot(idim,i) = 0 101 | grad(idim,1,i) = 0 102 | grad(idim,2,i) = 0 103 | 104 | hess(idim,1,i) = 0 105 | hess(idim,2,i) = 0 106 | hess(idim,3,i) = 0 107 | enddo 108 | enddo 109 | 110 | dnorm = sqrt(dnorm) 111 | dnormd = sqrt(dnormd) 112 | do i=1,ns 113 | do idim = 1,nd 114 | charge(idim,i) = charge(idim,i)/dnorm 115 | charge(idim,i) = 0 116 | charge(idim,1) = 1.0d0 117 | dipstr(idim,i) = dipstr(idim,i)/dnormd 118 | dipstr(idim,i) = 0 119 | end do 120 | end do 121 | 122 | 123 | ! call prin2('min source separation = *', ssep, 1) 124 | 125 | shift = h/100 126 | do i = 1,ns 127 | centers(1,i) = source(1,i) + shift 128 | centers(2,i) = source(2,i) 129 | end do 130 | 131 | !call prin2('centers = *', centers, 3*nc) 132 | 133 | ! 134 | ! now form a multipole expansion at each center 135 | ! 136 | allocate(nterms(nc), impole(nc)) 137 | 138 | ntm = 30 139 | ntot1 = 0 140 | do i = 1,nc 141 | nterms(i) = ntm + 2*cos(pi/2*i) 142 | nterms(i) = ntm 143 | ntot1 = ntot1 + (2*nterms(i)+1) 144 | 145 | end do 146 | 147 | ntot = nd*ntot1 148 | 149 | 150 | allocate(mpole(ntot)) 151 | 152 | impole(1) = 1 153 | do i = 1,nc-1 154 | ilen = (2*nterms(i)+1) 155 | impole(i+1) = impole(i) + nd*ilen 156 | end do 157 | 158 | call zinitialize(ntot, mpole) 159 | 160 | ns1 = 1 161 | rscale = 1 162 | sc = abs(zk)*shift 163 | if (sc .lt. 1) rscale = sc 164 | 165 | 166 | allocate(rscales(nc)) 167 | do i = 1,nc 168 | rscales(i) = rscale 169 | call h2dformmpc(nd,zk,rscales(i),source(1,i),ns1,charge(1,i), & 170 | centers(1,i),nterms(i),mpole(impole(i))) 171 | end do 172 | 173 | 174 | ! 175 | ! do the direct calculation 176 | ! 177 | thresh = 1.0d-15 178 | ifcharge = 1 179 | ifdipole = 0 180 | ifpgh = 1 181 | ntarg = 0 182 | ifpghtarg = 0 183 | call hfmm2d(nd, eps, zk, ns, source, ifcharge, & 184 | charge, ifdipole,dipstr,dipvec, iper, ifpgh, pot, grad, & 185 | hess, ntarg, targ, ifpghtarg, pottarg, gradtarg, hesstarg, ier) 186 | 187 | 188 | 189 | allocate(local(ntot)) 190 | 191 | ! 192 | ! now test source to source, charge, 193 | ! with potentials 194 | ! 195 | print * 196 | print * 197 | print * 198 | write(6,*) 'testing multipoles to locals' 199 | write(6,*) 'input: multipole expansions' 200 | write(6,*) 'output: local expansions' 201 | write(6,*) 202 | write(6,*) 203 | 204 | 205 | call hfmm2d_mps(nd, eps, zk, & 206 | nc, centers, rscales, nterms, ntot,mpole, impole, local,ier) 207 | 208 | 209 | call zinitialize(nd*nc, pot2) 210 | npts = 1 211 | do i = 1,nc 212 | call h2dtaevalp(nd, zk, rscales(i), & 213 | centers(1,i), local(impole(i)), & 214 | nterms(i), source(1,i), npts, pot2(1,i)) 215 | end do 216 | 217 | nprin = min(2*nd*nc,24) 218 | call prin2('from hfmm3d_mps, potential = *', pot2, nprin) 219 | call prin2('via fmm, potential = *', pot, nprin) 220 | 221 | erra = 0 222 | dnorm = 0 223 | do j = 1,nc 224 | do i = 1,nd 225 | erra = erra + abs(pot(i,j)-pot2(i,j))**2 226 | dnorm = dnorm + abs(pot(i,j))**2 227 | if(abs(pot(i,j)-pot2(i,j)).ge.1.0d-6) print *, real(pot(1,j)),real(pot2(1,j)) 228 | 229 | end do 230 | end do 231 | 232 | 233 | erra = sqrt(erra/dnorm) 234 | call prin2('l2 rel err=*',erra,1) 235 | 236 | open(unit=33,file='print_testres.txt',access='append') 237 | isuccess = 0 238 | ntest = 1 239 | if(erra.lt.eps) isuccess = 1 240 | 241 | write(33,'(a,i1,a,i1,a)') 'Successfully completed ', & 242 | isuccess,' out of ',ntest,' tests in helm2d_mps testing suite' 243 | close(33) 244 | 245 | 246 | 247 | 248 | stop 249 | end program 250 | 251 | 252 | 253 | ! ---------------------------------------------------------- 254 | ! 255 | ! This is the end of the debugging code. 256 | ! 257 | ! ---------------------------------------------------------- 258 | subroutine prinmp(str, mpole, nterms) 259 | implicit double precision (a-h,o-z) 260 | character (len=*) :: str 261 | double complex :: mpole(0:nterms, -nterms:nterms) 262 | double complex :: tmp(-10000:10000) 263 | 264 | print *, trim(str) 265 | 266 | do n = 0,nterms 267 | print * 268 | write(6,'(a,i2,a,i2,a,i2)') 'n = ', n, ' m = ', -n, '...', n 269 | do m = -nterms,nterms 270 | tmp(m) = mpole(n,m) 271 | end do 272 | call prin2('coefs = *', tmp(-n), 2*n+1) 273 | end do 274 | 275 | return 276 | end subroutine prinmp 277 | 278 | 279 | 280 | subroutine zinitialize(len, zs) 281 | implicit double precision (a-h,o-z) 282 | double complex :: zs(len) 283 | 284 | do i = 1,len 285 | zs(i) = 0 286 | end do 287 | return 288 | end subroutine zinitialize 289 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /test/helmholtz/test_hfmm2d_mps.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-hfmm2d 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | HOST = gcc-openmp-x86 6 | #HOST = intel 7 | 8 | # FC - fortran compiler 9 | # FFLAGS - fortran compiler flags 10 | 11 | ifeq ($(HOST),gcc) 12 | FC=gfortran 13 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 14 | endif 15 | 16 | ifeq ($(HOST),gcc-openmp) 17 | FC = gfortran 18 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 19 | endif 20 | 21 | ifeq ($(HOST),gcc-openmp-x86) 22 | FC = gfortran 23 | FFLAGS=-fPIC -O3 -funroll-loops -march=x86-64 -fopenmp -std=legacy 24 | endif 25 | 26 | ifeq ($(HOST),intel) 27 | FC = ifort 28 | FFLAGS=-fPIC -O2 -qopenmp 29 | endif 30 | 31 | # Test objects 32 | # 33 | 34 | HFMM = ../../src/helmholtz 35 | COM = ../../src/common 36 | 37 | 38 | .PHONY: all clean list 39 | 40 | 41 | OBJECTS = test_hfmm2d_mps.o \ 42 | $(COM)/prini.o \ 43 | $(COM)/hkrand.o \ 44 | $(COM)/dlaran.o \ 45 | $(COM)/pts_tree2d.o \ 46 | $(COM)/tree_routs2d.o \ 47 | $(COM)/cumsum.o \ 48 | $(HFMM)/hfmm2d.o \ 49 | $(HFMM)/hfmm2d_mps.o \ 50 | $(HFMM)/hfmm2dwrap.o \ 51 | $(HFMM)/hfmm2dwrap_vec.o \ 52 | $(COM)/fmmcommon2d.o \ 53 | $(COM)/cdjseval2d.o \ 54 | $(COM)/dfft_threadsafe.o \ 55 | $(COM)/next235.o \ 56 | $(HFMM)/helmrouts2d.o \ 57 | $(HFMM)/helmkernels2d.o \ 58 | $(COM)/hank103.o \ 59 | $(HFMM)/h2dcommon.o \ 60 | $(HFMM)/hndiv2d.o \ 61 | $(HFMM)/wideband2d.o \ 62 | $(HFMM)/h2dterms.o 63 | 64 | 65 | # 66 | 67 | %.o : %.f %.h 68 | $(FC) $(FFLAGS) $< -o $@ 69 | %.o: %.f90 70 | $(FC) -c $(FFLAGS) $< -o $@ 71 | 72 | all: $(OBJECTS) 73 | rm -f $(PROJECT) 74 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 75 | ./$(PROJECT) 76 | 77 | clean: 78 | rm -f $(OBJECTS) 79 | rm -f $(PROJECT) 80 | 81 | list: $(SOURCES) 82 | $(warning Requires: $^) 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /test/laplace/run_laptest.sh: -------------------------------------------------------------------------------- 1 | rm -rf print_testres.txt 2 | ./int2-test-cfmm2d 3 | ./int2-test-cfmm2d-vec 4 | ./int2-test-lfmm2d 5 | ./int2-test-lfmm2d-vec 6 | ./int2-test-rfmm2d 7 | ./int2-test-rfmm2d-vec 8 | mv print_testres.txt ../../print_testreslap.txt 9 | rm -rf fort.13 10 | -------------------------------------------------------------------------------- /test/laplace/test_cfmm2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-cfmm2d 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | 6 | # FC - fortran compiler 7 | # FFLAGS - fortran compiler flags 8 | 9 | ifeq ($(HOST),gcc) 10 | FC=gfortran 11 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 12 | endif 13 | 14 | ifeq ($(HOST),gcc-openmp) 15 | FC = gfortran 16 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 17 | endif 18 | 19 | # Test objects 20 | # 21 | 22 | LFMM = ../../src/laplace 23 | COM = ../../src/common 24 | 25 | 26 | .PHONY: all clean list 27 | 28 | 29 | OBJECTS = test_cfmm2d.o \ 30 | $(COM)/prini.o \ 31 | $(COM)/hkrand.o \ 32 | $(COM)/dlaran.o \ 33 | $(COM)/pts_tree2d.o \ 34 | $(COM)/tree_routs2d.o \ 35 | $(COM)/cumsum.o \ 36 | $(LFMM)/cfmm2d.o \ 37 | $(LFMM)/cfmm2dwrap.o \ 38 | $(LFMM)/cfmm2dwrap_vec.o \ 39 | $(LFMM)/lfmm2d.o \ 40 | $(LFMM)/lfmm2dwrap.o \ 41 | $(LFMM)/lfmm2dwrap_vec.o \ 42 | $(COM)/fmmcommon2d.o \ 43 | $(LFMM)/laprouts2d.o \ 44 | $(LFMM)/lndiv2d.o \ 45 | $(LFMM)/lapkernels2d.o \ 46 | $(LFMM)/cauchykernels2d.o \ 47 | $(LFMM)/l2dterms.o 48 | 49 | 50 | # 51 | 52 | %.o : %.f %.h 53 | $(FC) $(FFLAGS) $< -o $@ 54 | 55 | all: $(OBJECTS) 56 | rm -f $(PROJECT) 57 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 58 | ./$(PROJECT) 59 | 60 | clean: 61 | rm -f $(OBJECTS) 62 | rm -f $(PROJECT) 63 | 64 | list: $(SOURCES) 65 | $(warning Requires: $^) 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /test/laplace/test_cfmm2d_vec.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-cfmm2d-vec 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | 6 | # FC - fortran compiler 7 | # FFLAGS - fortran compiler flags 8 | 9 | ifeq ($(HOST),gcc) 10 | FC=gfortran 11 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 12 | endif 13 | 14 | ifeq ($(HOST),gcc-openmp) 15 | FC = gfortran 16 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 17 | endif 18 | 19 | # Test objects 20 | # 21 | 22 | LFMM = ../../src/laplace 23 | COM = ../../src/common 24 | 25 | 26 | .PHONY: all clean list 27 | 28 | 29 | OBJECTS = test_cfmm2d_vec.o \ 30 | $(COM)/prini.o \ 31 | $(COM)/hkrand.o \ 32 | $(COM)/dlaran.o \ 33 | $(COM)/pts_tree2d.o \ 34 | $(COM)/tree_routs2d.o \ 35 | $(COM)/cumsum.o \ 36 | $(LFMM)/cfmm2d.o \ 37 | $(LFMM)/cfmm2dwrap.o \ 38 | $(LFMM)/cfmm2dwrap_vec.o \ 39 | $(LFMM)/lfmm2d.o \ 40 | $(LFMM)/lfmm2dwrap.o \ 41 | $(LFMM)/lfmm2dwrap_vec.o \ 42 | $(COM)/fmmcommon2d.o \ 43 | $(LFMM)/laprouts2d.o \ 44 | $(LFMM)/lndiv2d.o \ 45 | $(LFMM)/lapkernels2d.o \ 46 | $(LFMM)/cauchykernels2d.o \ 47 | $(LFMM)/l2dterms.o 48 | 49 | 50 | # 51 | 52 | %.o : %.f %.h 53 | $(FC) $(FFLAGS) $< -o $@ 54 | 55 | all: $(OBJECTS) 56 | rm -f $(PROJECT) 57 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 58 | ./$(PROJECT) 59 | 60 | clean: 61 | rm -f $(OBJECTS) 62 | rm -f $(PROJECT) 63 | 64 | list: $(SOURCES) 65 | $(warning Requires: $^) 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /test/laplace/test_lfmm2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-lfmm2d 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | 6 | # FC - fortran compiler 7 | # FFLAGS - fortran compiler flags 8 | 9 | ifeq ($(HOST),gcc) 10 | FC=gfortran 11 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 12 | endif 13 | 14 | ifeq ($(HOST),gcc-openmp) 15 | FC = gfortran 16 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 17 | endif 18 | 19 | # Test objects 20 | # 21 | 22 | LFMM = ../../src/laplace 23 | COM = ../../src/common 24 | 25 | 26 | .PHONY: all clean list 27 | 28 | 29 | OBJECTS = test_lfmm2d.o \ 30 | $(COM)/prini.o \ 31 | $(COM)/hkrand.o \ 32 | $(COM)/dlaran.o \ 33 | $(COM)/pts_tree2d.o \ 34 | $(COM)/tree_routs2d.o \ 35 | $(COM)/cumsum.o \ 36 | $(LFMM)/lfmm2d.o \ 37 | $(LFMM)/lfmm2dwrap.o \ 38 | $(LFMM)/lfmm2dwrap_vec.o \ 39 | $(LFMM)/cfmm2d.o \ 40 | $(LFMM)/cfmm2dwrap.o \ 41 | $(LFMM)/cfmm2dwrap_vec.o \ 42 | $(COM)/fmmcommon2d.o \ 43 | $(LFMM)/laprouts2d.o \ 44 | $(LFMM)/lndiv2d.o \ 45 | $(LFMM)/lapkernels2d.o \ 46 | $(LFMM)/cauchykernels2d.o \ 47 | $(LFMM)/l2dterms.o 48 | 49 | 50 | # 51 | 52 | %.o : %.f %.h 53 | $(FC) $(FFLAGS) $< -o $@ 54 | 55 | all: $(OBJECTS) 56 | rm -f $(PROJECT) 57 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 58 | ./$(PROJECT) 59 | 60 | clean: 61 | rm -f $(OBJECTS) 62 | rm -f $(PROJECT) 63 | 64 | list: $(SOURCES) 65 | $(warning Requires: $^) 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /test/laplace/test_lfmm2d_vec.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-lfmm2d-vec 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | 6 | # FC - fortran compiler 7 | # FFLAGS - fortran compiler flags 8 | 9 | ifeq ($(HOST),gcc) 10 | FC=gfortran 11 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 12 | endif 13 | 14 | ifeq ($(HOST),gcc-openmp) 15 | FC = gfortran 16 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 17 | endif 18 | 19 | # Test objects 20 | # 21 | 22 | LFMM = ../../src/laplace 23 | COM = ../../src/common 24 | 25 | 26 | .PHONY: all clean list 27 | 28 | 29 | OBJECTS = test_lfmm2d_vec.o \ 30 | $(COM)/prini.o \ 31 | $(COM)/hkrand.o \ 32 | $(COM)/dlaran.o \ 33 | $(COM)/pts_tree2d.o \ 34 | $(COM)/tree_routs2d.o \ 35 | $(COM)/cumsum.o \ 36 | $(LFMM)/lfmm2d.o \ 37 | $(LFMM)/lfmm2dwrap.o \ 38 | $(LFMM)/lfmm2dwrap_vec.o \ 39 | $(LFMM)/cfmm2d.o \ 40 | $(LFMM)/cfmm2dwrap.o \ 41 | $(LFMM)/cfmm2dwrap_vec.o \ 42 | $(COM)/fmmcommon2d.o \ 43 | $(LFMM)/laprouts2d.o \ 44 | $(LFMM)/lndiv2d.o \ 45 | $(LFMM)/lapkernels2d.o \ 46 | $(LFMM)/cauchykernels2d.o \ 47 | $(LFMM)/l2dterms.o 48 | 49 | 50 | # 51 | 52 | %.o : %.f %.h 53 | $(FC) $(FFLAGS) $< -o $@ 54 | 55 | all: $(OBJECTS) 56 | rm -f $(PROJECT) 57 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 58 | ./$(PROJECT) 59 | 60 | clean: 61 | rm -f $(OBJECTS) 62 | rm -f $(PROJECT) 63 | 64 | list: $(SOURCES) 65 | $(warning Requires: $^) 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /test/laplace/test_rfmm2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-rfmm2d 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | 6 | # FC - fortran compiler 7 | # FFLAGS - fortran compiler flags 8 | 9 | ifeq ($(HOST),gcc) 10 | FC=gfortran 11 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 12 | endif 13 | 14 | ifeq ($(HOST),gcc-openmp) 15 | FC = gfortran 16 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 17 | endif 18 | 19 | # Test objects 20 | # 21 | 22 | LFMM = ../../src/laplace 23 | COM = ../../src/common 24 | 25 | 26 | .PHONY: all clean list 27 | 28 | 29 | OBJECTS = test_rfmm2d.o \ 30 | $(COM)/prini.o \ 31 | $(COM)/hkrand.o \ 32 | $(COM)/dlaran.o \ 33 | $(COM)/pts_tree2d.o \ 34 | $(COM)/tree_routs2d.o \ 35 | $(COM)/cumsum.o \ 36 | $(LFMM)/lfmm2d.o \ 37 | $(LFMM)/lfmm2dwrap.o \ 38 | $(LFMM)/lfmm2dwrap_vec.o \ 39 | $(LFMM)/cfmm2d.o \ 40 | $(LFMM)/cfmm2dwrap.o \ 41 | $(LFMM)/cfmm2dwrap_vec.o \ 42 | $(LFMM)/rfmm2d.o \ 43 | $(LFMM)/rfmm2dwrap.o \ 44 | $(LFMM)/rfmm2dwrap_vec.o \ 45 | $(COM)/fmmcommon2d.o \ 46 | $(LFMM)/laprouts2d.o \ 47 | $(LFMM)/lndiv2d.o \ 48 | $(LFMM)/lapkernels2d.o \ 49 | $(LFMM)/rlapkernels2d.o \ 50 | $(LFMM)/cauchykernels2d.o \ 51 | $(LFMM)/l2dterms.o 52 | 53 | 54 | # 55 | 56 | %.o : %.f %.h 57 | $(FC) $(FFLAGS) $< -o $@ 58 | 59 | all: $(OBJECTS) 60 | rm -f $(PROJECT) 61 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 62 | ./$(PROJECT) 63 | 64 | clean: 65 | rm -f $(OBJECTS) 66 | rm -f $(PROJECT) 67 | 68 | list: $(SOURCES) 69 | $(warning Requires: $^) 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /test/laplace/test_rfmm2d_vec.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-rfmm2d-vec 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | 6 | # FC - fortran compiler 7 | # FFLAGS - fortran compiler flags 8 | 9 | ifeq ($(HOST),gcc) 10 | FC=gfortran 11 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 12 | endif 13 | 14 | ifeq ($(HOST),gcc-openmp) 15 | FC = gfortran 16 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 17 | endif 18 | 19 | # Test objects 20 | # 21 | 22 | LFMM = ../../src/laplace 23 | COM = ../../src/common 24 | 25 | 26 | .PHONY: all clean list 27 | 28 | 29 | OBJECTS = test_rfmm2d_vec.o \ 30 | $(COM)/prini.o \ 31 | $(COM)/hkrand.o \ 32 | $(COM)/dlaran.o \ 33 | $(COM)/pts_tree2d.o \ 34 | $(COM)/tree_routs2d.o \ 35 | $(COM)/cumsum.o \ 36 | $(LFMM)/lfmm2d.o \ 37 | $(LFMM)/lfmm2dwrap.o \ 38 | $(LFMM)/lfmm2dwrap_vec.o \ 39 | $(LFMM)/cfmm2d.o \ 40 | $(LFMM)/cfmm2dwrap.o \ 41 | $(LFMM)/cfmm2dwrap_vec.o \ 42 | $(LFMM)/rfmm2d.o \ 43 | $(LFMM)/rfmm2dwrap.o \ 44 | $(LFMM)/rfmm2dwrap_vec.o \ 45 | $(COM)/fmmcommon2d.o \ 46 | $(LFMM)/laprouts2d.o \ 47 | $(LFMM)/lndiv2d.o \ 48 | $(LFMM)/lapkernels2d.o \ 49 | $(LFMM)/rlapkernels2d.o \ 50 | $(LFMM)/cauchykernels2d.o \ 51 | $(LFMM)/l2dterms.o 52 | 53 | 54 | # 55 | 56 | %.o : %.f %.h 57 | $(FC) $(FFLAGS) $< -o $@ 58 | 59 | all: $(OBJECTS) 60 | rm -f $(PROJECT) 61 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 62 | ./$(PROJECT) 63 | 64 | clean: 65 | rm -f $(OBJECTS) 66 | rm -f $(PROJECT) 67 | 68 | list: $(SOURCES) 69 | $(warning Requires: $^) 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /test/modified-biharmonic/jinjaroot.yaml: -------------------------------------------------------------------------------- 1 | mbhDirectRouts: 2 | - 3 | name: mbh2d_directcp_vec 4 | ker: c 5 | out: p 6 | - 7 | name: mbh2d_directdp_vec 8 | ker: d 9 | out: p 10 | - 11 | name: mbh2d_directcdp_vec 12 | ker: cd 13 | out: p 14 | - 15 | name: mbh2d_directqp_vec 16 | ker: q 17 | out: p 18 | - 19 | name: mbh2d_directcqp_vec 20 | ker: cq 21 | out: p 22 | - 23 | name: mbh2d_directdqp_vec 24 | ker: dq 25 | out: p 26 | - 27 | name: mbh2d_directcdqp_vec 28 | ker: cdq 29 | out: p 30 | - 31 | name: mbh2d_directop_vec 32 | ker: o 33 | out: p 34 | - 35 | name: mbh2d_directcop_vec 36 | ker: co 37 | out: p 38 | - 39 | name: mbh2d_directdop_vec 40 | ker: do 41 | out: p 42 | - 43 | name: mbh2d_directcdop_vec 44 | ker: cdo 45 | out: p 46 | - 47 | name: mbh2d_directqop_vec 48 | ker: qo 49 | out: p 50 | - 51 | name: mbh2d_directcqop_vec 52 | ker: cqo 53 | out: p 54 | - 55 | name: mbh2d_directdqop_vec 56 | ker: dqo 57 | out: p 58 | - 59 | name: mbh2d_directcdqop_vec 60 | ker: cdqo 61 | out: p 62 | - 63 | name: mbh2d_directcg_vec 64 | ker: c 65 | out: g 66 | - 67 | name: mbh2d_directdg_vec 68 | ker: d 69 | out: g 70 | - 71 | name: mbh2d_directcdg_vec 72 | ker: cd 73 | out: g 74 | - 75 | name: mbh2d_directqg_vec 76 | ker: q 77 | out: g 78 | - 79 | name: mbh2d_directcqg_vec 80 | ker: cq 81 | out: g 82 | - 83 | name: mbh2d_directdqg_vec 84 | ker: dq 85 | out: g 86 | - 87 | name: mbh2d_directcdqg_vec 88 | ker: cdq 89 | out: g 90 | - 91 | name: mbh2d_directog_vec 92 | ker: o 93 | out: g 94 | - 95 | name: mbh2d_directcog_vec 96 | ker: co 97 | out: g 98 | - 99 | name: mbh2d_directdog_vec 100 | ker: do 101 | out: g 102 | - 103 | name: mbh2d_directcdog_vec 104 | ker: cdo 105 | out: g 106 | - 107 | name: mbh2d_directqog_vec 108 | ker: qo 109 | out: g 110 | - 111 | name: mbh2d_directcqog_vec 112 | ker: cqo 113 | out: g 114 | - 115 | name: mbh2d_directdqog_vec 116 | ker: dqo 117 | out: g 118 | - 119 | name: mbh2d_directcdqog_vec 120 | ker: cdqo 121 | out: g 122 | - 123 | name: mbh2d_directch_vec 124 | ker: c 125 | out: h 126 | - 127 | name: mbh2d_directdh_vec 128 | ker: d 129 | out: h 130 | - 131 | name: mbh2d_directcdh_vec 132 | ker: cd 133 | out: h 134 | - 135 | name: mbh2d_directqh_vec 136 | ker: q 137 | out: h 138 | - 139 | name: mbh2d_directcqh_vec 140 | ker: cq 141 | out: h 142 | - 143 | name: mbh2d_directdqh_vec 144 | ker: dq 145 | out: h 146 | - 147 | name: mbh2d_directcdqh_vec 148 | ker: cdq 149 | out: h 150 | - 151 | name: mbh2d_directoh_vec 152 | ker: o 153 | out: h 154 | - 155 | name: mbh2d_directcoh_vec 156 | ker: co 157 | out: h 158 | - 159 | name: mbh2d_directdoh_vec 160 | ker: do 161 | out: h 162 | - 163 | name: mbh2d_directcdoh_vec 164 | ker: cdo 165 | out: h 166 | - 167 | name: mbh2d_directqoh_vec 168 | ker: qo 169 | out: h 170 | - 171 | name: mbh2d_directcqoh_vec 172 | ker: cqo 173 | out: h 174 | - 175 | name: mbh2d_directdqoh_vec 176 | ker: dqo 177 | out: h 178 | - 179 | name: mbh2d_directcdqoh_vec 180 | ker: cdqo 181 | out: h 182 | -------------------------------------------------------------------------------- /test/modified-biharmonic/jinjaroot.yaml.py: -------------------------------------------------------------------------------- 1 | 2 | fname="jinjaroot.yaml" 3 | 4 | file = open(fname,"w") 5 | 6 | file.write("mbhDirectRouts:\n") 7 | 8 | outs=["p","g","h"] 9 | 10 | for out in outs: 11 | for i in range(16): 12 | i1 = i % 2 13 | i2 = (i // 2) % 2 14 | i3 = (i // 4) % 2 15 | i4 = (i // 8) % 2 16 | ker = "" 17 | if (i1 == 1): ker += "c" 18 | if (i2 == 1): ker += "d" 19 | if (i3 == 1): ker += "q" 20 | if (i4 == 1): ker += "o" 21 | 22 | if ker != "": 23 | name = "mbh2d_direct"+ker+out+"_vec" 24 | file.write(" -\n") 25 | file.write(" name: " + name + "\n") 26 | file.write(" ker: " + ker + "\n") 27 | file.write(" out: " + out + "\n") 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/modified-biharmonic/run_mbhtest.sh: -------------------------------------------------------------------------------- 1 | rm -rf print_testres.txt 2 | ./int2-test-mbhrouts2d 3 | mv print_testres.txt ../../print_testresmbh.txt 4 | rm -rf fort.13 5 | -------------------------------------------------------------------------------- /test/modified-biharmonic/test_mbhfmm2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-test-mbhfmm2d 2 | 3 | HOST = gcc 4 | #HOST = gcc-dbg 5 | #HOST = gcc-openmp 6 | #HOST = intel 7 | 8 | # FC - fortran compiler 9 | # FFLAGS - fortran compiler flags 10 | 11 | ifeq ($(HOST),gcc) 12 | FC=gfortran 13 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 14 | endif 15 | 16 | ifeq ($(HOST),gcc-dbg) 17 | FC=gfortran 18 | FFLAGS=-g -pg -std=legacy 19 | endif 20 | 21 | ifeq ($(HOST),gcc-openmp) 22 | FC = gfortran 23 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 24 | endif 25 | 26 | ifeq ($(HOST),intel) 27 | FC = ifort 28 | FFLAGS=-fPIC -O2 -qopenmp 29 | endif 30 | 31 | # Test objects 32 | # 33 | 34 | HFMM = ../../src/helmholtz 35 | LFMM = ../../src/laplace 36 | MBHFMM = ../../src/modified-biharmonic 37 | COM = ../../src/common 38 | 39 | 40 | .PHONY: all clean list 41 | 42 | 43 | OBJECTS = test_mbhfmm2d.o \ 44 | $(COM)/prini.o \ 45 | $(COM)/hkrand.o \ 46 | $(COM)/dlaran.o \ 47 | $(COM)/pts_tree2d.o \ 48 | $(COM)/tree_routs2d.o \ 49 | $(COM)/cumsum.o \ 50 | $(HFMM)/hfmm2d.o \ 51 | $(HFMM)/hfmm2dwrap.o \ 52 | $(HFMM)/hfmm2dwrap_vec.o \ 53 | $(HFMM)/hndiv2d.o \ 54 | $(COM)/fmmcommon2d.o \ 55 | $(COM)/cdjseval2d.o \ 56 | $(COM)/dfft_threadsafe.o \ 57 | $(COM)/next235.o \ 58 | $(HFMM)/helmrouts2d.o \ 59 | $(HFMM)/helmkernels2d.o \ 60 | $(COM)/hank103.o \ 61 | $(HFMM)/h2dcommon.o \ 62 | $(HFMM)/wideband2d.o \ 63 | $(HFMM)/h2dterms.o \ 64 | $(LFMM)/l2dterms.o \ 65 | $(MBHFMM)/mbhkernels2d.o \ 66 | $(MBHFMM)/mbhrouts2d.o \ 67 | $(MBHFMM)/mbhgreen2d.o \ 68 | $(MBHFMM)/mbhfmm2d.o 69 | 70 | 71 | # 72 | 73 | %.o : %.f %.h 74 | $(FC) $(FFLAGS) $< -o $@ 75 | 76 | all: $(OBJECTS) 77 | rm -f $(PROJECT) 78 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 79 | ./$(PROJECT) 80 | 81 | clean: 82 | rm -f $(OBJECTS) 83 | rm -f $(PROJECT) 84 | 85 | list: $(SOURCES) 86 | $(warning Requires: $^) 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /test/modified-biharmonic/test_mbhrouts2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-test-mbhrouts2d 2 | 3 | HOST = gcc 4 | HOST = gcc-dbg 5 | #HOST = gcc-openmp 6 | #HOST = intel 7 | 8 | # FC - fortran compiler 9 | # FFLAGS - fortran compiler flags 10 | 11 | ifeq ($(HOST),gcc) 12 | FC=gfortran 13 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -std=legacy 14 | endif 15 | 16 | ifeq ($(HOST),gcc-dbg) 17 | FC=gfortran 18 | FFLAGS=-g -std=legacy 19 | endif 20 | 21 | ifeq ($(HOST),gcc-openmp) 22 | FC = gfortran 23 | FFLAGS=-fPIC -O3 -funroll-loops -march=native -fopenmp -std=legacy 24 | endif 25 | 26 | ifeq ($(HOST),intel) 27 | FC = ifort 28 | FFLAGS=-fPIC -O2 -qopenmp 29 | endif 30 | 31 | # Test objects 32 | # 33 | 34 | HFMM = ../../src/helmholtz 35 | LFMM = ../../src/laplace 36 | MBHFMM = ../../src/modified-biharmonic 37 | COM = ../../src/common 38 | 39 | 40 | .PHONY: all clean list 41 | 42 | 43 | OBJECTS = test_mbhrouts2d.o \ 44 | $(COM)/prini.o \ 45 | $(COM)/hkrand.o \ 46 | $(COM)/dlaran.o \ 47 | $(COM)/pts_tree2d.o \ 48 | $(COM)/tree_routs2d.o \ 49 | $(COM)/cumsum.o \ 50 | $(HFMM)/hfmm2d.o \ 51 | $(HFMM)/hfmm2dwrap.o \ 52 | $(HFMM)/hfmm2dwrap_vec.o \ 53 | $(HFMM)/hndiv2d.o \ 54 | $(COM)/fmmcommon2d.o \ 55 | $(COM)/cdjseval2d.o \ 56 | $(COM)/dfft_threadsafe.o \ 57 | $(COM)/next235.o \ 58 | $(HFMM)/helmrouts2d.o \ 59 | $(HFMM)/helmkernels2d.o \ 60 | $(COM)/hank103.o \ 61 | $(HFMM)/h2dcommon.o \ 62 | $(HFMM)/wideband2d.o \ 63 | $(HFMM)/h2dterms.o \ 64 | $(LFMM)/l2dterms.o \ 65 | $(MBHFMM)/mbhkernels2d.o \ 66 | $(MBHFMM)/mbhrouts2d.o \ 67 | $(MBHFMM)/mbhgreen2d.o 68 | 69 | # 70 | 71 | %.o : %.f %.h 72 | $(FC) $(FFLAGS) $< -o $@ 73 | 74 | all: $(OBJECTS) 75 | rm -f $(PROJECT) 76 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 77 | ./$(PROJECT) 78 | 79 | clean: 80 | rm -f $(OBJECTS) 81 | rm -f $(PROJECT) 82 | 83 | list: $(SOURCES) 84 | $(warning Requires: $^) 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /test/stokes/test_stfmm2d.f: -------------------------------------------------------------------------------- 1 | implicit real *8 (a-h,o-z) 2 | real *8, allocatable :: sources(:,:),targ(:,:) 3 | real *8, allocatable :: stoklet(:,:),strslet(:,:),strsvec(:,:) 4 | real *8, allocatable :: pot(:,:),grad(:,:,:),pre(:) 5 | real *8, allocatable :: potex(:,:),gradex(:,:,:),preex(:) 6 | 7 | real *8, allocatable :: pottarg(:,:),gradtarg(:,:,:),pretarg(:) 8 | real *8, allocatable :: pottargex(:,:),gradtargex(:,:,:), 9 | 1 pretargex(:) 10 | 11 | real *8 expc(100),texps(100),scj(100) 12 | 13 | integer ipass(27) 14 | 15 | complex *16 ima 16 | data ima/(0.0d0,1.0d0)/ 17 | 18 | call prini(6,13) 19 | 20 | ntests=1 21 | do i = 1,ntests 22 | ipass(i) = 0 23 | enddo 24 | 25 | done = 1 26 | pi = atan(done)*4 27 | 28 | nsrc = 9998 29 | ntarg = 9999 30 | 31 | allocate(sources(2,nsrc),stoklet(2,nsrc)) 32 | allocate(strslet(2,nsrc),strsvec(2,nsrc)) 33 | allocate(targ(2,ntarg)) 34 | allocate(pot(2,nsrc),grad(2,2,nsrc),pre(nsrc)) 35 | allocate(pottarg(2,ntarg),gradtarg(2,2,ntarg),pretarg(ntarg)) 36 | 37 | do i=1,nsrc 38 | 39 | sources(1,i) = hkrand(0) 40 | sources(2,i) = hkrand(0) 41 | 42 | stoklet(1,i) = hkrand(0) 43 | stoklet(2,i) = hkrand(0) 44 | 45 | strslet(1,i) = hkrand(0) 46 | strslet(2,i) = hkrand(0) 47 | 48 | strsvec(1,i) = hkrand(0) 49 | strsvec(2,i) = hkrand(0) 50 | enddo 51 | 52 | 53 | 54 | do i=1,ntarg 55 | targ(1,i) = hkrand(0) 56 | targ(2,i) = hkrand(0) 57 | enddo 58 | 59 | nts = min(20,nsrc) 60 | ntt = min(20,ntarg) 61 | 62 | allocate(potex(2,nts),gradex(2,2,nts),preex(nts)) 63 | allocate(pottargex(2,ntt),gradtargex(2,2,ntt),pretargex(ntt)) 64 | 65 | eps = 0.5d-6 66 | 67 | ifstoklet = 1 68 | ifstrslet = 1 69 | iper = 0 70 | ifppreg = 3 71 | ifppregtarg = 3 72 | nd = 1 73 | call stfmm2d(nd,eps,nsrc,sources,ifstoklet,stoklet, 74 | 1 ifstrslet,strslet,strsvec,ifppreg,pot,pre,grad, 75 | 2 ntarg,targ,ifppregtarg,pottarg,pretarg,gradtarg,ier) 76 | 77 | c call prin2('pot=*',pot,2*nsrc) 78 | c call prin2('pre=*',pre,nsrc) 79 | c call prin2('grad=*',grad,4*nsrc) 80 | 81 | 82 | c 83 | cc test against exact potential 84 | c 85 | call dzero(potex,2*nts) 86 | call dzero(pottargex,2*ntt) 87 | call dzero(gradex,4*nts) 88 | call dzero(gradtargex,4*ntt) 89 | call dzero(preex,nts) 90 | call dzero(pretargex,ntt) 91 | 92 | thresh = 1.0d-14 93 | 94 | call st2ddirectstokstrsg(nd,sources,ifstoklet,stoklet,ifstrslet, 95 | 1 strslet,strsvec,nsrc,sources,nts,potex,preex,gradex,thresh) 96 | 97 | call st2ddirectstokstrsg(nd,sources,ifstoklet,stoklet,ifstrslet, 98 | 1 strslet,strsvec,nsrc,targ,ntt,pottargex,pretargex,gradtargex, 99 | 2 thresh) 100 | 101 | c call prin2('potex=*',potex,2*nts) 102 | c call prin2('preex=*',preex,nts) 103 | c call prin2('gradex=*',gradex,4*nts) 104 | 105 | 106 | 107 | errps = 0 108 | errpt = 0 109 | 110 | errgs = 0 111 | errgt = 0 112 | 113 | errpres = 0 114 | errpret = 0 115 | if(ifppreg.ge.1) call derr(potex,pot,2*nts,errps) 116 | if(ifppregtarg.ge.1) call derr(pottargex,pottarg,2*ntt,errpt) 117 | 118 | 119 | if(ifppreg.ge.2) call derr(preex,pre,nts,errpres) 120 | if(ifppregtarg.ge.2) call derr(pretargex,pretarg,ntt,errpret) 121 | 122 | if(ifppreg.ge.3) call derr(gradex,grad,4*nts,errgs) 123 | if(ifppregtarg.ge.3) call derr(gradtargex,gradtarg,4*ntt,errgt) 124 | 125 | call errprintbh(errps,errpres,errgs,errpt,errpret, 126 | 1 errgt) 127 | if (errps .lt. eps .and. errgs .lt. eps 128 | 1 .and. errpres .lt. eps .and. 129 | 1 errpt .lt. eps .and. errgt .lt. eps 130 | 1 .and. errpret .lt. eps) 131 | 1 ipass(1) = 1 132 | 133 | print *, "ipass=",ipass(1) 134 | ntests = 1 135 | 136 | npass = 0 137 | do i = 1,ntests 138 | npass = npass + ipass(i) 139 | enddo 140 | 141 | 142 | 143 | open(unit=33,file='print_testres.txt',access='append') 144 | write(33,'(a,i2,a,i2,a)') 'Successfully completed ',npass, 145 | 1 ' out of ',ntests,' tests in bhfmm2d testing suite' 146 | close(33) 147 | 148 | 149 | 150 | 151 | stop 152 | end 153 | c----------------------------------------------------- 154 | subroutine dzero(vec,n) 155 | implicit real *8 (a-h,o-z) 156 | real *8 vec(*) 157 | 158 | do i=1,n 159 | vec(i) = 0 160 | enddo 161 | 162 | return 163 | end 164 | c------------------------------------ 165 | subroutine derr(vec1,vec2,n,erra) 166 | implicit real *8 (a-h,o-z) 167 | real *8 vec1(*),vec2(*) 168 | 169 | ra = 0 170 | erra = 0 171 | do i=1,n 172 | ra = ra + vec1(i)**2 173 | erra = erra + (vec1(i)-vec2(i))**2 174 | enddo 175 | 176 | erra = sqrt(erra/ra) 177 | 178 | return 179 | end 180 | c---------------------------------- 181 | subroutine errprintbh(errps,errgs,errhs,errpt,errgt,errht) 182 | implicit real *8 (a-h,o-z) 183 | 1100 format(3(2x,e11.5)) 184 | 185 | 186 | write(6,*) 'error in sources' 187 | write(6,*) 'pot err, grad err, hess err' 188 | write(6,1100) errps,errgs,errhs 189 | write(6,*) 190 | write(6,*) 191 | write(6,* ) 'error in targets' 192 | write(6,*) 'pot err, grad err, hess err' 193 | write(6,1100) errpt,errgt,errht 194 | write(6,*) 195 | write(6,*) 196 | write(6,*)'===================' 197 | 198 | return 199 | end 200 | 201 | -------------------------------------------------------------------------------- /test/stokes/test_stfmm2d.make: -------------------------------------------------------------------------------- 1 | PROJECT = int2-stfmm2d 2 | 3 | HOST = gcc 4 | HOST = gcc-openmp 5 | 6 | arch = native 7 | # arch = x86-64 8 | 9 | # FC - fortran compiler 10 | # FFLAGS - fortran compiler flags 11 | 12 | ifeq ($(HOST),gcc) 13 | FC=gfortran 14 | FFLAGS=-fPIC -O3 -funroll-loops -march=${arch} -std=legacy 15 | endif 16 | 17 | ifeq ($(HOST),gcc-openmp) 18 | FC = gfortran 19 | FFLAGS=-fPIC -O3 -funroll-loops -march=${arch} -fopenmp -std=legacy 20 | endif 21 | 22 | # Test objects 23 | # 24 | 25 | BHFMM = ../../src/biharmonic 26 | STFMM = ../../src/stokes 27 | COM = ../../src/common 28 | 29 | 30 | .PHONY: all clean list 31 | 32 | 33 | OBJECTS = test_stfmm2d.o \ 34 | $(COM)/prini.o \ 35 | $(COM)/hkrand.o \ 36 | $(COM)/dlaran.o \ 37 | $(COM)/pts_tree2d.o \ 38 | $(COM)/tree_routs2d.o \ 39 | $(COM)/cumsum.o \ 40 | $(BHFMM)/bhfmm2d.o \ 41 | $(COM)/fmmcommon2d.o \ 42 | $(BHFMM)/bhrouts2d.o \ 43 | $(STFMM)/stfmm2d.o \ 44 | $(STFMM)/stokkernels2d.o \ 45 | $(BHFMM)/bhkernels2d.o \ 46 | $(BHFMM)/bhndiv2d.o \ 47 | $(BHFMM)/bh2dterms.o 48 | 49 | 50 | # 51 | 52 | %.o : %.f %.h 53 | $(FC) $(FFLAGS) $< -o $@ 54 | 55 | all: $(OBJECTS) 56 | rm -f $(PROJECT) 57 | $(FC) $(FFLAGS) -o $(PROJECT) $(OBJECTS) 58 | ./$(PROJECT) 59 | 60 | clean: 61 | rm -f $(OBJECTS) 62 | rm -f $(PROJECT) 63 | 64 | list: $(SOURCES) 65 | $(warning Requires: $^) 66 | 67 | 68 | 69 | 70 | 71 | 72 | --------------------------------------------------------------------------------