From 2e4549e51adf461007732f65f450c3b6e56e90c9 Mon Sep 17 00:00:00 2001 From: podlesny <podlesny@mi.fu-berlin.de> Date: Tue, 3 Sep 2019 17:47:34 +0200 Subject: [PATCH] major file system change --- data/2d-dip-contours-performance.tikz | 91 +++ data/2d-dip-single-points.tikz | 51 ++ data/2d-effort-over-tolerance.tikz | 17 + data/2d-velocity-contours-threequakes.tikz | 61 ++ data/2d-velocity-contours-zoom.tikz | 51 ++ data/3d-performance.tikz | 57 ++ data/3d-velocity-contours.tikz | 156 +++++ data/boxplot.tikz | 43 ++ data/config.ini | 4 + data/includes.tex | 51 ++ .../2d-dip-contours-performance.tex | 7 + data/standalone/2d-dip-single-points.tex | 7 + data/standalone/2d-effort-over-tolerance.tex | 7 + .../2d-velocity-contours-threequakes.tex | 7 + data/standalone/2d-velocity-contours-zoom.tex | 7 + data/standalone/3d-performance.tex | 7 + data/standalone/3d-velocity-contours.tex | 7 + data/standalone/Makefile | 18 + data/standalone/boxplot.tex | 7 + data/tools/2d-dip-contours.R | 108 ++++ data/tools/2d-event-writer.R | 68 +++ data/tools/2d-fpi-tolerance.R | 41 ++ data/tools/2d-performance.R | 58 ++ data/tools/2d-velocity-contours.R | 95 +++ data/tools/3d-performance.R | 62 ++ data/tools/3d-velocity-contours.R | 67 ++ data/tools/comparison:lab-sim.R | 42 ++ data/tools/generate-2d.bash | 25 + data/tools/generate-3d.bash | 16 + data/tools/generate-others.bash | 13 + data/tools/support/findQuakes.R | 18 + data/tools/support/maxVelocity.cpp | 29 + data/tools/support/negativeStarts.cpp | 13 + data/tools/support/positiveStarts.cpp | 14 + data/tools/support/trapezoidal.cpp | 9 + data/tools/support/writeContours.R | 11 + debugging.m | 577 ++++++++++++++++++ dune/tectonic/CMakeLists.txt | 38 +- {src => dune/tectonic}/assemblers.cc | 4 +- {src => dune/tectonic}/assemblers.hh | 4 +- {src => dune/tectonic}/assemblers_tmpl.cc | 0 {src => dune/tectonic}/data-structures/.cc | 0 dune/tectonic/data-structures/CMakeLists.txt | 19 + .../data-structures/body/CMakeLists.txt | 13 + .../tectonic/data-structures/body}/body.cc | 0 .../tectonic/data-structures/body}/body.hh | 10 +- .../data-structures/body}/body_tmpl.cc | 4 +- .../{ => data-structures/body}/bodydata.hh | 0 .../body}/boundarycondition.hh | 0 .../tectonic}/data-structures/enumparser.cc | 0 .../tectonic}/data-structures/enumparser.hh | 0 .../tectonic}/data-structures/enums.hh | 0 .../data-structures/friction/CMakeLists.txt | 20 + .../friction}/frictioncouplingpair.hh | 3 +- .../friction}/frictiondata.hh | 0 .../friction}/frictionpotential.hh | 2 +- .../friction}/globalfriction.hh | 6 +- .../friction}/globalfrictiondata.hh | 2 +- .../friction}/globalratestatefriction.hh | 14 +- .../friction}/localfriction.hh | 2 +- .../globalfrictioncontainer.cc | 0 .../globalfrictioncontainer.hh | 0 .../tectonic}/data-structures/matrices.hh | 0 .../data-structures/network/CMakeLists.txt | 12 + .../network}/contactnetwork.cc | 8 +- .../network}/contactnetwork.hh | 19 +- .../network/contactnetwork_tmpl.cc | 10 + .../network}/levelcontactnetwork.cc | 12 +- .../network}/levelcontactnetwork.hh | 19 +- .../network}/levelcontactnetwork_tmpl.cc | 10 +- .../data-structures/program_state.hh | 85 ++- {src => dune/tectonic}/explicitgrid.hh | 0 {src => dune/tectonic}/explicitvectors.hh | 0 dune/tectonic/factories/CMakeLists.txt | 22 + .../tectonic}/factories/cantorfactory.cc | 0 .../tectonic}/factories/cantorfactory.hh | 0 .../tectonic}/factories/cantorfactory_tmpl.cc | 0 .../factories/contactnetworkfactory.hh | 2 +- .../factories/levelcontactnetworkfactory.hh | 0 .../factories/stackedblocksfactory.cc | 12 +- .../factories/stackedblocksfactory.hh | 10 +- .../factories/stackedblocksfactory_tmpl.cc | 0 .../tectonic}/factories/threeblocksfactory.cc | 14 +- .../tectonic}/factories/threeblocksfactory.hh | 9 +- .../factories/threeblocksfactory_tmpl.cc | 0 dune/tectonic/factories/twoblocksfactory.cc | 199 ++++++ dune/tectonic/factories/twoblocksfactory.hh | 87 +++ .../factories/twoblocksfactory_tmpl.cc | 8 + {src => dune/tectonic}/gridselector.hh | 0 dune/tectonic/io/CMakeLists.txt | 16 + {src => dune/tectonic}/io/hdf5-bodywriter.hh | 27 +- {src => dune/tectonic}/io/hdf5-levelwriter.hh | 28 +- dune/tectonic/io/hdf5/CMakeLists.txt | 26 + .../io/hdf5/frictionalboundary-writer.cc | 5 +- .../io/hdf5/frictionalboundary-writer.hh | 0 .../io/hdf5/frictionalboundary-writer_tmpl.cc | 0 .../tectonic}/io/hdf5/iteration-writer.cc | 0 .../tectonic}/io/hdf5/iteration-writer.hh | 0 .../tectonic}/io/hdf5/patchinfo-writer.cc | 12 +- .../tectonic}/io/hdf5/patchinfo-writer.hh | 8 +- .../io/hdf5/patchinfo-writer_tmpl.cc | 0 {src => dune/tectonic}/io/hdf5/restart-io.cc | 0 {src => dune/tectonic}/io/hdf5/restart-io.hh | 0 .../tectonic}/io/hdf5/restart-io_tmpl.cc | 0 {src => dune/tectonic}/io/hdf5/restrict.hh | 0 .../tectonic}/io/hdf5/surface-writer.cc | 0 .../tectonic}/io/hdf5/surface-writer.hh | 0 .../tectonic}/io/hdf5/surface-writer_tmpl.cc | 0 {src => dune/tectonic}/io/hdf5/time-writer.cc | 0 {src => dune/tectonic}/io/hdf5/time-writer.hh | 0 .../tectonic}/io/hdf5/time-writer_tmpl.cc | 0 .../tectonic}/io/uniform-grid-writer.cc | 0 {src => dune/tectonic}/io/vtk.cc | 0 {src => dune/tectonic}/io/vtk.hh | 0 {src => dune/tectonic}/io/vtk_tmpl.cc | 0 dune/tectonic/minimisation.hh | 41 -- dune/tectonic/myblockproblem.hh | 273 --------- dune/tectonic/problem-data/CMakeLists.txt | 22 + .../tectonic/problem-data}/bc.hh | 13 +- dune/tectonic/{ => problem-data}/gravity.hh | 0 .../tectonic/problem-data/grid/CMakeLists.txt | 25 + .../tectonic/problem-data}/grid/cube.cc | 0 .../tectonic/problem-data}/grid/cube.hh | 0 .../tectonic/problem-data}/grid/cube_tmpl.cc | 0 .../tectonic/problem-data}/grid/cubefaces.cc | 0 .../tectonic/problem-data}/grid/cubefaces.hh | 0 .../problem-data}/grid/cubefaces_tmpl.cc | 0 .../problem-data}/grid/cubegridconstructor.hh | 0 .../problem-data}/grid/cuboidgeometry.cc | 14 +- .../problem-data}/grid/cuboidgeometry.hh | 4 +- .../problem-data}/grid/cuboidgeometry_tmpl.cc | 0 .../problem-data}/grid/gridconstructor.hh | 0 .../tectonic/problem-data}/grid/mygrids.cc | 8 +- .../tectonic/problem-data}/grid/mygrids.hh | 4 +- .../problem-data}/grid/mygrids_tmpl.cc | 0 .../problem-data}/grid/simplexmanager.cc | 0 .../problem-data}/grid/simplexmanager.hh | 0 .../tectonic/problem-data}/midpoint.hh | 0 .../tectonic/problem-data}/mybody.hh | 25 +- .../problem-data}/myglobalfrictiondata.hh | 2 +- .../tectonic/problem-data}/patchfunction.hh | 0 .../problem-data}/segmented-function.hh | 0 dune/tectonic/quadraticenergy.hh | 18 - dune/tectonic/spatial-solving/CMakeLists.txt | 15 + .../spatial-solving/fixedpointiterator.cc | 191 +++--- .../spatial-solving/fixedpointiterator.hh | 11 +- .../fixedpointiterator_tmpl.cc | 41 ++ .../preconditioners/CMakeLists.txt | 19 + .../hierarchicleveliterator.hh | 0 .../levelpatchpreconditioner.hh | 66 +- .../multilevelpatchpreconditioner.hh | 46 +- .../preconditioners/nbodycontacttransfer.cc | 10 +- .../preconditioners/nbodycontacttransfer.hh | 2 +- .../preconditioners/patchproblem.hh | 115 ++++ .../preconditioners/supportpatchfactory.hh | 7 +- .../tectonic/spatial-solving/solverfactory.cc | 46 ++ .../spatial-solving/solverfactory.hh | 23 +- .../spatial-solving/solverfactory_ex.cc | 17 + .../spatial-solving/solverfactory_tmpl.cc | 21 + .../spatial-solving/tnnmg/CMakeLists.txt | 18 + .../spatial-solving/tnnmg/functional.hh | 0 .../spatial-solving/tnnmg/linearcorrection.hh | 0 .../spatial-solving/tnnmg/linearization.hh | 0 .../spatial-solving/tnnmg/linesearchsolver.hh | 0 .../tnnmg/localbisectionsolver.hh | 0 .../spatial-solving/tnnmg/zerononlinearity.hh | 0 {src => dune/tectonic}/tests/CMakeLists.txt | 1 + {src => dune/tectonic}/tests/common.hh | 0 {src => dune/tectonic}/tests/couplingtest.hh | 0 .../tests/globalfrictioncontainertest.cc | 0 .../tectonic}/tests/gridgluefrictiontest.cc | 0 {src => dune/tectonic/tests}/nodalweights.cc | 0 {src => dune/tectonic/tests}/nodalweights.hh | 0 .../tectonic}/tests/nodalweightstest.cc | 0 .../tests/nonoverlappingcouplingtest.cc | 0 .../tectonic/tests}/solverfactorytest.cc | 40 +- .../tests/supportpatchfactorytest.cc | 0 dune/tectonic/time-stepping/CMakeLists.txt | 23 + .../time-stepping/adaptivetimestepper.cc | 276 +++++++++ .../time-stepping/adaptivetimestepper.hh | 23 +- .../time-stepping/adaptivetimestepper_tmpl.cc | 42 ++ .../time-stepping/coupledtimestepper.cc | 29 +- .../time-stepping/coupledtimestepper.hh | 12 +- .../time-stepping/coupledtimestepper_tmpl.cc | 40 ++ {src => dune/tectonic}/time-stepping/rate.cc | 0 {src => dune/tectonic}/time-stepping/rate.hh | 0 .../time-stepping/rate/CMakeLists.txt | 15 + .../time-stepping/rate/backward_euler.cc | 0 .../time-stepping/rate/backward_euler.hh | 0 .../tectonic}/time-stepping/rate/newmark.cc | 0 .../tectonic}/time-stepping/rate/newmark.hh | 0 .../time-stepping/rate/rateupdater.cc | 0 .../time-stepping/rate/rateupdater.hh | 0 .../time-stepping/rate/rateupdater_tmpl.cc | 4 +- .../tectonic}/time-stepping/rate_tmpl.cc | 9 +- {src => dune/tectonic}/time-stepping/state.cc | 0 {src => dune/tectonic}/time-stepping/state.hh | 0 .../time-stepping/state/CMakeLists.txt | 14 + .../state/ageinglawstateupdater.cc | 0 .../state/ageinglawstateupdater.hh | 0 .../time-stepping/state/calculation.wxm | 0 .../tectonic/time-stepping/state/explicit.aux | 1 + .../tectonic/time-stepping/state/explicit.log | 285 +++++++++ .../tectonic/time-stepping/state/explicit.pdf | Bin 0 -> 82543 bytes .../time-stepping/state/explicit.synctex.gz | Bin 0 -> 2143 bytes .../time-stepping/state/explicit.tex | 0 .../state/sliplawstateupdater.cc | 0 .../state/sliplawstateupdater.hh | 0 .../time-stepping/state/stateupdater.hh | 8 +- .../tectonic}/time-stepping/state_tmpl.cc | 2 +- .../tectonic}/time-stepping/updaters.hh | 0 dune/tectonic/utils/CMakeLists.txt | 18 + {src => dune/tectonic}/utils/almostequal.hh | 0 {src => dune/tectonic}/utils/debugutils.hh | 0 {src => dune/tectonic}/utils/diameter.hh | 0 dune/tectonic/{ => utils}/geocoordinate.hh | 0 .../{ => utils}/index-in-sorted-range.hh | 0 {src => dune/tectonic}/utils/tobool.hh | 0 program_structure.txt | 29 - src/CMakeLists.txt | 108 +--- src/data-structures/contactnetwork_tmpl.cc | 12 - src/foam/CMakeLists.txt | 43 ++ .../foam-2D.cfg} | 9 +- src/foam/foam.cc | 483 +++++++++++++++ src/foam/foam.cfg | 107 ++++ src/multi-body-problem-data/geometry.tex | 68 --- src/multi-body-problem/CMakeLists.txt | 46 ++ .../multi-body-problem-2D.cfg | 8 +- .../multi-body-problem-3D.cfg | 0 .../multi-body-problem.cc | 121 ++-- .../multi-body-problem.cfg | 25 +- src/one-body-problem-3D.cfg | 24 - src/one-body-problem-data/bc.hh | 18 - src/one-body-problem-data/geometry.tex | 68 --- src/one-body-problem-data/midpoint.hh | 12 - src/one-body-problem-data/mybody.hh | 55 -- src/one-body-problem-data/mygeometry.cc | 158 ----- src/one-body-problem-data/mygeometry.hh | 89 --- .../myglobalfrictiondata.hh | 42 -- src/one-body-problem-data/mygrid.cc | 227 ------- src/one-body-problem-data/mygrid.hh | 84 --- src/one-body-problem-data/mygrid_tmpl.cc | 17 - src/one-body-problem-data/patchfunction.hh | 31 - .../segmented-function.hh | 34 -- src/one-body-problem-data/weakpatch.hh | 32 - src/one-body-problem.cc | 361 ----------- src/one-body-problem.cfg | 70 --- src/spatial-solving/CMakeLists.txt | 2 - .../fixedpointiterator_tmpl.cc | 27 - .../preconditioners/CMakeLists.txt | 8 - .../preconditioners/localproblem.hh | 141 ----- src/spatial-solving/solverfactory.cc | 50 -- src/spatial-solving/solverfactory_tmpl.cc | 36 -- src/spatial-solving/tnnmg/CMakeLists.txt | 8 - src/tests/contactmerge.cc | 40 -- src/time-stepping/adaptivetimestepper.cc | 137 ----- src/time-stepping/adaptivetimestepper_tmpl.cc | 27 - src/time-stepping/coupledtimestepper_tmpl.cc | 27 - todo.txt | 29 - 259 files changed, 4707 insertions(+), 2868 deletions(-) create mode 100644 data/2d-dip-contours-performance.tikz create mode 100644 data/2d-dip-single-points.tikz create mode 100644 data/2d-effort-over-tolerance.tikz create mode 100644 data/2d-velocity-contours-threequakes.tikz create mode 100644 data/2d-velocity-contours-zoom.tikz create mode 100644 data/3d-performance.tikz create mode 100644 data/3d-velocity-contours.tikz create mode 100644 data/boxplot.tikz create mode 100644 data/config.ini create mode 100644 data/includes.tex create mode 100644 data/standalone/2d-dip-contours-performance.tex create mode 100644 data/standalone/2d-dip-single-points.tex create mode 100644 data/standalone/2d-effort-over-tolerance.tex create mode 100644 data/standalone/2d-velocity-contours-threequakes.tex create mode 100644 data/standalone/2d-velocity-contours-zoom.tex create mode 100644 data/standalone/3d-performance.tex create mode 100644 data/standalone/3d-velocity-contours.tex create mode 100644 data/standalone/Makefile create mode 100644 data/standalone/boxplot.tex create mode 100644 data/tools/2d-dip-contours.R create mode 100644 data/tools/2d-event-writer.R create mode 100644 data/tools/2d-fpi-tolerance.R create mode 100644 data/tools/2d-performance.R create mode 100644 data/tools/2d-velocity-contours.R create mode 100644 data/tools/3d-performance.R create mode 100644 data/tools/3d-velocity-contours.R create mode 100644 data/tools/comparison:lab-sim.R create mode 100755 data/tools/generate-2d.bash create mode 100755 data/tools/generate-3d.bash create mode 100755 data/tools/generate-others.bash create mode 100644 data/tools/support/findQuakes.R create mode 100644 data/tools/support/maxVelocity.cpp create mode 100644 data/tools/support/negativeStarts.cpp create mode 100644 data/tools/support/positiveStarts.cpp create mode 100644 data/tools/support/trapezoidal.cpp create mode 100644 data/tools/support/writeContours.R create mode 100644 debugging.m rename {src => dune/tectonic}/assemblers.cc (98%) rename {src => dune/tectonic}/assemblers.hh (97%) rename {src => dune/tectonic}/assemblers_tmpl.cc (100%) rename {src => dune/tectonic}/data-structures/.cc (100%) create mode 100644 dune/tectonic/data-structures/CMakeLists.txt create mode 100644 dune/tectonic/data-structures/body/CMakeLists.txt rename {src/data-structures => dune/tectonic/data-structures/body}/body.cc (100%) rename {src/data-structures => dune/tectonic/data-structures/body}/body.hh (97%) rename {src/data-structures => dune/tectonic/data-structures/body}/body_tmpl.cc (70%) rename dune/tectonic/{ => data-structures/body}/bodydata.hh (100%) rename {src => dune/tectonic/data-structures/body}/boundarycondition.hh (100%) rename {src => dune/tectonic}/data-structures/enumparser.cc (100%) rename {src => dune/tectonic}/data-structures/enumparser.hh (100%) rename {src => dune/tectonic}/data-structures/enums.hh (100%) create mode 100644 dune/tectonic/data-structures/friction/CMakeLists.txt rename {src => dune/tectonic/data-structures/friction}/frictioncouplingpair.hh (95%) rename dune/tectonic/{ => data-structures/friction}/frictiondata.hh (100%) rename dune/tectonic/{ => data-structures/friction}/frictionpotential.hh (99%) rename dune/tectonic/{ => data-structures/friction}/globalfriction.hh (93%) rename dune/tectonic/{ => data-structures/friction}/globalfrictiondata.hh (96%) rename dune/tectonic/{ => data-structures/friction}/globalratestatefriction.hh (91%) rename dune/tectonic/{ => data-structures/friction}/localfriction.hh (99%) rename {src => dune/tectonic}/data-structures/globalfrictioncontainer.cc (100%) rename {src => dune/tectonic}/data-structures/globalfrictioncontainer.hh (100%) rename {src => dune/tectonic}/data-structures/matrices.hh (100%) create mode 100644 dune/tectonic/data-structures/network/CMakeLists.txt rename {src/data-structures => dune/tectonic/data-structures/network}/contactnetwork.cc (98%) rename {src/data-structures => dune/tectonic/data-structures/network}/contactnetwork.hh (95%) create mode 100644 dune/tectonic/data-structures/network/contactnetwork_tmpl.cc rename {src/data-structures => dune/tectonic/data-structures/network}/levelcontactnetwork.cc (97%) rename {src/data-structures => dune/tectonic/data-structures/network}/levelcontactnetwork.hh (91%) rename {src/data-structures => dune/tectonic/data-structures/network}/levelcontactnetwork_tmpl.cc (54%) rename {src => dune/tectonic}/data-structures/program_state.hh (82%) rename {src => dune/tectonic}/explicitgrid.hh (100%) rename {src => dune/tectonic}/explicitvectors.hh (100%) create mode 100644 dune/tectonic/factories/CMakeLists.txt rename {src => dune/tectonic}/factories/cantorfactory.cc (100%) rename {src => dune/tectonic}/factories/cantorfactory.hh (100%) rename {src => dune/tectonic}/factories/cantorfactory_tmpl.cc (100%) rename {src => dune/tectonic}/factories/contactnetworkfactory.hh (96%) rename {src => dune/tectonic}/factories/levelcontactnetworkfactory.hh (100%) rename {src => dune/tectonic}/factories/stackedblocksfactory.cc (97%) rename {src => dune/tectonic}/factories/stackedblocksfactory.hh (93%) rename {src => dune/tectonic}/factories/stackedblocksfactory_tmpl.cc (100%) rename {src => dune/tectonic}/factories/threeblocksfactory.cc (96%) rename {src => dune/tectonic}/factories/threeblocksfactory.hh (92%) rename {src => dune/tectonic}/factories/threeblocksfactory_tmpl.cc (100%) create mode 100644 dune/tectonic/factories/twoblocksfactory.cc create mode 100644 dune/tectonic/factories/twoblocksfactory.hh create mode 100644 dune/tectonic/factories/twoblocksfactory_tmpl.cc rename {src => dune/tectonic}/gridselector.hh (100%) create mode 100644 dune/tectonic/io/CMakeLists.txt rename {src => dune/tectonic}/io/hdf5-bodywriter.hh (64%) rename {src => dune/tectonic}/io/hdf5-levelwriter.hh (67%) create mode 100644 dune/tectonic/io/hdf5/CMakeLists.txt rename {src => dune/tectonic}/io/hdf5/frictionalboundary-writer.cc (93%) rename {src => dune/tectonic}/io/hdf5/frictionalboundary-writer.hh (100%) rename {src => dune/tectonic}/io/hdf5/frictionalboundary-writer_tmpl.cc (100%) rename {src => dune/tectonic}/io/hdf5/iteration-writer.cc (100%) rename {src => dune/tectonic}/io/hdf5/iteration-writer.hh (100%) rename {src => dune/tectonic}/io/hdf5/patchinfo-writer.cc (89%) rename {src => dune/tectonic}/io/hdf5/patchinfo-writer.hh (83%) rename {src => dune/tectonic}/io/hdf5/patchinfo-writer_tmpl.cc (100%) rename {src => dune/tectonic}/io/hdf5/restart-io.cc (100%) rename {src => dune/tectonic}/io/hdf5/restart-io.hh (100%) rename {src => dune/tectonic}/io/hdf5/restart-io_tmpl.cc (100%) rename {src => dune/tectonic}/io/hdf5/restrict.hh (100%) rename {src => dune/tectonic}/io/hdf5/surface-writer.cc (100%) rename {src => dune/tectonic}/io/hdf5/surface-writer.hh (100%) rename {src => dune/tectonic}/io/hdf5/surface-writer_tmpl.cc (100%) rename {src => dune/tectonic}/io/hdf5/time-writer.cc (100%) rename {src => dune/tectonic}/io/hdf5/time-writer.hh (100%) rename {src => dune/tectonic}/io/hdf5/time-writer_tmpl.cc (100%) rename {src => dune/tectonic}/io/uniform-grid-writer.cc (100%) rename {src => dune/tectonic}/io/vtk.cc (100%) rename {src => dune/tectonic}/io/vtk.hh (100%) rename {src => dune/tectonic}/io/vtk_tmpl.cc (100%) delete mode 100644 dune/tectonic/minimisation.hh delete mode 100644 dune/tectonic/myblockproblem.hh create mode 100644 dune/tectonic/problem-data/CMakeLists.txt rename {src/multi-body-problem-data => dune/tectonic/problem-data}/bc.hh (69%) rename dune/tectonic/{ => problem-data}/gravity.hh (100%) create mode 100644 dune/tectonic/problem-data/grid/CMakeLists.txt rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cube.cc (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cube.hh (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cube_tmpl.cc (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cubefaces.cc (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cubefaces.hh (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cubefaces_tmpl.cc (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cubegridconstructor.hh (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cuboidgeometry.cc (94%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cuboidgeometry.hh (95%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cuboidgeometry_tmpl.cc (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/gridconstructor.hh (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/mygrids.cc (97%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/mygrids.hh (93%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/mygrids_tmpl.cc (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/simplexmanager.cc (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/simplexmanager.hh (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/midpoint.hh (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/mybody.hh (65%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/myglobalfrictiondata.hh (95%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/patchfunction.hh (100%) rename {src/multi-body-problem-data => dune/tectonic/problem-data}/segmented-function.hh (100%) delete mode 100644 dune/tectonic/quadraticenergy.hh create mode 100644 dune/tectonic/spatial-solving/CMakeLists.txt rename {src => dune/tectonic}/spatial-solving/fixedpointiterator.cc (61%) rename {src => dune/tectonic}/spatial-solving/fixedpointiterator.hh (86%) create mode 100644 dune/tectonic/spatial-solving/fixedpointiterator_tmpl.cc create mode 100644 dune/tectonic/spatial-solving/preconditioners/CMakeLists.txt rename {src => dune/tectonic}/spatial-solving/preconditioners/hierarchicleveliterator.hh (100%) rename {src => dune/tectonic}/spatial-solving/preconditioners/levelpatchpreconditioner.hh (72%) rename {src => dune/tectonic}/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh (86%) rename {src => dune/tectonic}/spatial-solving/preconditioners/nbodycontacttransfer.cc (97%) rename {src => dune/tectonic}/spatial-solving/preconditioners/nbodycontacttransfer.hh (97%) create mode 100644 dune/tectonic/spatial-solving/preconditioners/patchproblem.hh rename {src => dune/tectonic}/spatial-solving/preconditioners/supportpatchfactory.hh (98%) create mode 100644 dune/tectonic/spatial-solving/solverfactory.cc rename {src => dune/tectonic}/spatial-solving/solverfactory.hh (69%) create mode 100644 dune/tectonic/spatial-solving/solverfactory_ex.cc create mode 100644 dune/tectonic/spatial-solving/solverfactory_tmpl.cc create mode 100644 dune/tectonic/spatial-solving/tnnmg/CMakeLists.txt rename {src => dune/tectonic}/spatial-solving/tnnmg/functional.hh (100%) rename {src => dune/tectonic}/spatial-solving/tnnmg/linearcorrection.hh (100%) rename {src => dune/tectonic}/spatial-solving/tnnmg/linearization.hh (100%) rename {src => dune/tectonic}/spatial-solving/tnnmg/linesearchsolver.hh (100%) rename {src => dune/tectonic}/spatial-solving/tnnmg/localbisectionsolver.hh (100%) rename {src => dune/tectonic}/spatial-solving/tnnmg/zerononlinearity.hh (100%) rename {src => dune/tectonic}/tests/CMakeLists.txt (81%) rename {src => dune/tectonic}/tests/common.hh (100%) rename {src => dune/tectonic}/tests/couplingtest.hh (100%) rename {src => dune/tectonic}/tests/globalfrictioncontainertest.cc (100%) rename {src => dune/tectonic}/tests/gridgluefrictiontest.cc (100%) rename {src => dune/tectonic/tests}/nodalweights.cc (100%) rename {src => dune/tectonic/tests}/nodalweights.hh (100%) rename {src => dune/tectonic}/tests/nodalweightstest.cc (100%) rename {src => dune/tectonic}/tests/nonoverlappingcouplingtest.cc (100%) rename {src => dune/tectonic/tests}/solverfactorytest.cc (95%) rename {src => dune/tectonic}/tests/supportpatchfactorytest.cc (100%) create mode 100644 dune/tectonic/time-stepping/CMakeLists.txt create mode 100644 dune/tectonic/time-stepping/adaptivetimestepper.cc rename {src => dune/tectonic}/time-stepping/adaptivetimestepper.hh (75%) create mode 100644 dune/tectonic/time-stepping/adaptivetimestepper_tmpl.cc rename {src => dune/tectonic}/time-stepping/coupledtimestepper.cc (63%) rename {src => dune/tectonic}/time-stepping/coupledtimestepper.hh (77%) create mode 100644 dune/tectonic/time-stepping/coupledtimestepper_tmpl.cc rename {src => dune/tectonic}/time-stepping/rate.cc (100%) rename {src => dune/tectonic}/time-stepping/rate.hh (100%) create mode 100644 dune/tectonic/time-stepping/rate/CMakeLists.txt rename {src => dune/tectonic}/time-stepping/rate/backward_euler.cc (100%) rename {src => dune/tectonic}/time-stepping/rate/backward_euler.hh (100%) rename {src => dune/tectonic}/time-stepping/rate/newmark.cc (100%) rename {src => dune/tectonic}/time-stepping/rate/newmark.hh (100%) rename {src => dune/tectonic}/time-stepping/rate/rateupdater.cc (100%) rename {src => dune/tectonic}/time-stepping/rate/rateupdater.hh (100%) rename {src => dune/tectonic}/time-stepping/rate/rateupdater_tmpl.cc (80%) rename {src => dune/tectonic}/time-stepping/rate_tmpl.cc (77%) rename {src => dune/tectonic}/time-stepping/state.cc (100%) rename {src => dune/tectonic}/time-stepping/state.hh (100%) create mode 100644 dune/tectonic/time-stepping/state/CMakeLists.txt rename {src => dune/tectonic}/time-stepping/state/ageinglawstateupdater.cc (100%) rename {src => dune/tectonic}/time-stepping/state/ageinglawstateupdater.hh (100%) rename {src => dune/tectonic}/time-stepping/state/calculation.wxm (100%) create mode 100644 dune/tectonic/time-stepping/state/explicit.aux create mode 100644 dune/tectonic/time-stepping/state/explicit.log create mode 100644 dune/tectonic/time-stepping/state/explicit.pdf create mode 100644 dune/tectonic/time-stepping/state/explicit.synctex.gz rename {src => dune/tectonic}/time-stepping/state/explicit.tex (100%) rename {src => dune/tectonic}/time-stepping/state/sliplawstateupdater.cc (100%) rename {src => dune/tectonic}/time-stepping/state/sliplawstateupdater.hh (100%) rename {src => dune/tectonic}/time-stepping/state/stateupdater.hh (85%) rename {src => dune/tectonic}/time-stepping/state_tmpl.cc (93%) rename {src => dune/tectonic}/time-stepping/updaters.hh (100%) create mode 100644 dune/tectonic/utils/CMakeLists.txt rename {src => dune/tectonic}/utils/almostequal.hh (100%) rename {src => dune/tectonic}/utils/debugutils.hh (100%) rename {src => dune/tectonic}/utils/diameter.hh (100%) rename dune/tectonic/{ => utils}/geocoordinate.hh (100%) rename dune/tectonic/{ => utils}/index-in-sorted-range.hh (100%) rename {src => dune/tectonic}/utils/tobool.hh (100%) delete mode 100644 program_structure.txt delete mode 100644 src/data-structures/contactnetwork_tmpl.cc create mode 100644 src/foam/CMakeLists.txt rename src/{one-body-problem-2D.cfg => foam/foam-2D.cfg} (55%) create mode 100644 src/foam/foam.cc create mode 100644 src/foam/foam.cfg delete mode 100644 src/multi-body-problem-data/geometry.tex create mode 100644 src/multi-body-problem/CMakeLists.txt rename src/{ => multi-body-problem}/multi-body-problem-2D.cfg (64%) rename src/{ => multi-body-problem}/multi-body-problem-3D.cfg (100%) rename src/{ => multi-body-problem}/multi-body-problem.cc (81%) rename src/{ => multi-body-problem}/multi-body-problem.cfg (80%) delete mode 100644 src/one-body-problem-3D.cfg delete mode 100644 src/one-body-problem-data/bc.hh delete mode 100644 src/one-body-problem-data/geometry.tex delete mode 100644 src/one-body-problem-data/midpoint.hh delete mode 100644 src/one-body-problem-data/mybody.hh delete mode 100644 src/one-body-problem-data/mygeometry.cc delete mode 100644 src/one-body-problem-data/mygeometry.hh delete mode 100644 src/one-body-problem-data/myglobalfrictiondata.hh delete mode 100644 src/one-body-problem-data/mygrid.cc delete mode 100644 src/one-body-problem-data/mygrid.hh delete mode 100644 src/one-body-problem-data/mygrid_tmpl.cc delete mode 100644 src/one-body-problem-data/patchfunction.hh delete mode 100644 src/one-body-problem-data/segmented-function.hh delete mode 100644 src/one-body-problem-data/weakpatch.hh delete mode 100644 src/one-body-problem.cc delete mode 100644 src/one-body-problem.cfg delete mode 100644 src/spatial-solving/CMakeLists.txt delete mode 100644 src/spatial-solving/fixedpointiterator_tmpl.cc delete mode 100644 src/spatial-solving/preconditioners/CMakeLists.txt delete mode 100644 src/spatial-solving/preconditioners/localproblem.hh delete mode 100644 src/spatial-solving/solverfactory.cc delete mode 100644 src/spatial-solving/solverfactory_tmpl.cc delete mode 100644 src/spatial-solving/tnnmg/CMakeLists.txt delete mode 100644 src/tests/contactmerge.cc delete mode 100644 src/time-stepping/adaptivetimestepper.cc delete mode 100644 src/time-stepping/adaptivetimestepper_tmpl.cc delete mode 100644 src/time-stepping/coupledtimestepper_tmpl.cc delete mode 100644 todo.txt diff --git a/data/2d-dip-contours-performance.tikz b/data/2d-dip-contours-performance.tikz new file mode 100644 index 00000000..b3aaffa7 --- /dev/null +++ b/data/2d-dip-contours-performance.tikz @@ -0,0 +1,91 @@ +\pgfplotsarraynew\heights{% + -40\\-20\\-10\\-5\\-2.5\\% + 0\\% + 2.5\\5\\10\\20\\40\\% +} +\def\fnamebase{2d-dip-contours} +\def\fname{rfpitol=100e-7} + +\newread\threequakesminread +\openin\threequakesminread=generated/timeframe:min:threequakes:\fname.tex +\read\threequakesminread to \threequakesmin +\closein\threequakesminread + +\newread\threequakesmaxread +\openin\threequakesmaxread=generated/timeframe:max:threequakes:\fname.tex +\read\threequakesmaxread to \threequakesmax +\closein\threequakesmaxread + +\begin{tikzpicture}[trim axis group left, trim axis group right] + \begin{groupplot}[ + xmin=\threequakesmin, xmax=\threequakesmax, max space between ticks=40pt, + x tick label style={ /pgf/number format/1000 sep={} }, + tick label style={font=\footnotesize}, + label style={font=\small}, + group style={ + x descriptions at = edge bottom, + group size=1 by 4, + vertical sep=0cm + }, + width=12cm, + enlargelimits=false] + \nextgroupplot[ + semithick, + height = 6.5cm, + /pgf/number format/1000 sep={}, + ymax=0.7, + colormap/jet, + y tick label style={ + /pgf/number format/.cd, + fixed, fixed zerofill, precision=2, + /tikz/.cd + }, + tick label style={font=\footnotesize}, + label style={font=\small}, + legend style={font=\small, + at={(1.05,1)}, + anchor=north west, + fill=none}, + ylabel = distance from trench, y unit = m, + legend cell align=right, + contour/labels=false, + contour prepared] + \pgfplotsinvokeforeach{1,...,9} { % level 0 and 10 are empty + \pgfplotscolormapaccess[0:10]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + \def\fnameX{generated/\fnamebase:\fname:level:% + \pgfplotsarrayvalueofelem#1\of\heights.tex} + \addplot[contour prepared={draw color=mycolor#1}, forget plot] table \fnameX; + \addlegendimage{line legend,color=mycolor#1} + \addlegendentry{% + \SI{\pgfplotsarrayvalueofelem#1\of\heights}{\micro\meter}} + }; + \nextgroupplot[ + semithick, + height = 3.5cm, + ylabel style={align=center}, ylabel = time step\\size, y unit = s, + ytick={1e-3,1e-2,1e-1}, + ymax = 1, ymin = 1e-4, + ymode = log] + \addplot[const plot, mark=none] table[col sep=comma, y=timeIncrement] + {generated/2d-performance:\fname.csv}; + \nextgroupplot[ + semithick, + height = 3.5cm, + ylabel style={align=center}, ylabel=fixed-point\\iterations, + ytick={2,4,6,8}, + ymin=0, ymax=10] + \addplot[const plot, mark=none] table[col sep=comma, y=fixedPointIterations] + {generated/2d-performance:\fname.csv}; + \nextgroupplot[ + semithick, + height = 3.5cm, + xlabel = time, x unit = s, + ylabel style={align=center}, ylabel=multigrid\\iterations, + ytick={5,10,15,20}, + ymin=0, ymax=25] + \addplot[const plot, mark=none] table[col sep=comma, y=multiGridIterations] + {generated/2d-performance:\fname.csv}; + \end{groupplot} +\end{tikzpicture} diff --git a/data/2d-dip-single-points.tikz b/data/2d-dip-single-points.tikz new file mode 100644 index 00000000..9717932d --- /dev/null +++ b/data/2d-dip-single-points.tikz @@ -0,0 +1,51 @@ +\def\fnamebase{dip-single-points} +\def\fname{rfpitol=100e-7} + +\newread\threequakesminread +\openin\threequakesminread=generated/timeframe:min:threequakes:\fname.tex +\read\threequakesminread to \threequakesmin +\closein\threequakesminread + +\newread\threequakesmaxread +\openin\threequakesmaxread=generated/timeframe:max:threequakes:\fname.tex +\read\threequakesmaxread to \threequakesmax +\closein\threequakesmaxread + +\begin{tikzpicture}[trim axis left, trim axis right] + \begin{axis}[ + xmin=\threequakesmin, xmax=\threequakesmax, max space between ticks=40pt, + /pgf/number format/1000 sep={}, + x tick label style={ + /pgf/number format/.cd, + 1000 sep={}, + /tikz/.cd + }, + y tick label style={ + /pgf/number format/.cd, + fixed, fixed zerofill, precision=2, + /tikz/.cd + }, + tick label style={font=\footnotesize}, + label style={font=\small}, + legend style={font=\small, at={(1.05,1)}, + anchor=north west, + fill=none}, + legend entries={ + \SI{15}{\centi\meter}, + \SI{30}{\centi\meter}, + \SI{45}{\centi\meter} + }, + ylabel style={align=center}, ylabel=vertical surface\\displacement, y unit = m, + change y base, y SI prefix=micro, + xlabel = time, x unit=s, + width = 12cm, + height = 4cm, + semithick] + \addplot[width=2pt] table[col sep=comma, x index = 0, y index=1] + {generated/\fnamebase:\fname.csv}; + \addplot[width=2pt, dashed] table[col sep=comma, x index = 0, y index=2] + {generated/\fnamebase:\fname.csv}; + \addplot[width=2pt, dotted] table[col sep=comma, x index = 0, y index=3] + {generated/\fnamebase:\fname.csv}; + \end{axis} +\end{tikzpicture} diff --git a/data/2d-effort-over-tolerance.tikz b/data/2d-effort-over-tolerance.tikz new file mode 100644 index 00000000..21f13f59 --- /dev/null +++ b/data/2d-effort-over-tolerance.tikz @@ -0,0 +1,17 @@ +\begin{tikzpicture}[trim axis left, trim axis right] + \begin{axis}[ + semithick, + width = 12cm, + height = 4cm, + xmode=log, + %ymin = 0, + % scaled y ticks=base 10:0, + xlabel = fixed point tolerance, + ylabel style={align=center}, ylabel = multigrid\\iterations, % (multigrid steps) + extra x ticks = 1e-5, + extra x tick labels = { time-stepping\\tolerance }, + extra x tick style = { align=center, grid = major, ticklabel pos=right } + ] + \addplot[mark=+] table[col sep=comma, y=mg] {generated/fpi-data.csv}; + \end{axis} +\end{tikzpicture} diff --git a/data/2d-velocity-contours-threequakes.tikz b/data/2d-velocity-contours-threequakes.tikz new file mode 100644 index 00000000..a144cefe --- /dev/null +++ b/data/2d-velocity-contours-threequakes.tikz @@ -0,0 +1,61 @@ +\pgfplotsarraynew\contourlevels{% + 1\\3\\ + 10\\30\\ + 100\\300\\ + 1000\\3000\\ +} + +\def\fname{threequakes:rfpitol=100e-7} + +\newread\threequakesminread +\openin\threequakesminread=generated/timeframe:min:\fname.tex +\read\threequakesminread to \threequakesmin +\closein\threequakesminread + +\newread\threequakesmaxread +\openin\threequakesmaxread=generated/timeframe:max:\fname.tex +\read\threequakesmaxread to \threequakesmax +\closein\threequakesmaxread + +\begin{tikzpicture}[trim axis left, trim axis right] + \begin{axis}[ + xmin=\threequakesmin, xmax=\threequakesmax, max space between ticks=40pt, + ymax=0.85, + colormap/jet, + x tick label style={ + /pgf/number format/.cd, + 1000 sep={}, + /tikz/.cd + }, + y tick label style={ + /pgf/number format/.cd, + fixed, fixed zerofill, precision=2, + /tikz/.cd + }, + tick label style={font=\footnotesize}, + label style={font=\small}, + legend style={font=\small, + at={(1.05,1)}, + anchor=north west, + fill=none}, + ylabel = distance from trench, y unit = m, + xlabel = time, x unit=s, + width = 12cm, height = 6.5cm, + legend cell align=right, + contour/labels=false, + enlargelimits=false, + semithick] + + \pgfplotsinvokeforeach{0,2,4,6} { + \pgfplotscolormapaccess[0:7]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + \def\fnameX{generated/2d-velocity-contours:\fname:level:% + \pgfplotsarrayvalueofelem#1\of\contourlevels.tex} + \addplot[contour prepared={draw color=mycolor#1}, forget plot] table \fnameX; + \addlegendimage{line legend,color=mycolor#1} + \addlegendentry{% + \SI{\pgfplotsarrayvalueofelem#1\of\contourlevels}{\micro\meter/\second}} + }; + \end{axis} +\end{tikzpicture} diff --git a/data/2d-velocity-contours-zoom.tikz b/data/2d-velocity-contours-zoom.tikz new file mode 100644 index 00000000..24b77cf4 --- /dev/null +++ b/data/2d-velocity-contours-zoom.tikz @@ -0,0 +1,51 @@ +\pgfplotsarraynew\contourlevels{% + 1\\3\\ + 10\\30\\ + 100\\300\\ + 1000\\3000\\ +} + +\def\fname{zoom:rfpitol=100e-7} +\begin{tikzpicture}[trim axis left, trim axis right] + \begin{axis}[ + max space between ticks=40pt, + ymax=0.7, + colormap/jet, + x tick label style={ + /pgf/number format/.cd, + fixed, fixed zerofill, precision=2, + 1000 sep={}, + /tikz/.cd + }, + y tick label style={ + /pgf/number format/.cd, + fixed, fixed zerofill, precision=2, + /tikz/.cd + }, + tick label style={font=\footnotesize}, + label style={font=\small}, + legend style={font=\small, + at={(1.05,1)}, + anchor=north west, + fill=none}, + ylabel = distance from trench, y unit = m, + xlabel = time, x unit=s, + width = 12cm, height = 6.5cm, + legend cell align=right, + enlargelimits=false, + contour/labels=false, + semithick] + + \pgfplotsinvokeforeach{0,...,6} { % level 7 is empty + \pgfplotscolormapaccess[0:7]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + \def\fnameX{generated/2d-velocity-contours:\fname:level:% + \pgfplotsarrayvalueofelem#1\of\contourlevels.tex} + \addplot[contour prepared={draw color=mycolor#1}, forget plot] table \fnameX; + \addlegendimage{line legend,color=mycolor#1} + \addlegendentry{% + \SI{\pgfplotsarrayvalueofelem#1\of\contourlevels}{\micro\meter/\second}} + }; + \end{axis} +\end{tikzpicture} diff --git a/data/3d-performance.tikz b/data/3d-performance.tikz new file mode 100644 index 00000000..9eba91b8 --- /dev/null +++ b/data/3d-performance.tikz @@ -0,0 +1,57 @@ +\def\fname{rtol=1e-5_diam=1e-2} + +\newread\threequakesminread +\openin\threequakesminread=generated/timeframe:min:threequakes:\fname.tex +\read\threequakesminread to \threequakesmin +\closein\threequakesminread + +\newread\threequakesmaxread +\openin\threequakesmaxread=generated/timeframe:max:threequakes:\fname.tex +\read\threequakesmaxread to \threequakesmax +\closein\threequakesmaxread + +\begin{tikzpicture}[trim axis group left, trim axis group right] + \begin{groupplot}[ + xmin=\threequakesmin, xmax=\threequakesmax, + max space between ticks=40pt, + x tick label style={ + /pgf/number format/.cd, + 1000 sep={}, + /tikz/.cd + }, + tick label style={font=\footnotesize}, + label style={font=\small}, + group style={ + x descriptions at = edge bottom, + group size=1 by 3, + vertical sep=0cm + }, + height=3.5cm, width=12cm, + enlargelimits=false] + + \nextgroupplot[ + semithick, + ylabel style={align=center}, ylabel = time step\\size, y unit = s, + ytick={1e-3,1e-2,1e-1}, + ymax = 1, ymin = 1e-4, + ymode = log] + \addplot[const plot, mark=none] table[col sep=comma, y=timeIncrement] + {generated/3d-performance:\fname.csv}; + \nextgroupplot[ + semithick, + ylabel style={align=center}, ylabel = fixed-point\\iterations, + ytick={2,4,6,8}, + ymin=0, ymax=10] + \addplot[const plot, mark=none] table[col sep=comma, y=fixedPointIterations] + {generated/3d-performance:\fname.csv}; + \nextgroupplot[ + semithick, + xlabel = time, x unit = s, + ylabel style={align=center}, ylabel=multigrid\\iterations, + ytick={5,10,15,20}, + ymin=0, ymax=25 + ] + \addplot[const plot, mark=none] table[col sep=comma, y=multiGridIterations] + {generated/3d-performance:\fname.csv}; + \end{groupplot} +\end{tikzpicture} diff --git a/data/3d-velocity-contours.tikz b/data/3d-velocity-contours.tikz new file mode 100644 index 00000000..0bd999b9 --- /dev/null +++ b/data/3d-velocity-contours.tikz @@ -0,0 +1,156 @@ +\def\fname{generated/3d-velocity-contours:rtol=1e-5_diam=1e-2} +\pgfplotstableread[col sep=comma]{\fname:times.csv}\myloadedtable + +\pgfplotsarraynew\contourlevels{% + 1\\2\\3\\5\\% + 10\\20\\30\\50\\% + 100\\200\\300\\500\\% + 1000\\ +} + +\begin{tikzpicture}[trim axis group left, trim axis group right] + \begin{groupplot}[ + group style={ + y descriptions at = edge left, + group size=6 by 1, + horizontal sep=0cm + }, + ymin=-0.30, ymax= 0.30, + enlarge x limits=false, + colormap/jet, + y tick label style={ + /pgf/number format/.cd, + fixed, fixed zerofill, precision=2, + /tikz/.cd + }, + ytick = {-0.30,-0.20,-0.10,0.00,0.10,0.20,0.30}, + tick label style={font=\footnotesize}, + label style={font=\small}, + width = 3.5cm, height = 6cm, + enlargelimits=false, + contour/labels=false, + % + groupplot xlabel={distance from trench [\si{\meter}]}, + ] + + \nextgroupplot[semithick, xlabel = { + \pgfplotstablegetelem{0}{times}\of\myloadedtable% + $t_0 \approx + \SI[round-mode=places,round-precision=0]{\pgfplotsretval}{\second}$ + }, + ylabel = width, y unit = m] + \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30); % X + \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y + \pgfplotsinvokeforeach{0,...,12} { + \pgfplotscolormapaccess[0:14]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + + \pgfplotstablegetelem{0}{timeSteps}\of\myloadedtable + \edef\fnameX{\fname:% + step:\pgfplotsretval:% + level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex} + \addplot[contour prepared={draw color=mycolor#1}] table \fnameX; + }; + + \nextgroupplot[semithick, xlabel = { + \pgfplotstablegetelem{1}{timeOffsets}\of\myloadedtable% + $t_0 + + \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$ + }] + \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30); % X + \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y + \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty + \pgfplotscolormapaccess[0:14]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + \pgfplotstablegetelem{1}{timeSteps}\of\myloadedtable + \edef\fnameX{\fname:% + step:\pgfplotsretval:% + level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex} + \addplot[contour prepared={draw color=mycolor#1}] table \fnameX; + }; + + \nextgroupplot[semithick, xlabel = { + \pgfplotstablegetelem{2}{timeOffsets}\of\myloadedtable% + $t_0 + + \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$ + }] + \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30); % X + \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y + \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty + \pgfplotscolormapaccess[0:14]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + \pgfplotstablegetelem{2}{timeSteps}\of\myloadedtable + \edef\fnameX{\fname:% + step:\pgfplotsretval:% + level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex} + \addplot[contour prepared={draw color=mycolor#1}] table \fnameX; + }; + + \nextgroupplot[semithick, xlabel = { + \pgfplotstablegetelem{3}{timeOffsets}\of\myloadedtable% + $t_0 + + \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$ + }, + legend columns=4, + legend cell align=right, + legend style={font=\small, + at={(0,1.05)}, + anchor=south, + fill=none}, + ] + \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30); % X + \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y + \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty + \pgfplotscolormapaccess[0:14]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + \pgfplotstablegetelem{3}{timeSteps}\of\myloadedtable + \edef\fnameX{\fname:% + step:\pgfplotsretval:% + level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex} + \addplot[contour prepared={draw color=mycolor#1}, forget plot] table \fnameX; + \addlegendimage{line legend,color=mycolor#1} + \addlegendentry{% + \SI{\pgfplotsarrayvalueofelem#1\of\contourlevels}{\micro\meter/\second}} + }; + + \nextgroupplot[semithick, xlabel = { + \pgfplotstablegetelem{4}{timeOffsets}\of\myloadedtable% + $t_0 + + \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$ + }] + \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30); % X + \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y + \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty + \pgfplotscolormapaccess[0:14]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + \pgfplotstablegetelem{4}{timeSteps}\of\myloadedtable + \edef\fnameX{\fname:% + step:\pgfplotsretval:% + level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex} + \addplot[contour prepared={draw color=mycolor#1}] table \fnameX; + }; + + \nextgroupplot[semithick, xlabel = { + \pgfplotstablegetelem{5}{timeOffsets}\of\myloadedtable% + $t_0 + + \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$ + }] + \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30); % X + \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y + \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty + \pgfplotscolormapaccess[0:14]{#1}{jet} + \def\TEMP{\definecolor{mycolor#1}{rgb}} + \expandafter\TEMP\expandafter{\pgfmathresult} + \pgfplotstablegetelem{5}{timeSteps}\of\myloadedtable + \edef\fnameX{\fname:% + step:\pgfplotsretval:% + level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex} + \addplot[contour prepared={draw color=mycolor#1}] table \fnameX; + }; + \end{groupplot} +\end{tikzpicture} diff --git a/data/boxplot.tikz b/data/boxplot.tikz new file mode 100644 index 00000000..9f087cc4 --- /dev/null +++ b/data/boxplot.tikz @@ -0,0 +1,43 @@ +\def\simulationtag{rfpitol=100e-7} +\begin{tikzpicture}[trim axis group left, trim axis group right] + \begin{groupplot}[ + tick label style={font=\footnotesize}, + label style={font=\small}, + % + group style={ + y descriptions at = edge left, + group size=3 by 1, + horizontal sep=0.75cm + }, + height=4cm, + width=4.5cm, + % + ytick={1,2,3}, + yticklabels={experiment, simulation} + ] + % + \nextgroupplot[semithick, xlabel = recurrence time, x unit = s, xmode=log, + log ticks with fixed point, xtick={5,10,20,40}] + \addplot[mark=+, boxplot={ box extend = 0.5 }] + table[y index=0] {generated/boxplot-data:lab:recurrence.tex}; + \addplot[mark=+, boxplot={ box extend = 0.5 }] + table[y index=0] {generated/boxplot-data:simulation:\simulationtag:recurrence.tex}; + % + \nextgroupplot[semithick, xlabel = rupture width, x unit=m, xmin=0, xmax=0.4, + extra x ticks = 0.2, + extra x tick labels = , + extra x tick style = { grid = major } + ] + \addplot[mark=+, boxplot={ box extend = 0.5 }] + table[y index=0] {generated/boxplot-data:lab:ruptureWidth.tex}; + \addplot[mark=+, boxplot={ box extend = 0.5 }] + table[y index=0] {generated/boxplot-data:simulation:\simulationtag:ruptureWidth.tex}; + % + \nextgroupplot[semithick, xlabel = peak slip, x unit=mm, xmode=log, log ticks with fixed point, + xtick={0.03, 0.06, 0.12}] + \addplot[mark=+, boxplot={ box extend = 0.5 }] + table[y index=0] {generated/boxplot-data:lab:peakSlip.tex}; + \addplot[mark=+, boxplot={ box extend = 0.5 }] + table[y index=0] {generated/boxplot-data:simulation:\simulationtag:peakSlip.tex}; + \end{groupplot} +\end{tikzpicture} diff --git a/data/config.ini b/data/config.ini new file mode 100644 index 00000000..a3a37a49 --- /dev/null +++ b/data/config.ini @@ -0,0 +1,4 @@ +[directories] +simulation = ~/group/publications/2016-PippingKornhuberRosenauOncken +experiment = ~/group/publications/2016-RosenauCorbiDominguezRudolfRitterPipping +output = generated diff --git a/data/includes.tex b/data/includes.tex new file mode 100644 index 00000000..32594a4b --- /dev/null +++ b/data/includes.tex @@ -0,0 +1,51 @@ +\usepackage{pgfplots} +\pgfplotsset{compat=1.11} % FIXME: 1.12 would be nice; debian:8.7 only has 1.11 +\usepackage{pgfplotstable} +\usepgfplotslibrary{groupplots} +\usepgfplotslibrary{statistics} +\usepgfplotslibrary{units} + + +%% Typeset the mu from '[xy] SI prefix=micro' as an upright mu +%% From https://tex.stackexchange.com/a/224574 +\pgfplotsset{ + x SI prefix/micro/.style={/pgfplots/axis base prefix={axis x base 6 prefix \micro}}, + y SI prefix/micro/.style={/pgfplots/axis base prefix={axis y base 6 prefix \micro}}, + z SI prefix/micro/.style={/pgfplots/axis base prefix={axis z base 6 prefix \micro}}, + unit code/.code 2 args={\si{#1#2}}, +} + +%% Add support for 'groupplot [xy]label' +%% From http://tex.stackexchange.com/a/117935/16940, see also +%% https://sourceforge.net/p/pgfplots/feature-requests/48/ +\makeatletter +\pgfplotsset{ + groupplot xlabel/.initial={}, + every groupplot x label/.style={ + at={($({\pgfplots@group@name\space c1r\pgfplots@group@rows.west}|-{\pgfplots@group@name\space c1r\pgfplots@group@rows.outer south})!0.5!({\pgfplots@group@name\space c\pgfplots@group@columns r\pgfplots@group@rows.east}|-{\pgfplots@group@name\space c\pgfplots@group@columns r\pgfplots@group@rows.outer south})$)}, + anchor=north, + }, + groupplot ylabel/.initial={}, + every groupplot y label/.style={ + rotate=90, + at={($({\pgfplots@group@name\space c1r1.north}-|{\pgfplots@group@name\space c1r1.outer +west})!0.5!({\pgfplots@group@name\space c1r\pgfplots@group@rows.south}-|{\pgfplots@group@name\space c1r\pgfplots@group@rows.outer west})$)}, + anchor=south + }, + execute at end groupplot/.code={% + \node [/pgfplots/every groupplot x label] +{\pgfkeysvalueof{/pgfplots/groupplot xlabel}}; + \node [/pgfplots/every groupplot y label] +{\pgfkeysvalueof{/pgfplots/groupplot ylabel}}; + } +} + +\def\endpgfplots@environment@groupplot{% + \endpgfplots@environment@opt% + \pgfkeys{/pgfplots/execute at end groupplot}% + \endgroup% +} +\makeatother + +%% Have \includegraphics{} support tikz files +\usepackage{tikzscale} \ No newline at end of file diff --git a/data/standalone/2d-dip-contours-performance.tex b/data/standalone/2d-dip-contours-performance.tex new file mode 100644 index 00000000..8df31895 --- /dev/null +++ b/data/standalone/2d-dip-contours-performance.tex @@ -0,0 +1,7 @@ +\documentclass[border={3cm 0cm}]{standalone} +\usepackage{siunitx} +\input{includes} + +\begin{document} +\includegraphics{2d-dip-contours-performance.tikz} +\end{document} diff --git a/data/standalone/2d-dip-single-points.tex b/data/standalone/2d-dip-single-points.tex new file mode 100644 index 00000000..eaadd61b --- /dev/null +++ b/data/standalone/2d-dip-single-points.tex @@ -0,0 +1,7 @@ +\documentclass[border={3cm 0cm}]{standalone} +\usepackage{siunitx} +\input{includes} + +\begin{document} +\includegraphics{2d-dip-single-points.tikz} +\end{document} diff --git a/data/standalone/2d-effort-over-tolerance.tex b/data/standalone/2d-effort-over-tolerance.tex new file mode 100644 index 00000000..45f6bc94 --- /dev/null +++ b/data/standalone/2d-effort-over-tolerance.tex @@ -0,0 +1,7 @@ +\documentclass[border={3cm 0cm}]{standalone} +\usepackage{siunitx} +\input{includes} + +\begin{document} +\includegraphics{2d-effort-over-tolerance.tikz} +\end{document} diff --git a/data/standalone/2d-velocity-contours-threequakes.tex b/data/standalone/2d-velocity-contours-threequakes.tex new file mode 100644 index 00000000..2e2d9cb1 --- /dev/null +++ b/data/standalone/2d-velocity-contours-threequakes.tex @@ -0,0 +1,7 @@ +\documentclass[border={3cm 0cm}]{standalone} +\usepackage{siunitx} +\input{includes} + +\begin{document} +\includegraphics{2d-velocity-contours-threequakes} +\end{document} diff --git a/data/standalone/2d-velocity-contours-zoom.tex b/data/standalone/2d-velocity-contours-zoom.tex new file mode 100644 index 00000000..e24d742d --- /dev/null +++ b/data/standalone/2d-velocity-contours-zoom.tex @@ -0,0 +1,7 @@ +\documentclass[border={3cm 0cm}]{standalone} +\usepackage{siunitx} +\input{includes} + +\begin{document} +\includegraphics{2d-velocity-contours-zoom} +\end{document} diff --git a/data/standalone/3d-performance.tex b/data/standalone/3d-performance.tex new file mode 100644 index 00000000..b1e3456f --- /dev/null +++ b/data/standalone/3d-performance.tex @@ -0,0 +1,7 @@ +\documentclass[border={3cm 0cm}]{standalone} +\usepackage{siunitx} +\input{includes} + +\begin{document} +\includegraphics{3d-performance.tikz} +\end{document} diff --git a/data/standalone/3d-velocity-contours.tex b/data/standalone/3d-velocity-contours.tex new file mode 100644 index 00000000..be7f8c79 --- /dev/null +++ b/data/standalone/3d-velocity-contours.tex @@ -0,0 +1,7 @@ +\documentclass[border={3cm 0cm}]{standalone} +\usepackage{siunitx} +\input{includes} + +\begin{document} +\includegraphics{3d-velocity-contours.tikz} +\end{document} diff --git a/data/standalone/Makefile b/data/standalone/Makefile new file mode 100644 index 00000000..c9e461a0 --- /dev/null +++ b/data/standalone/Makefile @@ -0,0 +1,18 @@ +PDFs=\ + 2d-dip-contours-performance.pdf \ + 2d-dip-single-points.pdf \ + 2d-effort-over-tolerance.pdf \ + 2d-velocity-contours-threequakes.pdf \ + 2d-velocity-contours-zoom.pdf \ + 3d-performance.pdf \ + 3d-velocity-contours.pdf \ + boxplot.pdf +PNGs=$(PDFs:.pdf=.png) + +pdf: $(PDFs) +%.pdf: standalone/%.tex + latexmk -pdf $< + +png: $(PNGs) +%.png: %.pdf + convert -density 300 $< -quality 100 $@ diff --git a/data/standalone/boxplot.tex b/data/standalone/boxplot.tex new file mode 100644 index 00000000..1fd38393 --- /dev/null +++ b/data/standalone/boxplot.tex @@ -0,0 +1,7 @@ +\documentclass[border={3cm 0cm}]{standalone} +\usepackage{siunitx} +\input{includes} + +\begin{document} +\input{boxplot.tikz} +\end{document} diff --git a/data/tools/2d-dip-contours.R b/data/tools/2d-dip-contours.R new file mode 100644 index 00000000..04b36652 --- /dev/null +++ b/data/tools/2d-dip-contours.R @@ -0,0 +1,108 @@ +source('tools/support/findQuakes.R') +source('tools/support/writeContours.R') +Rcpp::sourceCpp('tools/support/trapezoidal.cpp') + +finalTime <- 1000 # s +specialTrenchDistances <- c(0.15,0.30,0.45) # m +convergenceVelocity <- 5e-5 # m/s + +last <- function(x) x[[length(x)]] +paste. <- function(...) paste(..., sep='.') +pasteColon<- function(...) paste(..., sep=':') + +directories <- ini::read.ini('config.ini')$directories +dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE) +for (basedir in c("rfpitol=100e-7")) { + dir <- file.path(directories[['simulation']], + '2d-lab-fpi-tolerance', basedir) + h5file <- h5::h5file(file.path(dir, 'output.h5'), 'r') + relativeTime <- h5file['relativeTime'][] + realTime <- finalTime * relativeTime + + calcMask <- relativeTime >= 0.7 + calcTime <- realTime[calcMask] + calcDuration <- last(calcTime) - calcTime[[1]] + calcRange <- range(which(calcMask)) + calcLength <- sum(calcMask) + + ## We are interested in an enlarged time range around actual events here, + ## (and no other quantities!) hence we pass a very low velocity here. + quakes <- findQuakes(1e-6 + convergenceVelocity, + h5file['/frictionalBoundary/velocity'][,,], + indices = calcRange[1]:calcRange[2]) + quakes$beginning <- realTime[quakes$beginningIndex] + quakes$ending <- realTime[quakes$endingIndex] + quakes$duration <- quakes$ending - quakes$beginning + numQuakes <- nrow(quakes) + + relaxedTime <- extendrange(c(quakes[[numQuakes-2,'beginning']], + quakes[[numQuakes, 'ending']]), f=0.02) + threeQuakeTimeMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]]) + + plotMask <- threeQuakeTimeMask + plotTime <- realTime[plotMask] + plotRange <- range(which(plotMask)) + plotLength <- sum(plotMask) + + write(relaxedTime[[1]], + file.path(directories[['output']], + paste.(pasteColon('timeframe', 'min', 'threequakes', basedir), + 'tex'))) + write(relaxedTime[[2]], + file.path(directories[['output']], + paste.(pasteColon('timeframe', 'max', 'threequakes', basedir), + 'tex'))) + + surfaceCoordinates <- h5file['/surface/coordinates'][] + surfaceTrenchDistance <- surfaceCoordinates[,1] / cos(atan(.27)) + perm <- order(surfaceTrenchDistance) + + displacement <- h5file['/surface/displacement'] + # This is the displacement imposed through the Dirichlet condition at the last node + displacementOffset <- displacement[calcRange[1]:calcRange[2],last(perm),1] + balancedSurfaceDisplacement <- matrix(nrow = plotLength, ncol = displacement@dim[2]) + for (k in 1:displacement@dim[2]) { + d <- displacement[calcRange[1]:calcRange[2],k,1:2] + d[,,1] <- d[,,1] - displacementOffset + # We're in a tilted coordinate system + dv <- -sin(atan(.27))*d[,,1] + cos(atan(.27))*d[,,2] + meanVertSurfaceDisplacement <- trapezoidal(calcTime, dv) / calcDuration + balancedSurfaceDisplacement[,k] <- (dv - meanVertSurfaceDisplacement)[ + (plotRange[1] - calcRange[1] + 1):(plotRange[2] - calcRange[1] + 1) + ] + } + + ## Interpolate velocity to special points from surrounding velocities + { + data <- matrix(nrow=plotLength, ncol=1+length(specialTrenchDistances)) + data[,1] <- plotTime + for (k in seq(plotLength)) { + interpolant <- approxfun(surfaceTrenchDistance[perm], + balancedSurfaceDisplacement[k,perm]) + for (i in seq(specialTrenchDistances)) { + specialTrenchDistance <- specialTrenchDistances[[i]] + data[k,i+1] <- interpolant(specialTrenchDistance) + } + } + singleDataName <- file.path(directories[['output']], + paste.(pasteColon('dip-single-points', basedir), + 'csv')) + write.csv(data, singleDataName, row.names = FALSE) + } + h5::h5close(h5file) + + printlevels <- c('-40','-20','-10','-5','-2.5','0','2.5','5','10','20','40') + levels <- as.numeric(printlevels) * 1e-6 + + ret <- contourLines(plotTime, + surfaceTrenchDistance[perm], + balancedSurfaceDisplacement[,perm], + levels=levels) + + for (i in seq(printlevels)) + writeContours(ret, levels[[i]], + file.path(directories[['output']], + paste.(pasteColon('2d-dip-contours', basedir, + 'level', printlevels[[i]]), + 'tex'))) +} diff --git a/data/tools/2d-event-writer.R b/data/tools/2d-event-writer.R new file mode 100644 index 00000000..fffe5e28 --- /dev/null +++ b/data/tools/2d-event-writer.R @@ -0,0 +1,68 @@ +source('tools/support/findQuakes.R') + +finalTime <- 1000 # s +convergenceVelocity <- 5e-5 # m/s +criticalVelocity <- 1000e-6 + convergenceVelocity + +paste. <- function(...) paste(..., sep='.') +pasteColon<- function(...) paste(..., sep=':') + +directories <- ini::read.ini('config.ini')$directories +dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE) +for (basedir in c("rfpitol=100e-7")) { + dir <- file.path(directories[['simulation']], + '2d-lab-fpi-tolerance', basedir) + h5file <- h5::h5file(file.path(dir, 'output.h5'), 'r') + relativeTime <- h5file['relativeTime'][] + realTime <- finalTime * relativeTime + + velocityProxy<- h5file['/frictionalBoundary/velocity'] + + quakes <- findQuakes(criticalVelocity, velocityProxy, + indices = 1:dim(velocityProxy)[1], 1) + + basalCoordinates <- h5file['/frictionalBoundary/coordinates'][] + + maximumVelocities<- maxVelocity(velocityProxy[,,1]) + displacement <- h5file['/frictionalBoundary/displacement'] + numVertices <- dim(displacement)[[2]] + for (quakeID in seq(nrow(quakes))) { + qb <- quakes[[quakeID,'beginningIndex']] + qe <- quakes[[quakeID,'endingIndex']] + localSlippingTimes <- abs(velocityProxy[qb:qe,,1][,,1]) > criticalVelocity + + qd <- displacement[qb:qe,,1] + slip <- vector(mode='numeric', length=numVertices) + for (i in seq(numVertices)) { + if (any(localSlippingTimes[,i])) { + begs <- positiveStarts(localSlippingTimes[,i]) + ends <- negativeStarts(localSlippingTimes[,i]) + slip[i]<- sum(qd[ends,i,] - qd[begs,i,]) + } + } + quakes[quakeID,'peakSlip'] <- max(abs(slip)) + quakes[quakeID,'peakSlipRate'] <- max(maximumVelocities[qb:qe]) + + maxRuptureWidth <- 0 + for (ts in seq(dim(localSlippingTimes)[[1]])) { + st <- localSlippingTimes[ts,] + if (!any(st)) + next; + + slippingCoordinates <- basalCoordinates[st,1] # x-coordinate only + maxRuptureWidth <- max(maxRuptureWidth, diff(range(slippingCoordinates))) + } + quakes[quakeID,'ruptureWidth'] <- maxRuptureWidth + } + h5::h5close(h5file) + + quakes$beginning <- realTime[quakes$beginningIndex] + quakes$ending <- realTime[quakes$endingIndex] + + write.csv(quakes[c('beginning','ending', + 'peakSlip','peakSlipRate', + 'ruptureWidth')], + row.names = FALSE, quote = FALSE, + file = file.path(directories[['output']], + paste.(pasteColon('events', basedir), 'csv'))) +} diff --git a/data/tools/2d-fpi-tolerance.R b/data/tools/2d-fpi-tolerance.R new file mode 100644 index 00000000..1442e4e6 --- /dev/null +++ b/data/tools/2d-fpi-tolerance.R @@ -0,0 +1,41 @@ +rfpitols <- c('1e-7', '2e-7', '3e-7', '5e-7', + '10e-7', '20e-7', '30e-7', '50e-7', + '100e-7', '200e-7', '300e-7', '500e-7', + '1000e-7', '2000e-7', '3000e-7', '5000e-7', + '10000e-7', '20000e-7', '30000e-7', '50000e-7', + '100000e-7') +numEntries <- length(rfpitols) + +data <- data.frame(row.names = rfpitols, + tol = rep(NA, numEntries), + time = rep(NA, numEntries), + fpi = rep(NA, numEntries), + mg = rep(NA, numEntries)) + +directories <- ini::read.ini('config.ini')$directories +dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE) +for (rfpitol in rfpitols) { + basedir <- paste('rfpitol', rfpitol, sep='=') + dir <- file.path(directories[['simulation']], + '2d-lab-fpi-tolerance', basedir) + h5file <- h5::h5file(file.path(dir, 'output.h5'), 'r') + + data[rfpitol,'tol'] <- as.numeric(rfpitol) + + relativeTimeProxy <- h5file['/relativeTime'] + relativeTimeLen <- relativeTimeProxy@dim + data[rfpitol,'time'] <- relativeTimeProxy[relativeTimeProxy@dim] + + ## FIXME: why do we drop the first entry? + fixedPointIterationsProxy <- h5file["/iterations/fixedPoint/total"] + fixedPointIterationsLen <- fixedPointIterationsProxy@dim + data[rfpitol,'fpi'] <- sum(fixedPointIterationsProxy[2:fixedPointIterationsLen]) + + multiGridIterationsProxy <- h5file["/iterations/multiGrid/total"] + multiGridIterationsLen <- multiGridIterationsProxy@dim + data[rfpitol,'mg'] <- sum(multiGridIterationsProxy[2:multiGridIterationsLen]) + h5::h5close(h5file) +} + +write.csv(data, file.path(directories[['output']], 'fpi-data.csv'), + row.names = FALSE, quote = FALSE) diff --git a/data/tools/2d-performance.R b/data/tools/2d-performance.R new file mode 100644 index 00000000..0f3ab59c --- /dev/null +++ b/data/tools/2d-performance.R @@ -0,0 +1,58 @@ +source('tools/support/findQuakes.R') + +finalTime <- 1000 # s +convergenceVelocity <- 5e-5 # m/s + +paste. <- function(...) paste(..., sep='.') +pasteColon<- function(...) paste(..., sep=':') + +directories <- ini::read.ini('config.ini')$directories +dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE) +for (basedir in c("rfpitol=100e-7")) { + dir <- file.path(directories[['simulation']], + '2d-lab-fpi-tolerance', basedir) + h5file <- h5::h5file(file.path(dir, 'output.h5'), 'r') + relativeTime <- h5file['relativeTime'][] + realTime <- finalTime * relativeTime + + velocityProxy<- h5file['/frictionalBoundary/velocity'] + + ## We are interested in an enlarged time range around actual events here, + ## (and no other quantities!) hence we pass a very low velocity here. + quakes <- findQuakes(1e-6 + convergenceVelocity, velocityProxy, + indices = 1:dim(velocityProxy)[1], 1) + quakes$beginning <- realTime[quakes$beginningIndex] + quakes$ending <- realTime[quakes$endingIndex] + quakes$duration <- quakes$ending - quakes$beginning + numQuakes <- nrow(quakes) + + relaxedTime <- extendrange(c(quakes[[numQuakes-2,'beginning']], + quakes[[numQuakes, 'ending']]), f=0.02) + threeQuakeTimeMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]]) + plotMask <- threeQuakeTimeMask + plotIndices<- which(plotMask) + plotIndices<- c(plotIndices[1]-1,plotIndices,plotIndices[length(plotIndices)]+1) + + write(relaxedTime[[1]], + file.path(directories[['output']], + paste.(pasteColon('timeframe', 'min', 'threequakes', + basedir), 'tex'))) + write(relaxedTime[[2]], + file.path(directories[['output']], + paste.(pasteColon('timeframe', 'max', 'threequakes', + basedir), 'tex'))) + + timeWindow = realTime[plotIndices] + + relativeTau <- h5file['relativeTimeIncrement'][] + fixedPointIterations <- h5file['/iterations/fixedPoint/final'][] + multiGridIterations <- h5file['/iterations/multiGrid/final'][] + write.csv(data.frame(time = timeWindow, + timeIncrement = finalTime * relativeTau[plotIndices], + fixedPointIterations = fixedPointIterations[plotIndices], + multiGridIterations = multiGridIterations[plotIndices]), + file.path(directories[['output']], + paste.(pasteColon('2d-performance', basedir), 'csv')), + row.names = FALSE, quote = FALSE) + h5::h5close(h5file) +} diff --git a/data/tools/2d-velocity-contours.R b/data/tools/2d-velocity-contours.R new file mode 100644 index 00000000..dd44112c --- /dev/null +++ b/data/tools/2d-velocity-contours.R @@ -0,0 +1,95 @@ +source('tools/support/findQuakes.R') +source('tools/support/writeContours.R') + +finalTime <- 1000 # s +convergenceVelocity <- 5e-5 # m/s + +paste. <- function(...) paste(..., sep='.') +pasteColon<- function(...) paste(..., sep=':') + +directories <- ini::read.ini('config.ini')$directories +dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE) +for (basedir in c("rfpitol=100e-7")) { + dir <- file.path(directories[['simulation']], + '2d-lab-fpi-tolerance', basedir) + h5file <- h5::h5file(file.path(dir, 'output.h5'), 'r') + relativeTime <- h5file['relativeTime'][] + realTime <- finalTime * relativeTime + + velocityProxy<- h5file['/frictionalBoundary/velocity'] + + basalCoordinates <- h5file['/frictionalBoundary/coordinates'][] + basalTrenchDistance <- basalCoordinates[,1] + perm <- order(basalTrenchDistance) + sortedBasalTrenchDistance <- basalTrenchDistance[perm] + + { + ## We are interested in an enlarged time range around actual events here, + ## (and no other quantities!) hence we pass a very low velocity here. + quakes <- findQuakes(1e-6 + convergenceVelocity, velocityProxy, + indices = 1:dim(velocityProxy)[1], 1) + quakes$beginning <- realTime[quakes$beginningIndex] + quakes$ending <- realTime[quakes$endingIndex] + quakes$duration <- quakes$ending - quakes$beginning + numQuakes <- nrow(quakes) + + relaxedTime <- extendrange(c(quakes[[numQuakes-2,'beginning']], + quakes[[numQuakes, 'ending']]), f=0.02) + plotMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]]) + plotIndices<- which(plotMask) + + write(relaxedTime[[1]], + file.path(directories[['output']], + paste.(pasteColon('timeframe', 'min', 'threequakes', + basedir), 'tex'))) + write(relaxedTime[[2]], + file.path(directories[['output']], + paste.(pasteColon('timeframe', 'max', 'threequakes', + basedir), 'tex'))) + + printlevels <- c('1000','100','10','1') + levels <- 1e-6 * as.numeric(printlevels) + convergenceVelocity + ret <- contourLines(realTime[plotIndices], + sortedBasalTrenchDistance, + abs(velocityProxy[plotIndices,perm,1][,,1]), + levels = levels) + + for (i in seq(printlevels)) + writeContours(ret, levels[[i]], + file.path(directories[['output']], + paste.(pasteColon('2d-velocity-contours', + 'threequakes', basedir, 'level', + printlevels[[i]]), 'tex'))) + } + { + ## We are interested in an enlarged time range around actual events here, + ## (and no other quantities!) hence we pass a rather low velocity here. + quakes <- findQuakes(300e-6 + convergenceVelocity, velocityProxy, + indices = 1:dim(velocityProxy)[1], 1) + quakes$beginning <- realTime[quakes$beginningIndex] + quakes$ending <- realTime[quakes$endingIndex] + quakes$duration <- quakes$ending - quakes$beginning + numQuakes <- nrow(quakes) + quake <- quakes[numQuakes,] + relaxedTime <- + c(quake[['beginning']] - 0.9*(quake[['ending']] - quake[['beginning']]), + quake[['ending']] + 0.1*(quake[['ending']] - quake[['beginning']])) + plotMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]]) + plotIndices<- which(plotMask) + + printlevels <- c('3000','1000','300','100','30','10','3','1') + levels <- 1e-6 * as.numeric(printlevels) + convergenceVelocity + ret <- contourLines(realTime[plotIndices], + sortedBasalTrenchDistance, + abs(velocityProxy[plotIndices,perm,1][,,1]), + levels = levels) + + for (i in seq(printlevels)) + writeContours(ret, levels[[i]], + file.path(directories[['output']], + paste.(pasteColon('2d-velocity-contours', + 'zoom', basedir, 'level', + printlevels[[i]]), 'tex'))) + } + h5::h5close(h5file) +} diff --git a/data/tools/3d-performance.R b/data/tools/3d-performance.R new file mode 100644 index 00000000..d795a5ca --- /dev/null +++ b/data/tools/3d-performance.R @@ -0,0 +1,62 @@ +source('tools/support/findQuakes.R') + +finalTime <- 1000 # s +convergenceVelocity <- 5e-5 # m/s + +paste. <- function(...) paste(..., sep='.') +pasteColon<- function(...) paste(..., sep=':') + +directories <- ini::read.ini('config.ini')$directories +dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE) +for (basedir in c("rtol=1e-5_diam=1e-2")) { + dir <- file.path(directories[['simulation']], + '3d-lab', basedir) + h5file <- h5::h5file(file.path(dir, 'output.h5'), 'r') + relativeTime <- h5file['relativeTime'][] + realTime <- finalTime * relativeTime + + velocityProxy<- h5file['/frictionalBoundary/velocity'] + + ## We are interested in an enlarged time range around actual events here, + ## (and no other quantities!) hence we pass a very low velocity here. + quakes <- findQuakes(1e-6 + convergenceVelocity, velocityProxy, + ## Note: We only look at the last 2000 timesteps here because + ## we're only interested in the last few events. This + ## dramatically reduces RAM usage and runtime. + indices = seq(dim(velocityProxy)[1]-2000, + dim(velocityProxy)[1]), c(1,3)) + quakes$beginning <- realTime[quakes$beginningIndex] + quakes$ending <- realTime[quakes$endingIndex] + quakes$duration <- quakes$ending - quakes$beginning + numQuakes <- nrow(quakes) + + relaxedTime <- extendrange(c(quakes[[numQuakes-2,'beginning']], + quakes[[numQuakes, 'ending']]), f=0.02) + threeQuakeTimeMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]]) + plotMask <- threeQuakeTimeMask + plotIndices<- which(plotMask) + plotIndices<- c(plotIndices[1]-1,plotIndices,plotIndices[length(plotIndices)]+1) + + write(relaxedTime[[1]], + file.path(directories[['output']], + paste.(pasteColon('timeframe', 'min', 'threequakes', + basedir), 'tex'))) + write(relaxedTime[[2]], + file.path(directories[['output']], + paste.(pasteColon('timeframe', 'max', 'threequakes', + basedir), 'tex'))) + + timeWindow = realTime[plotIndices] + + relativeTau <- h5file['relativeTimeIncrement'][] + fixedPointIterations <- h5file['/iterations/fixedPoint/final'][] + multiGridIterations <- h5file['/iterations/multiGrid/final'][] + write.csv(data.frame(time = timeWindow, + timeIncrement = finalTime * relativeTau[plotIndices], + fixedPointIterations = fixedPointIterations[plotIndices], + multiGridIterations = multiGridIterations[plotIndices]), + file.path(directories[['output']], + paste.(pasteColon('3d-performance', basedir), 'csv')), + row.names = FALSE, quote = FALSE) + h5::h5close(h5file) +} diff --git a/data/tools/3d-velocity-contours.R b/data/tools/3d-velocity-contours.R new file mode 100644 index 00000000..f50845ea --- /dev/null +++ b/data/tools/3d-velocity-contours.R @@ -0,0 +1,67 @@ +source('tools/support/findQuakes.R') +source('tools/support/writeContours.R') + +finalTime <- 1000 # s +convergenceVelocity <- 5e-5 # m/s +printlevels <- c('1','2','3','5', + '10','20','30','50', + '100','200','300','500', + '1000') +criticalVelocities <- 1e-6*as.numeric(printlevels) + convergenceVelocity + +paste. <- function(...) paste(..., sep='.') +pasteColon<- function(...) paste(..., sep=':') + +directories <- ini::read.ini('config.ini')$directories +dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE) +for (basedir in c("rtol=1e-5_diam=1e-2")) { + dir <- file.path(directories[['simulation']], + '3d-lab', basedir) + h5file <- h5::h5file(file.path(dir, 'output.h5'), 'r') + relativeTime <- h5file['relativeTime'][] + realTime <- finalTime * relativeTime + + velocityProxy<- h5file['/frictionalBoundary/velocity'] + + ## We are interested in an enlarged time range around actual events here, + ## (and no other quantities!) hence we pass a rather low velocity here. + quakes <- findQuakes(200e-6 + convergenceVelocity, velocityProxy, + ## Note: We only look at the last 1000 timesteps here because + ## we're only interested in the last few events. This + ## dramatically reduces RAM usage and runtime. + indices = seq(dim(velocityProxy)[1]-1000, + dim(velocityProxy)[1]), c(1,3)) + quake <- quakes[nrow(quakes)-1,] # Q: why did we not need the -1 in julia? + + weakPatchGridVelocityProxy <- h5file["/weakPatchGrid/velocity"] + + stepSize <- 30 ## note: should/might differ by time/spatial resolution + ts <- seq(quake$beginningIndex, quake$endingIndex, by=stepSize) + dd <- data.frame(timeSteps = ts, + times = realTime[ts], + timeOffsets = realTime[ts] - realTime[quake$beginningIndex]) + + fname = pasteColon('3d-velocity-contours', basedir) + write.csv(dd, row.names = FALSE, quote = FALSE, + file = file.path(directories[['output']], + paste.(pasteColon(fname, 'times'), 'csv'))) + + weakPatchGridXCoordinates <- h5file["/weakPatchGrid/xCoordinates"][] + weakPatchGridZCoordinates <- h5file["/weakPatchGrid/zCoordinates"][] + + for (t in ts) { + m <- weakPatchGridVelocityProxy[t,,,] + s <- sqrt(m[,,,1]^2 + m[,,,3]^2) + ret <- contourLines(weakPatchGridXCoordinates, weakPatchGridZCoordinates, s, + level=criticalVelocities) + + for (i in seq(printlevels)) + writeContours(ret, criticalVelocities[[i]], + file.path(directories[['output']], + paste.(pasteColon(fname, + 'step', t, + 'level', printlevels[[i]]), + 'tex'))) + } + h5::h5close(h5file) +} diff --git a/data/tools/comparison:lab-sim.R b/data/tools/comparison:lab-sim.R new file mode 100644 index 00000000..9c43c050 --- /dev/null +++ b/data/tools/comparison:lab-sim.R @@ -0,0 +1,42 @@ +paste. <- function(...) paste(..., sep='.') +pasteColon<- function(...) paste(..., sep=':') + +basedir <- 'rfpitol=100e-7' + +directories <- ini::read.ini('config.ini')$directories +labdata <- within( + read.table(unz(file.path(directories[['experiment']], + 'B_Scale-model-earthquake-data.zip'), + 'scaleEQs_12-31_catalogue.txt'), + sep='\t', header=FALSE, comment.char='%', + col.names=c('frame', + 'meanSlipNature', 'meanSlipLab', + 'peakSlipNature', 'peakSlipLab', + 'ruptureWidthNature', 'ruptureWidthLab', + 'ignored', 'ignored', 'ignored', 'ignored', 'ignored')), + { + recurrenceLab <- c(NA, diff(frame))/10 # (10Hz camera: 10 frames ~ 1s) + meanSlipLab <- meanSlipLab / 1e6 # micro m -> m + peakSlipLab <- peakSlipLab / 1e6}) # micro m -> m +## NB: We skip the first two quakes here, for compatibility with my old code +## Maybe skipping the first was intentional so that each quake would have +## a recurrence time. But skipping the second was certainly an accident +labdata <- labdata[3:nrow(labdata),] + +simdata <- read.csv(file.path(directories[['output']], + paste.(pasteColon('events', basedir), 'csv'))) + +report <- function(lab, sim, quantity) { + write.table(lab, file.path(directories[['output']], + paste.(pasteColon('boxplot-data', 'lab', + quantity), 'tex')), + row.names=FALSE, col.names=FALSE) + write.table(sim, file.path(directories[['output']], + paste.(pasteColon('boxplot-data', 'simulation', + basedir, quantity), 'tex')), + row.names=FALSE, col.names=FALSE) +} +report(labdata$recurrenceLab, diff(simdata$beginning), 'recurrence') +report(labdata$ruptureWidthLab, simdata$ruptureWidth, 'ruptureWidth') +# meters -> millimeters +report(labdata$peakSlipLab * 1000, simdata$peakSlip*1000, 'peakSlip') diff --git a/data/tools/generate-2d.bash b/data/tools/generate-2d.bash new file mode 100755 index 00000000..320720cf --- /dev/null +++ b/data/tools/generate-2d.bash @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -e + +rr() { + echo "$(date)" Running: Rscript $@ + Rscript --vanilla --default-packages=grDevices,methods,stats,utils tools/$@ +} + +# contours +rr 2d-velocity-contours.R + +# dip +rr 2d-dip-contours.R + +# iterations / adaptivity +rr 2d-performance.R + +# box plot (one half) +rr 2d-event-writer.R + +# fpi data +rr 2d-fpi-tolerance.R + +date diff --git a/data/tools/generate-3d.bash b/data/tools/generate-3d.bash new file mode 100755 index 00000000..f4bed78b --- /dev/null +++ b/data/tools/generate-3d.bash @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -e + +rr() { + echo "$(date)" Running: Rscript $@ + Rscript --vanilla --default-packages=grDevices,methods,stats,utils tools/$@ +} + +# performance +rr 3d-performance.R + +# velocity contours +rr 3d-velocity-contours.R + +date diff --git a/data/tools/generate-others.bash b/data/tools/generate-others.bash new file mode 100755 index 00000000..6bf2e29c --- /dev/null +++ b/data/tools/generate-others.bash @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -e + +rr() { + echo "$(date)" Running: Rscript $@ + Rscript --vanilla --default-packages=grDevices,methods,stats,utils tools/$@ +} + +# box plot (one half) +rr comparison:lab-sim.R + +date diff --git a/data/tools/support/findQuakes.R b/data/tools/support/findQuakes.R new file mode 100644 index 00000000..698b6498 --- /dev/null +++ b/data/tools/support/findQuakes.R @@ -0,0 +1,18 @@ +Rcpp::sourceCpp('tools/support/maxVelocity.cpp') +Rcpp::sourceCpp('tools/support/negativeStarts.cpp') +Rcpp::sourceCpp('tools/support/positiveStarts.cpp') + +findQuakes <- function (criticalVelocity, velocity, indices, dimensions) { + maximumVelocities<- maxVelocity(velocity[indices,,dimensions]) + slippingTimes <- maximumVelocities > criticalVelocity + + ns <- negativeStarts(slippingTimes) + indices[[1]] - 1 + ps <- positiveStarts(slippingTimes) + indices[[1]] - 1 + + ## NOTE: we drop incomplete quakes here + mlen <- min(length(ns), length(ps)) + ns <- ns[1:mlen] + ps <- ps[1:mlen] + + return(data.frame(endingIndex = ns, beginningIndex = ps)) +} diff --git a/data/tools/support/maxVelocity.cpp b/data/tools/support/maxVelocity.cpp new file mode 100644 index 00000000..5294e563 --- /dev/null +++ b/data/tools/support/maxVelocity.cpp @@ -0,0 +1,29 @@ +#include <Rcpp.h> + +// For std::hypot(x,y) +// [[Rcpp::plugins(cpp11)]] + +// Layout of vectors is such that loops over inner indices are traversed first +// [[Rcpp::export]] +Rcpp::NumericVector maxVelocity(Rcpp::NumericVector const &x) { + Rcpp::IntegerVector size = x.attr("dim"); + Rcpp::NumericVector ret(size[0]); + switch (size[2]) { + case 1: + for (size_t ts = 0; ts < size[0]; ++ts) + for (size_t coord = 0; coord < size[1]; ++coord) + ret[ts] = std::max(ret[ts], + std::abs(x[0 * size[1] * size[0] + coord * size[0] + ts])); + break; + case 2: + for (size_t ts = 0; ts < size[0]; ++ts) + for (size_t coord = 0; coord < size[1]; ++coord) + ret[ts] = std::max(ret[ts], + std::hypot(x[0 * size[1] * size[0] + coord * size[0] + ts], + x[1 * size[1] * size[0] + coord * size[0] + ts])); + break; + default: + throw std::range_error("Inadmissible value"); + } + return ret; +} diff --git a/data/tools/support/negativeStarts.cpp b/data/tools/support/negativeStarts.cpp new file mode 100644 index 00000000..940765c2 --- /dev/null +++ b/data/tools/support/negativeStarts.cpp @@ -0,0 +1,13 @@ +#include <Rcpp.h> + +// [[Rcpp::export]] +Rcpp::NumericVector negativeStarts(Rcpp::NumericVector const &x) { + std::vector<size_t> starts(0); + bool prev = false; + for (size_t i = 0; i < x.size(); ++i) { + if (prev && !x[i]) + starts.push_back(i+1); // R indices start at 1 + prev = x[i]; + } + return Rcpp::NumericVector(starts.begin(), starts.end()); +} diff --git a/data/tools/support/positiveStarts.cpp b/data/tools/support/positiveStarts.cpp new file mode 100644 index 00000000..3e9498c0 --- /dev/null +++ b/data/tools/support/positiveStarts.cpp @@ -0,0 +1,14 @@ +#include <Rcpp.h> + +// [[Rcpp::export]] +Rcpp::NumericVector positiveStarts(Rcpp::NumericVector const &x) { + std::vector<size_t> starts(0); + bool prev = false; + for (size_t i = 0; i < x.size(); ++i) { + if (!prev && x[i]) + starts.push_back(i+1); // R indices start at 1 + prev = x[i]; + } + return Rcpp::NumericVector(starts.begin(), starts.end()); +} + diff --git a/data/tools/support/trapezoidal.cpp b/data/tools/support/trapezoidal.cpp new file mode 100644 index 00000000..3b4833d6 --- /dev/null +++ b/data/tools/support/trapezoidal.cpp @@ -0,0 +1,9 @@ +#include <Rcpp.h> + +// [[Rcpp::export]] +double trapezoidal(Rcpp::NumericVector const &x, Rcpp::NumericVector const &y) { + double ret = 0; + for (size_t i = 1; i < x.size(); ++i) + ret += (x[i] - x[i - 1]) * (y[i] + y[i - 1]) / 2; + return ret; +} diff --git a/data/tools/support/writeContours.R b/data/tools/support/writeContours.R new file mode 100644 index 00000000..9394bf5f --- /dev/null +++ b/data/tools/support/writeContours.R @@ -0,0 +1,11 @@ +writeContours <- function (contours, level, file) { + file.create(file) + for (cl in contours[sapply(contours, function(x) x$level) == level]) { + conn <- file(file, 'a') + write.table(cbind(cl$x, cl$y, level), + file = file, row.names = FALSE, col.names = FALSE, + append = TRUE) + writeLines("\n", conn) + close(conn) + } +} diff --git a/debugging.m b/debugging.m new file mode 100644 index 00000000..259ae8db --- /dev/null +++ b/debugging.m @@ -0,0 +1,577 @@ + +A = [... +]; + +f = [... +0; +-4.33681e-19; +0; +1.0842e-19; +-2.66671e-06; +-4.94914e-07; +0; +-2.71051e-20; +-4.19923e-06; +-4.21374e-07; +-3.92235e-06; +-8.64817e-07; +0; +-5.42101e-20; +-4.96301e-06; +-4.13502e-06; +0; +0; +-7.03515e-06; +-5.84881e-06; +-4.93309e-06; +-2.37804e-06; +0; +0; +-2.90755e-06; +-1.23334e-06; +0; +0; +-2.2449e-06; +-8.21563e-07; +0; +0; +0; +0; +0; +0; +-7.24652e-06; +-8.25293e-07; +0; +2.4104e-06; +-8.19294e-06; +-1.18617e-06; +-5.58223e-06; +-1.69348e-06; +0; +1.88001e-06; +-1.03387e-05; +-8.22886e-06; +0; +0; +-1.07258e-05; +-8.62344e-06; +-9.76077e-06; +-4.93954e-06; +-9.10261e-06; +-7.35307e-06; +-4.01973e-06; +-2.38351e-06; +-5.92659e-06; +-4.23858e-07; +-7.9911e-06; +-4.04139e-06; +-3.80594e-06; +-3.06903e-06; +-3.92924e-06; +-2.71681e-06; +-5.12975e-06; +-1.37642e-06; +-4.79892e-06; +-1.14935e-06; +-7.19726e-06; +-3.54967e-06; +-6.62755e-06; +-6.1499e-07; +0; +1.28701e-05; +0; +0; +-1.09944e-05; +-1.92221e-06; +0; +1.17853e-05; +-1.21456e-05; +-2.20784e-06; +-8.3682e-06; +-2.01449e-06; +0; +0; +-1.43122e-05; +-1.00938e-05; +0; +0; +-1.48374e-05; +-1.03947e-05; +-1.3684e-05; +-6.31825e-06; +-1.35318e-05; +-9.3703e-06; +-5.76679e-06; +-1.88878e-06; +-9.18524e-06; +-1.51544e-06; +-1.16296e-05; +-5.64398e-06; +-5.20301e-06; +-2.13559e-06; +-5.55432e-06; +-2.017e-06; +-7.96841e-06; +-1.7895e-06; +-7.95375e-06; +-1.76175e-06; +-1.0596e-05; +-5.24553e-06; +-1.02345e-05; +-1.74422e-06; +-2.16064e-05; +-1.85059e-06; +-2.24752e-05; +-3.34957e-07; +-1.34774e-05; +-2.51353e-06; +-2.18312e-05; +-1.04202e-06; +-1.99898e-05; +-1.463e-06; +-1.94256e-05; +-2.11821e-06; +-5e-05; +5.03269e-07; +-2.00631e-05; +-2.41829e-06; +-2.11637e-05; +-1.12298e-06; +-1.61508e-05; +-1.11752e-05; +-1.7267e-05; +-6.9337e-06; +-1.43931e-05; +-6.46903e-06; +-1.70354e-05; +-2.45177e-06; +-5e-05; +-2.50465e-06; +-5e-05; +-1.21588e-05; +-2.01431e-05; +-1.19797e-05; +]; + +d = 0.00075745; +A2 = [... +]; + +f2 = [... +0; +0; +0; +0; +-3.01994e-06; +-1.76298e-07; +0; +0; +-4.78204e-06; +-2.0995e-07; +-5.01951e-06; +1.22653e-06; +0; +0; +-4.98476e-06; +-3.57931e-06; +0; +0; +-7.06572e-06; +-4.97786e-06; +-5.40025e-06; +-1.91591e-06; +0; +0; +-3.26344e-06; +-9.4196e-07; +0; +0; +-3.47107e-06; +1.69693e-06; +0; +0; +0; +0; +0; +0; +-8.36624e-06; +-3.21786e-07; +0; +0; +-9.19771e-06; +-4.8646e-07; +-9.46319e-06; +2.13218e-06; +0; +0; +-1.03261e-05; +-6.78209e-06; +0; +0; +-1.09634e-05; +-7.09926e-06; +-1.01615e-05; +-3.77678e-06; +-9.09151e-06; +-6.13484e-06; +-9.06507e-06; +4.28268e-06; +-6.83374e-06; +-2.4706e-07; +-8.51881e-06; +-3.22169e-06; +-7.83369e-06; +3.49294e-06; +-8.45665e-06; +3.90404e-06; +-7.913e-06; +1.91502e-06; +-7.13457e-06; +1.77604e-06; +-7.71821e-06; +-2.87949e-06; +-7.58455e-06; +-3.19117e-07; +0; +0; +0; +0; +-1.17905e-05; +-6.57623e-07; +0; +0; +-1.26738e-05; +-7.75536e-07; +-1.28663e-05; +2.59111e-06; +0; +0; +-1.33726e-05; +-8.23012e-06; +0; +0; +-1.40382e-05; +-8.4827e-06; +-1.3445e-05; +-4.60248e-06; +-1.21277e-05; +-7.7075e-06; +-1.20933e-05; +5.59837e-06; +-1.00511e-05; +-5.83173e-07; +-1.16989e-05; +-4.19969e-06; +-1.07938e-05; +5.03904e-06; +-1.14551e-05; +5.33497e-06; +-1.1057e-05; +2.39173e-06; +-1.01977e-05; +2.22842e-06; +-1.08385e-05; +-3.93909e-06; +-1.09119e-05; +-6.59537e-07; +-1.51572e-05; +6.80143e-06; +-1.97651e-05; +7.92292e-06; +-1.3582e-05; +-8.81729e-07; +-1.73372e-05; +7.52177e-06; +-1.63794e-05; +2.79237e-06; +-1.33659e-05; +2.38778e-06; +-5e-05; +7.93536e-06; +-1.92072e-05; +-9.96979e-07; +-1.93357e-05; +3.15138e-06; +-1.54595e-05; +-9.11795e-06; +-1.68142e-05; +-5.1397e-06; +-1.4113e-05; +-4.66534e-06; +-1.63265e-05; +-9.49749e-07; +-5e-05; +-1.0631e-06; +-5e-05; +-1.02021e-05; +-1.98778e-05; +-9.99727e-06; +]; + +d2 = 0; + +sum(sum(abs(f-f2)>1e-14)) + + +sum(sum(abs(A-A2)>1e-14)) + + +alpha0 = 100; +V = 1e-5; %1e-20; +V0 = 5e-5; +L = 2.25e-5; + +alpha = @(t) log(exp(alpha0 - V.*t./L ) - V0 * (exp(-t./L.*V)-1)./V); + +x = [0:0.001:0.1]; +alpha(x) +plot(x, alpha(x)); + +%abs(d-d2) + +% x = [... +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% -1.2337e-10; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% -1.2337e-10; +% 0; +% -1.2337e-10; +% 0; +% 0; +% 0; +% ]; +% +% ignore = [... +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 1; +% 1; +% 0; +% 0; +% 1; +% 1; +% 0; +% 0; +% 1; +% 1; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 1; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 0; +% 1; +% 0; +% 1; +% 0; +% 0; +% 0; +% ]; +% +% newA = A; +% newf = f; +% for i=1:length(ignore) +% if (ignore(i)==1) +% for j=1:length(ignore) +% newA(i,j) = (i==j); +% end +% newf(i) = x(i); +% end +% end +% newA +% newf + +% ignore = zeros(1, length(f)); +% for i=1:length(ignore) +% if (A(i,i)==0) +% ignore(1, i) = 1; +% end +% end +% +% indices = []; +% for i=1:length(ignore) +% if (ignore(i)==0) +% indices = [indices i]; +% end +% end +% +% len = length(indices); +% newA = zeros(len, len); +% newf = zeros(1, len); +% for i=1:len +% newf(i) = f(indices(i)); +% +% for j=1:len +% newA(i,j) = A(indices(i), indices(j)); +% end +% end +% newf; +% newA + +%inv(A); + +% sol = newA\newf +% +% tnnmgSol = [... +% -1.03349; +% -0.0502635; +% 0.0161336; +% -0.00852914; +% -0.0130659; +% 0.00660115; +% -0.434915; +% -0.0128241; +% -0.00893317; +% 0.00884256; +% -0.0110232; +% -0.10936; +% 1.14978; +% 0.0581132; +% 0.019598; +% 0.190758; +% 0.478393; +% -0.00433049; +% 0.0513446; +% 0.353218; +% -0.00482644; +% 0.11758; +% 0; +% 0; +% -0.013677; +% 0.0512563; +% 0; +% 0; +% -0.00514197; +% -0.117664; +% 0; +% 0; +% 0.130034; +% 0.574041; +% 0.0136965; +% 0.214953; +% 0.0335986; +% -0.00703477; +% 0.0438202; +% 0.346506; +% -0.000896805; +% 0.127837; +% 0.041946; +% 0.217409; +% -1.2337e-10; +% 0.112528; +% -0.00828618; +% 0.00453345; +% -0.00898709; +% 0.0781683; +% 0.092355; +% -0.556143; +% -0.00443686; +% -0.140953; +% 0.0424371; +% -0.250082; +% -0.00336878; +% 0.00105471; +% -1.2337e-10; +% 0.0188452; +% -1.2337e-10; +% -0.14111; +% 0.00298499; +% -0.190904; +% ]; +% +% sol-tnnmgSol \ No newline at end of file diff --git a/dune/tectonic/CMakeLists.txt b/dune/tectonic/CMakeLists.txt index 52c9f309..de041acc 100644 --- a/dune/tectonic/CMakeLists.txt +++ b/dune/tectonic/CMakeLists.txt @@ -1,16 +1,24 @@ +add_subdirectory("data-structures") +add_subdirectory("factories") +add_subdirectory("io") +add_subdirectory("problem-data") +add_subdirectory("spatial-solving") +add_subdirectory("tests") +add_subdirectory("time-stepping") +add_subdirectory("utils") + +add_custom_target(tectonic_dune SOURCES + assemblers.hh + assemblers.cc + explicitgrid.hh + explicitvectors.hh + gridselector.hh +) + +#install headers install(FILES - bodydata.hh - frictiondata.hh - frictionpotential.hh - globalfrictiondata.hh - globalfriction.hh - globalratestatefriction.hh - gravity.hh - localfriction.hh - minimisation.hh - myblockproblem.hh - mydirectionalconvexfunction.hh - quadraticenergy.hh - tectonic.hh - transformedglobalratestatefriction.hh - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) + assemblers.hh + explicitgrid.hh + explicitvectors.hh + gridselector.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/assemblers.cc b/dune/tectonic/assemblers.cc similarity index 98% rename from src/assemblers.cc rename to dune/tectonic/assemblers.cc index 1160fd59..609436ca 100644 --- a/src/assemblers.cc +++ b/dune/tectonic/assemblers.cc @@ -17,8 +17,8 @@ #include <dune/fufem/functiontools/p0p1interpolation.hh> #include <dune/fufem/quadraturerules/quadraturerulecache.hh> -#include <dune/tectonic/frictionpotential.hh> -#include <dune/tectonic/globalratestatefriction.hh> +#include "data-structures/friction/frictionpotential.hh" +#include "data-structures/friction/globalratestatefriction.hh" #include "assemblers.hh" diff --git a/src/assemblers.hh b/dune/tectonic/assemblers.hh similarity index 97% rename from src/assemblers.hh rename to dune/tectonic/assemblers.hh index 695a94af..df0b3cd6 100644 --- a/src/assemblers.hh +++ b/dune/tectonic/assemblers.hh @@ -14,8 +14,8 @@ #include <dune/fufem/functionspacebases/p1nodalbasis.hh> #include <dune/fufem/boundarypatch.hh> -#include <dune/tectonic/globalfriction.hh> -#include <dune/tectonic/globalfrictiondata.hh> +#include "data-structures/friction/globalfriction.hh" +#include "data-structures/friction/globalfrictiondata.hh" #include "data-structures/enums.hh" diff --git a/src/assemblers_tmpl.cc b/dune/tectonic/assemblers_tmpl.cc similarity index 100% rename from src/assemblers_tmpl.cc rename to dune/tectonic/assemblers_tmpl.cc diff --git a/src/data-structures/.cc b/dune/tectonic/data-structures/.cc similarity index 100% rename from src/data-structures/.cc rename to dune/tectonic/data-structures/.cc diff --git a/dune/tectonic/data-structures/CMakeLists.txt b/dune/tectonic/data-structures/CMakeLists.txt new file mode 100644 index 00000000..2a5db4e9 --- /dev/null +++ b/dune/tectonic/data-structures/CMakeLists.txt @@ -0,0 +1,19 @@ +add_subdirectory("body") +add_subdirectory("friction") +add_subdirectory("network") + +add_custom_target(tectonic_dune_data-structures SOURCES + enumparser.hh + enumparser.cc + enums.hh + matrices.hh + program_state.hh +) + +#install headers +install(FILES + enumparser.hh + enums.hh + matrices.hh + program_state.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/dune/tectonic/data-structures/body/CMakeLists.txt b/dune/tectonic/data-structures/body/CMakeLists.txt new file mode 100644 index 00000000..699e013f --- /dev/null +++ b/dune/tectonic/data-structures/body/CMakeLists.txt @@ -0,0 +1,13 @@ +add_custom_target(tectonic_dune_data-structures_body SOURCES + body.hh + body.cc + bodydata.hh + boundarycondition.hh +) + +#install headers +install(FILES + body.hh + bodydata.hh + boundarycondition.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/data-structures/body.cc b/dune/tectonic/data-structures/body/body.cc similarity index 100% rename from src/data-structures/body.cc rename to dune/tectonic/data-structures/body/body.cc diff --git a/src/data-structures/body.hh b/dune/tectonic/data-structures/body/body.hh similarity index 97% rename from src/data-structures/body.hh rename to dune/tectonic/data-structures/body/body.hh index 6b5463cd..74809e50 100644 --- a/src/data-structures/body.hh +++ b/dune/tectonic/data-structures/body/body.hh @@ -24,12 +24,12 @@ #include <dune/solvers/norms/energynorm.hh> -#include <dune/tectonic/bodydata.hh> +#include "../../assemblers.hh" +#include "../enums.hh" +#include "../matrices.hh" -#include "../assemblers.hh" -#include "../boundarycondition.hh" -#include "enums.hh" -#include "matrices.hh" +#include "boundarycondition.hh" +#include "bodydata.hh" template <class HostGridType, class VectorType> class LeafBody { diff --git a/src/data-structures/body_tmpl.cc b/dune/tectonic/data-structures/body/body_tmpl.cc similarity index 70% rename from src/data-structures/body_tmpl.cc rename to dune/tectonic/data-structures/body/body_tmpl.cc index d2a5dab1..26ebfd64 100644 --- a/src/data-structures/body_tmpl.cc +++ b/dune/tectonic/data-structures/body/body_tmpl.cc @@ -2,8 +2,8 @@ #error MY_DIM unset #endif -#include "../explicitgrid.hh" -#include "../explicitvectors.hh" +#include "../../explicitgrid.hh" +#include "../../explicitvectors.hh" template class LeafBody<Grid, Vector>; diff --git a/dune/tectonic/bodydata.hh b/dune/tectonic/data-structures/body/bodydata.hh similarity index 100% rename from dune/tectonic/bodydata.hh rename to dune/tectonic/data-structures/body/bodydata.hh diff --git a/src/boundarycondition.hh b/dune/tectonic/data-structures/body/boundarycondition.hh similarity index 100% rename from src/boundarycondition.hh rename to dune/tectonic/data-structures/body/boundarycondition.hh diff --git a/src/data-structures/enumparser.cc b/dune/tectonic/data-structures/enumparser.cc similarity index 100% rename from src/data-structures/enumparser.cc rename to dune/tectonic/data-structures/enumparser.cc diff --git a/src/data-structures/enumparser.hh b/dune/tectonic/data-structures/enumparser.hh similarity index 100% rename from src/data-structures/enumparser.hh rename to dune/tectonic/data-structures/enumparser.hh diff --git a/src/data-structures/enums.hh b/dune/tectonic/data-structures/enums.hh similarity index 100% rename from src/data-structures/enums.hh rename to dune/tectonic/data-structures/enums.hh diff --git a/dune/tectonic/data-structures/friction/CMakeLists.txt b/dune/tectonic/data-structures/friction/CMakeLists.txt new file mode 100644 index 00000000..a9f8efd5 --- /dev/null +++ b/dune/tectonic/data-structures/friction/CMakeLists.txt @@ -0,0 +1,20 @@ +add_custom_target(tectonic_dune_data-structures_friction SOURCES + frictioncouplingpair.hh + frictiondata.hh + frictionpotential.hh + globalfriction.hh + globalfrictiondata.hh + globalratestatefriction.hh + localfriction.hh +) + +#install headers +install(FILES + frictioncouplingpair.hh + frictiondata.hh + frictionpotential.hh + globalfriction.hh + globalfrictiondata.hh + globalratestatefriction.hh + localfriction.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/frictioncouplingpair.hh b/dune/tectonic/data-structures/friction/frictioncouplingpair.hh similarity index 95% rename from src/frictioncouplingpair.hh rename to dune/tectonic/data-structures/friction/frictioncouplingpair.hh index 7eb36871..a4102b8e 100644 --- a/src/frictioncouplingpair.hh +++ b/dune/tectonic/data-structures/friction/frictioncouplingpair.hh @@ -3,7 +3,8 @@ #include <dune/fufem/geometry/convexpolyhedron.hh> #include <dune/contact/common/couplingpair.hh> -#include <dune/tectonic/globalfrictiondata.hh> + +#include "globalfrictiondata.hh" template <class GridType, class LocalVectorType, class field_type = double> class FrictionCouplingPair : public Dune::Contact::CouplingPair<GridType, GridType, field_type>{ diff --git a/dune/tectonic/frictiondata.hh b/dune/tectonic/data-structures/friction/frictiondata.hh similarity index 100% rename from dune/tectonic/frictiondata.hh rename to dune/tectonic/data-structures/friction/frictiondata.hh diff --git a/dune/tectonic/frictionpotential.hh b/dune/tectonic/data-structures/friction/frictionpotential.hh similarity index 99% rename from dune/tectonic/frictionpotential.hh rename to dune/tectonic/data-structures/friction/frictionpotential.hh index 2ed879b3..8b98b22b 100644 --- a/dune/tectonic/frictionpotential.hh +++ b/dune/tectonic/data-structures/friction/frictionpotential.hh @@ -9,7 +9,7 @@ #include <dune/common/exceptions.hh> #include <dune/common/function.hh> -#include <dune/tectonic/frictiondata.hh> +#include "frictiondata.hh" class FrictionPotential { public: diff --git a/dune/tectonic/globalfriction.hh b/dune/tectonic/data-structures/friction/globalfriction.hh similarity index 93% rename from dune/tectonic/globalfriction.hh rename to dune/tectonic/data-structures/friction/globalfriction.hh index 83395851..f3dbabc7 100644 --- a/dune/tectonic/globalfriction.hh +++ b/dune/tectonic/data-structures/friction/globalfriction.hh @@ -9,12 +9,10 @@ #include <dune/solvers/common/interval.hh> -#include <dune/tnnmg/functionals/nonsmoothconvexfunctional.hh> - -#include <dune/tectonic/localfriction.hh> +#include "localfriction.hh" template <class Matrix, class Vector> -class GlobalFriction { //: public Dune::TNNMG::NonsmoothConvexFunctional<> { +class GlobalFriction { protected: using ScalarVector = Dune::BlockVector<Dune::FieldVector<double, 1>>; diff --git a/dune/tectonic/globalfrictiondata.hh b/dune/tectonic/data-structures/friction/globalfrictiondata.hh similarity index 96% rename from dune/tectonic/globalfrictiondata.hh rename to dune/tectonic/data-structures/friction/globalfrictiondata.hh index 0fffac2c..7646bfcf 100644 --- a/dune/tectonic/globalfrictiondata.hh +++ b/dune/tectonic/data-structures/friction/globalfrictiondata.hh @@ -4,7 +4,7 @@ #include <dune/common/function.hh> #include <dune/common/fvector.hh> -#include <dune/tectonic/frictiondata.hh> +#include "frictiondata.hh" template <class DomainType> double evaluateScalarFunction( diff --git a/dune/tectonic/globalratestatefriction.hh b/dune/tectonic/data-structures/friction/globalratestatefriction.hh similarity index 91% rename from dune/tectonic/globalratestatefriction.hh rename to dune/tectonic/data-structures/friction/globalratestatefriction.hh index 078bd85d..0d007d8e 100644 --- a/dune/tectonic/globalratestatefriction.hh +++ b/dune/tectonic/data-structures/friction/globalratestatefriction.hh @@ -12,12 +12,12 @@ #include <dune/contact/assemblers/dualmortarcoupling.hh> -#include <dune/tectonic/geocoordinate.hh> -#include <dune/tectonic/globalfrictiondata.hh> -#include <dune/tectonic/globalfriction.hh> -#include <dune/tectonic/index-in-sorted-range.hh> +#include "globalfrictiondata.hh" +#include "globalfriction.hh" +#include "frictioncouplingpair.hh" -#include "../../src/frictioncouplingpair.hh" +#include "../../utils/geocoordinate.hh" +#include "../../utils/index-in-sorted-range.hh" template <class Matrix, class Vector, class ScalarFriction, class GridType> class GlobalRateStateFriction : public GlobalFriction<Matrix, Vector> { @@ -32,7 +32,7 @@ class GlobalRateStateFriction : public GlobalFriction<Matrix, Vector> { using typename Base::ScalarVector; using typename Base::LocalVectorType; - using FrictionCouplingPair = FrictionCouplingPair<GridType, LocalVectorType, field_type>; + using FrictionCoupling = FrictionCouplingPair<GridType, LocalVectorType, field_type>; using ContactCoupling = Dune::Contact::DualMortarCoupling<field_type, GridType>; size_t bodyIndex(const size_t globalIdx) { @@ -47,7 +47,7 @@ class GlobalRateStateFriction : public GlobalFriction<Matrix, Vector> { public: GlobalRateStateFriction(const std::vector<std::shared_ptr<ContactCoupling>>& contactCouplings, // contains nonmortarBoundary - const std::vector<std::shared_ptr<FrictionCouplingPair>>& couplings, // contains frictionInfo + const std::vector<std::shared_ptr<FrictionCoupling>>& couplings, // contains frictionInfo const std::vector<ScalarVector>& weights, const std::vector<ScalarVector>& weightedNormalStress) : restrictions_(), localToGlobal_(), zeroFriction_() { diff --git a/dune/tectonic/localfriction.hh b/dune/tectonic/data-structures/friction/localfriction.hh similarity index 99% rename from dune/tectonic/localfriction.hh rename to dune/tectonic/data-structures/friction/localfriction.hh index f2fb36ee..67b7f282 100644 --- a/dune/tectonic/localfriction.hh +++ b/dune/tectonic/data-structures/friction/localfriction.hh @@ -10,7 +10,7 @@ #include <dune/fufem/arithmetic.hh> #include <dune/solvers/common/interval.hh> -#include <dune/tectonic/frictionpotential.hh> +#include "frictionpotential.hh" template <size_t dimension> class LocalFriction { public: diff --git a/src/data-structures/globalfrictioncontainer.cc b/dune/tectonic/data-structures/globalfrictioncontainer.cc similarity index 100% rename from src/data-structures/globalfrictioncontainer.cc rename to dune/tectonic/data-structures/globalfrictioncontainer.cc diff --git a/src/data-structures/globalfrictioncontainer.hh b/dune/tectonic/data-structures/globalfrictioncontainer.hh similarity index 100% rename from src/data-structures/globalfrictioncontainer.hh rename to dune/tectonic/data-structures/globalfrictioncontainer.hh diff --git a/src/data-structures/matrices.hh b/dune/tectonic/data-structures/matrices.hh similarity index 100% rename from src/data-structures/matrices.hh rename to dune/tectonic/data-structures/matrices.hh diff --git a/dune/tectonic/data-structures/network/CMakeLists.txt b/dune/tectonic/data-structures/network/CMakeLists.txt new file mode 100644 index 00000000..1cfc9596 --- /dev/null +++ b/dune/tectonic/data-structures/network/CMakeLists.txt @@ -0,0 +1,12 @@ +add_custom_target(tectonic_dune_data-structures_network SOURCES + contactnetwork.hh + contactnetwork.cc + levelcontactnetwork.hh + levelcontactnetwork.cc +) + +#install headers +install(FILES + contactnetwork.hh + levelcontactnetwork.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/data-structures/contactnetwork.cc b/dune/tectonic/data-structures/network/contactnetwork.cc similarity index 98% rename from src/data-structures/contactnetwork.cc rename to dune/tectonic/data-structures/network/contactnetwork.cc index 84517f20..e369614c 100644 --- a/src/data-structures/contactnetwork.cc +++ b/dune/tectonic/data-structures/network/contactnetwork.cc @@ -7,13 +7,13 @@ #include <dune/fufem/assemblers/localassemblers/neumannboundaryassembler.hh> #include <dune/fufem/functions/constantfunction.hh> -#include <dune/tectonic/globalratestatefriction.hh> -#include <dune/tectonic/frictionpotential.hh> +#include "../friction/globalratestatefriction.hh" +#include "../friction/frictionpotential.hh" #include "contactnetwork.hh" -#include "../assemblers.hh" -#include "../utils/tobool.hh" +#include "../../assemblers.hh" +#include "../../utils/tobool.hh" template <class HostGridType, class VectorType> diff --git a/src/data-structures/contactnetwork.hh b/dune/tectonic/data-structures/network/contactnetwork.hh similarity index 95% rename from src/data-structures/contactnetwork.hh rename to dune/tectonic/data-structures/network/contactnetwork.hh index 6fb2e48b..fc9f554c 100644 --- a/src/data-structures/contactnetwork.hh +++ b/dune/tectonic/data-structures/network/contactnetwork.hh @@ -7,15 +7,16 @@ #include <dune/contact/assemblers/nbodyassembler.hh> -#include <dune/tectonic/bodydata.hh> -#include <dune/tectonic/globalfriction.hh> -#include <dune/tectonic/globalfrictiondata.hh> - -#include "../assemblers.hh" -#include "../frictioncouplingpair.hh" -#include "body.hh" -#include "enums.hh" -#include "matrices.hh" +#include "../../assemblers.hh" +#include "../enums.hh" +#include "../matrices.hh" + +#include "../body/body.hh" +#include "../body/bodydata.hh" +#include "../friction/frictioncouplingpair.hh" +#include "../friction/globalfriction.hh" +#include "../friction/globalfrictiondata.hh" + #include "levelcontactnetwork.hh" template <class HostGridType, class VectorType> diff --git a/dune/tectonic/data-structures/network/contactnetwork_tmpl.cc b/dune/tectonic/data-structures/network/contactnetwork_tmpl.cc new file mode 100644 index 00000000..9979e7c1 --- /dev/null +++ b/dune/tectonic/data-structures/network/contactnetwork_tmpl.cc @@ -0,0 +1,10 @@ +#ifndef MY_DIM +#error MY_DIM unset +#endif + +#include "../../explicitgrid.hh" +#include "../../explicitvectors.hh" + +#include "contactnetwork.hh" + +template class ContactNetwork<Grid, Vector>; diff --git a/src/data-structures/levelcontactnetwork.cc b/dune/tectonic/data-structures/network/levelcontactnetwork.cc similarity index 97% rename from src/data-structures/levelcontactnetwork.cc rename to dune/tectonic/data-structures/network/levelcontactnetwork.cc index f7a34d4a..f0c81bdd 100644 --- a/src/data-structures/levelcontactnetwork.cc +++ b/dune/tectonic/data-structures/network/levelcontactnetwork.cc @@ -8,14 +8,14 @@ #include <dune/fufem/functions/constantfunction.hh> #include <dune/fufem/facehierarchy.hh> -#include <dune/tectonic/globalratestatefriction.hh> -#include <dune/tectonic/frictionpotential.hh> +#include "../../assemblers.hh" +#include "../../utils/tobool.hh" +#include "../../utils/debugutils.hh" -#include "levelcontactnetwork.hh" +#include "../friction/globalratestatefriction.hh" +#include "../friction/frictionpotential.hh" -#include "../assemblers.hh" -#include "../utils/tobool.hh" -#include "../utils/debugutils.hh" +#include "levelcontactnetwork.hh" template <class GridType, class FrictionCouplingPair, class field_type> LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::LevelContactNetwork( diff --git a/src/data-structures/levelcontactnetwork.hh b/dune/tectonic/data-structures/network/levelcontactnetwork.hh similarity index 91% rename from src/data-structures/levelcontactnetwork.hh rename to dune/tectonic/data-structures/network/levelcontactnetwork.hh index c4976718..dc0b4de3 100644 --- a/src/data-structures/levelcontactnetwork.hh +++ b/dune/tectonic/data-structures/network/levelcontactnetwork.hh @@ -18,16 +18,15 @@ #include <dune/fufem/boundarypatch.hh> -#include <dune/tectonic/bodydata.hh> -#include <dune/tectonic/globalfriction.hh> -#include <dune/tectonic/globalfrictiondata.hh> - -#include "../assemblers.hh" -#include "../frictioncouplingpair.hh" -#include "body.hh" -#include "enums.hh" -#include "matrices.hh" -//#include "multi-body-problem-data/myglobalfrictiondata.hh" +#include "../../assemblers.hh" +#include "../enums.hh" +#include "../matrices.hh" + +#include "../body/body.hh" +#include "../body/bodydata.hh" +#include "../friction/frictioncouplingpair.hh" +#include "../friction/globalfriction.hh" +#include "../friction/globalfrictiondata.hh" template <class GridTypeTEMPLATE, class FrictionCouplingPair, class field_type> class LevelContactNetwork { diff --git a/src/data-structures/levelcontactnetwork_tmpl.cc b/dune/tectonic/data-structures/network/levelcontactnetwork_tmpl.cc similarity index 54% rename from src/data-structures/levelcontactnetwork_tmpl.cc rename to dune/tectonic/data-structures/network/levelcontactnetwork_tmpl.cc index da253a7f..3445a319 100644 --- a/src/data-structures/levelcontactnetwork_tmpl.cc +++ b/dune/tectonic/data-structures/network/levelcontactnetwork_tmpl.cc @@ -2,11 +2,13 @@ #error MY_DIM unset #endif -#include "../explicitgrid.hh" -#include "../explicitvectors.hh" +#include "../../explicitgrid.hh" +#include "../../explicitvectors.hh" -#include "../frictioncouplingpair.hh" -#include "contactnetwork_tmpl.cc" +#include "../friction/frictioncouplingpair.hh" +#include "contactnetwork.hh" #include "levelcontactnetwork.hh" +using MyContactNetwork = ContactNetwork<Grid, Vector>; + template class LevelContactNetwork<typename MyContactNetwork::GridType, typename MyContactNetwork::FrictionCouplingPair, typename MyContactNetwork::field_type>; diff --git a/src/data-structures/program_state.hh b/dune/tectonic/data-structures/program_state.hh similarity index 82% rename from src/data-structures/program_state.hh rename to dune/tectonic/data-structures/program_state.hh index ad0e796e..05198b41 100644 --- a/src/data-structures/program_state.hh +++ b/dune/tectonic/data-structures/program_state.hh @@ -6,7 +6,6 @@ #include <dune/matrix-vector/axpy.hh> #include <dune/fufem/boundarypatch.hh> -#include <dune/tnnmg/problem-classes/blocknonlineartnnmgproblem.hh> #include <dune/contact/assemblers/nbodyassembler.hh> @@ -14,13 +13,14 @@ #include <dune/solvers/solvers/loopsolver.hh> #include <dune/solvers/iterationsteps/cgstep.hh> -#include <dune/tectonic/bodydata.hh> +#include "body/bodydata.hh" #include "../assemblers.hh" -#include "contactnetwork.hh" +#include "network/contactnetwork.hh" #include "matrices.hh" #include "../spatial-solving/preconditioners/multilevelpatchpreconditioner.hh" #include "../spatial-solving/solverfactory.hh" +#include "../spatial-solving/solverfactory.cc" #include "../spatial-solving/tnnmg/functional.hh" #include "../spatial-solving/tnnmg/zerononlinearity.hh" #include "../utils/debugutils.hh" @@ -102,32 +102,36 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState { using Matrix = typename ContactNetwork::Matrix; const auto& nBodyAssembler = contactNetwork.nBodyAssembler(); - const auto& preconditionerParset = parset.sub("solver.tnnmg.linear.preconditioner"); - std::cout << "-- setupInitialConditions --" << std::endl; std::cout << "----------------------------" << std::endl; - /* - std::cout << "Building preconditioner..." << std::endl; + // make linear solver for linear correction in TNNMGStep + using Norm = EnergyNorm<Matrix, Vector>; using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, Matrix, Vector>; + using LinearSolver = typename Dune::Solvers::LoopSolver<Vector>; + + /* const auto& preconditionerParset = parset.sub("solver.tnnmg.preconditioner"); + Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), true); - /*Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), false); - activeLevels.back() = true; - activeLevels[activeLevels.size()-2] = true;*/ - /*print(activeLevels, "activeLevels:"); Preconditioner preconditioner(preconditionerParset, contactNetwork, activeLevels); + preconditioner.setPatchDepth(preconditionerParset.template get<size_t>("patchDepth")); + + std::cout << "Building preconditioner..." << std::endl; preconditioner.build(); - using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>; - using LinearSolverStep = typename Dune::Solvers::CGStep<Matrix, Vector, BitVector>; + auto cgStep = std::make_shared<Dune::Solvers::CGStep<Matrix, Vector>>(); + cgStep->setPreconditioner(preconditioner); + + Norm norm(*cgStep); + + auto linearSolver = std::make_shared<LinearSolver>(cgStep, parset.get<int>("solver.tnnmg.main.multi"), + parset.get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), + norm, Solver::QUIET); - LinearSolverStep linearSolverStep; - linearSolverStep.setPreconditioner(preconditioner); +*/ + // set multigrid solver + auto smoother = TruncatedBlockGSStep<Matrix, Vector>(); - EnergyNorm<Matrix, Vector> energyNorm(linearSolverStep); - LinearSolver linearSolver(linearSolverStep, parset.get<size_t>("solver.tnnmg.linear.maximumIterations"), parset.get<double>("solver.tnnmg.linear.tolerance"), energyNorm, Solver::FULL); - */ - using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>; using TransferOperator = NBodyContactTransfer<ContactNetwork, Vector>; using TransferOperators = std::vector<std::shared_ptr<TransferOperator>>; @@ -141,15 +145,14 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState { for (size_t i=0; i<transfer.size(); i++) std::dynamic_pointer_cast<TruncatedMGTransfer<Vector> >(transfer[i])->setRecomputeBitField(nullptr); - auto smoother = TruncatedBlockGSStep<Matrix, Vector>{}; auto linearMultigridStep = std::make_shared<Dune::Solvers::MultigridStep<Matrix, Vector> >(); linearMultigridStep->setMGType(1, 3, 3); - linearMultigridStep->setSmoother(&smoother); + linearMultigridStep->setSmoother(smoother); linearMultigridStep->setTransferOperators(transfer); - EnergyNorm<Matrix, Vector> mgNorm(*linearMultigridStep); - LinearSolver mgSolver(linearMultigridStep, parset.get<size_t>("solver.tnnmg.linear.maximumIterations"), parset.get<double>("solver.tnnmg.linear.tolerance"), mgNorm, Solver::FULL); + Norm norm(*linearMultigridStep); + auto linearSolver = std::make_shared<LinearSolver>(linearMultigridStep, parset.get<int>("solver.tnnmg.main.multi"), parset.get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), norm, Solver::QUIET); // Solving a linear problem with a multigrid solver auto const solveLinearProblem = [&]( @@ -215,9 +218,10 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState { Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), lower, upper); //TODO // set up TNMMG solver - using Factory = SolverFactory<Functional, BitVector, ContactNetwork>; + using Factory = SolverFactory<Functional, BitVector>; //Factory factory(parset.sub("solver.tnnmg"), J, linearSolver, _dirichletNodes); - Factory factory(parset.sub("solver.tnnmg"), J, mgSolver, _dirichletNodes, contactNetwork); + Factory factory(parset.sub("solver.tnnmg"), J, _dirichletNodes); + factory.build(linearSolver); /* std::vector<BitVector> bodyDirichletNodes; nBodyAssembler.postprocess(_dirichletNodes, bodyDirichletNodes); @@ -235,10 +239,9 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState { const EnergyNorm<Matrix, Vector> norm(bilinearForm); LoopSolver<Vector> solver( - tnnmgStep.get(), _localParset.get<size_t>("maximumIterations"), - _localParset.get<double>("tolerance"), &norm, - _localParset.get<Solver::VerbosityMode>("verbosity"), - false); // absolute error + *tnnmgStep.get(), _localParset.get<size_t>("maximumIterations"), + _localParset.get<double>("tolerance"), norm, + _localParset.get<Solver::VerbosityMode>("verbosity")); // absolute error solver.preprocess(); solver.solve(); @@ -317,7 +320,7 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState { solveLinearProblem(dirichletNodes, contactNetwork.matrices().elasticity, ell0, u, parset.sub("u0.solver")); - print(u, "initial u:"); + //print(u, "initial u:"); // Initial acceleration: Computed in agreement with Ma = ell0 - Au // (without Dirichlet constraints), again assuming dPhi(v = 0) = 0 @@ -329,7 +332,7 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState { // Initial normal stress const auto& body = contactNetwork.body(i); - std::vector<std::shared_ptr<typename ContactNetwork::LeafBody::BoundaryCondition>> frictionBoundaryConditions; + /*std::vector<std::shared_ptr<typename ContactNetwork::LeafBody::BoundaryCondition>> frictionBoundaryConditions; body->boundaryConditions("friction", frictionBoundaryConditions); for (size_t j=0; j<frictionBoundaryConditions.size(); j++) { ScalarVector frictionBoundaryStress(weightedNormalStress[i].size()); @@ -339,18 +342,34 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState { body->data()->getPoissonRatio(), u[i]); weightedNormalStress[i] += frictionBoundaryStress; - } + }*/ Dune::MatrixVector::subtractProduct(accelerationRHS[i], *body->matrices().elasticity, u[i]); } + for (size_t i=0; i<contactNetwork.nCouplings(); i++) { + const auto& coupling = contactNetwork.coupling(i); + const auto& contactCoupling = contactNetwork.nBodyAssembler().getContactCouplings()[i]; + + const auto nonmortarIdx = coupling->gridIdx_[0]; + const auto& body = contactNetwork.body(nonmortarIdx); + + ScalarVector frictionBoundaryStress(weightedNormalStress[nonmortarIdx].size()); + + body->assembler()->assembleWeightedNormalStress( + contactCoupling->nonmortarBoundary(), frictionBoundaryStress, body->data()->getYoungModulus(), + body->data()->getPoissonRatio(), u[nonmortarIdx]); + + weightedNormalStress[nonmortarIdx] += frictionBoundaryStress; + } + std::cout << "solving linear problem for a..." << std::endl; BitVector noNodes(dirichletNodes.size(), false); solveLinearProblem(noNodes, contactNetwork.matrices().mass, accelerationRHS, a, parset.sub("a0.solver")); - print(a, "initial a:"); + //print(a, "initial a:"); } private: diff --git a/src/explicitgrid.hh b/dune/tectonic/explicitgrid.hh similarity index 100% rename from src/explicitgrid.hh rename to dune/tectonic/explicitgrid.hh diff --git a/src/explicitvectors.hh b/dune/tectonic/explicitvectors.hh similarity index 100% rename from src/explicitvectors.hh rename to dune/tectonic/explicitvectors.hh diff --git a/dune/tectonic/factories/CMakeLists.txt b/dune/tectonic/factories/CMakeLists.txt new file mode 100644 index 00000000..b069d44e --- /dev/null +++ b/dune/tectonic/factories/CMakeLists.txt @@ -0,0 +1,22 @@ +add_custom_target(tectonic_dune_factories SOURCES + cantorfactory.hh + cantorfactory.cc + contactnetworkfactory.hh + levelcontactnetworkfactory.hh + stackedblocksfactory.hh + stackedblocksfactory.cc + threeblocksfactory.hh + threeblocksfactory.cc + twoblocksfactory.hh + twoblocksfactory.cc +) + +#install headers +install(FILES + cantorfactory.hh + contactnetworkfactory.hh + levelcontactnetworkfactory.hh + stackedblocksfactory.hh + threeblocksfactory.hh + twoblocksfactory.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/factories/cantorfactory.cc b/dune/tectonic/factories/cantorfactory.cc similarity index 100% rename from src/factories/cantorfactory.cc rename to dune/tectonic/factories/cantorfactory.cc diff --git a/src/factories/cantorfactory.hh b/dune/tectonic/factories/cantorfactory.hh similarity index 100% rename from src/factories/cantorfactory.hh rename to dune/tectonic/factories/cantorfactory.hh diff --git a/src/factories/cantorfactory_tmpl.cc b/dune/tectonic/factories/cantorfactory_tmpl.cc similarity index 100% rename from src/factories/cantorfactory_tmpl.cc rename to dune/tectonic/factories/cantorfactory_tmpl.cc diff --git a/src/factories/contactnetworkfactory.hh b/dune/tectonic/factories/contactnetworkfactory.hh similarity index 96% rename from src/factories/contactnetworkfactory.hh rename to dune/tectonic/factories/contactnetworkfactory.hh index c1968822..e62425fd 100644 --- a/src/factories/contactnetworkfactory.hh +++ b/dune/tectonic/factories/contactnetworkfactory.hh @@ -3,7 +3,7 @@ #include <dune/common/parametertree.hh> -#include "../data-structures/contactnetwork.hh" +#include "../data-structures/network/contactnetwork.hh" template <class HostGridType, class VectorType> class ContactNetworkFactory { diff --git a/src/factories/levelcontactnetworkfactory.hh b/dune/tectonic/factories/levelcontactnetworkfactory.hh similarity index 100% rename from src/factories/levelcontactnetworkfactory.hh rename to dune/tectonic/factories/levelcontactnetworkfactory.hh diff --git a/src/factories/stackedblocksfactory.cc b/dune/tectonic/factories/stackedblocksfactory.cc similarity index 97% rename from src/factories/stackedblocksfactory.cc rename to dune/tectonic/factories/stackedblocksfactory.cc index 051afa46..6e6f5428 100644 --- a/src/factories/stackedblocksfactory.cc +++ b/dune/tectonic/factories/stackedblocksfactory.cc @@ -6,9 +6,9 @@ #include <dune/contact/projections/normalprojection.hh> -#include "../multi-body-problem-data/bc.hh" -#include "../multi-body-problem-data/grid/cuboidgeometry.hh" -#include "../multi-body-problem-data/myglobalfrictiondata.hh" +#include "../problem-data/bc.hh" +#include "../problem-data/grid/cuboidgeometry.hh" +#include "../problem-data/myglobalfrictiondata.hh" #include "../utils/diameter.hh" @@ -106,7 +106,7 @@ void StackedBlocksFactory<HostGridType, VectorType>::setBodies() { // define weak patch and refine grid const auto& weakeningRegions = cuboidGeometry.weakeningRegions(); for (size_t j=0; j<weakeningRegions.size(); j++) { - refine(*grids[i], weakeningRegions[j], this->parset_.template get<double>("boundary.friction.smallestDiameter"), CuboidGeometry::lengthScale); + refine(*grids[i], weakeningRegions[j], this->parset_.template get<double>("boundary.friction.smallestDiameter"), CuboidGeometry::lengthScale()); } // determine minDiameter and maxDiameter @@ -151,7 +151,7 @@ void StackedBlocksFactory<HostGridType, VectorType>::setCouplings() { coupling->set(i, i+1, nonmortarPatch_[i], mortarPatch_[i], 0.1, Base::FrictionCouplingPair::CouplingType::STICK_SLIP, contactProjection, backend); coupling->setWeakeningPatch(weakPatches_[i]); - coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[i], CuboidGeometry::lengthScale)); + coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[i], CuboidGeometry::lengthScale())); } } @@ -185,7 +185,7 @@ void StackedBlocksFactory<HostGridType, VectorType>::setBoundaryConditions() { std::shared_ptr<Function> neumannFunction = std::make_shared<NeumannCondition>(); std::shared_ptr<Function> velocityDirichletFunction = std::make_shared<VelocityDirichletCondition>(); - const double lengthScale = CuboidGeometry::lengthScale; + const double lengthScale = CuboidGeometry::lengthScale(); for (size_t i=0; i<this->bodyCount_; i++) { const auto& body = this->contactNetwork_.body(i); diff --git a/src/factories/stackedblocksfactory.hh b/dune/tectonic/factories/stackedblocksfactory.hh similarity index 93% rename from src/factories/stackedblocksfactory.hh rename to dune/tectonic/factories/stackedblocksfactory.hh index b9471853..e8f9454f 100644 --- a/src/factories/stackedblocksfactory.hh +++ b/dune/tectonic/factories/stackedblocksfactory.hh @@ -9,9 +9,9 @@ #include "contactnetworkfactory.hh" -#include "../multi-body-problem-data/mybody.hh" -#include "../multi-body-problem-data/grid/mygrids.hh" -#include "../multi-body-problem-data/grid/cuboidgeometry.hh" +#include "../problem-data/mybody.hh" +#include "../problem-data/grid/mygrids.hh" +#include "../problem-data/grid/cuboidgeometry.hh" template <class HostGridType, class VectorType> class StackedBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType>{ private: @@ -69,6 +69,10 @@ template <class HostGridType, class VectorType> class StackedBlocksFactory : pub void setLevelCouplings() {} void setBoundaryConditions(); + auto& weakPatches() { + return weakPatches_; + } + private: static constexpr Dune::FieldVector<double, MY_DIM> zenith_() { #if MY_DIM == 2 diff --git a/src/factories/stackedblocksfactory_tmpl.cc b/dune/tectonic/factories/stackedblocksfactory_tmpl.cc similarity index 100% rename from src/factories/stackedblocksfactory_tmpl.cc rename to dune/tectonic/factories/stackedblocksfactory_tmpl.cc diff --git a/src/factories/threeblocksfactory.cc b/dune/tectonic/factories/threeblocksfactory.cc similarity index 96% rename from src/factories/threeblocksfactory.cc rename to dune/tectonic/factories/threeblocksfactory.cc index 7dded09d..61275c63 100644 --- a/src/factories/threeblocksfactory.cc +++ b/dune/tectonic/factories/threeblocksfactory.cc @@ -6,8 +6,8 @@ #include <dune/contact/projections/normalprojection.hh> -#include "../multi-body-problem-data/bc.hh" -#include "../multi-body-problem-data/myglobalfrictiondata.hh" +#include "../problem-data/bc.hh" +#include "../problem-data/myglobalfrictiondata.hh" #include "../utils/diameter.hh" @@ -28,8 +28,8 @@ void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setBodies() { double const depth = 0.60; origins[0] = {0, 0, 0}; - origins[1] = {0, origins[0][1] + widths[0], 0}; - origins[2] = {origins[1][0] + lengths[1], origins[0][1] + widths[0], 0}; + origins[1] = {0, origins[0][1] + heights[0], 0}; + origins[2] = {origins[1][0] + lengths[1], origins[0][1] + heights[0], 0}; cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lengths[0], heights[0], depth); cuboidGeometries_[0]->addWeakeningPatch(subParset, {origins[0][0], origins[0][1]+ heights[0], 0}, {origins[0][0] + lengths[0], origins[0][1]+ heights[0], 0}); @@ -70,7 +70,7 @@ void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setBodies() { // define weak patch and refine grid const auto& weakeningRegions = cuboidGeometry.weakeningRegions(); for (size_t j=0; j<weakeningRegions.size(); j++) { - refine(*grids[i], weakeningRegions[j], this->parset_.template get<double>("boundary.friction.smallestDiameter"), CuboidGeometry::lengthScale); + refine(*grids[i], weakeningRegions[j], this->parset_.template get<double>("boundary.friction.smallestDiameter"), CuboidGeometry::lengthScale()); } // determine minDiameter and maxDiameter @@ -137,7 +137,7 @@ void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setCouplings() { coupling->set(couplingIndices[i][0], couplingIndices[i][1], nonmortarPatch_[i], mortarPatch_[i], 0.1, Base::FrictionCouplingPair::CouplingType::STICK_SLIP, contactProjection, backend); coupling->setWeakeningPatch(weakPatches_[i]); - coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[i], CuboidGeometry::lengthScale)); + coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[i], CuboidGeometry::lengthScale())); } } @@ -149,7 +149,7 @@ void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setBoundaryConditions() { std::shared_ptr<Function> neumannFunction = std::make_shared<NeumannCondition>(); std::shared_ptr<Function> velocityDirichletFunction = std::make_shared<VelocityDirichletCondition>(); - const double lengthScale = CuboidGeometry::lengthScale; + const double lengthScale = CuboidGeometry::lengthScale(); for (size_t i=0; i<this->bodyCount_; i++) { const auto& body = this->contactNetwork_.body(i); diff --git a/src/factories/threeblocksfactory.hh b/dune/tectonic/factories/threeblocksfactory.hh similarity index 92% rename from src/factories/threeblocksfactory.hh rename to dune/tectonic/factories/threeblocksfactory.hh index e3405572..e72c7f1c 100644 --- a/src/factories/threeblocksfactory.hh +++ b/dune/tectonic/factories/threeblocksfactory.hh @@ -9,9 +9,9 @@ #include "contactnetworkfactory.hh" -#include "../multi-body-problem-data/mybody.hh" -#include "../multi-body-problem-data/grid/mygrids.hh" -#include "../multi-body-problem-data/grid/cuboidgeometry.hh" +#include "../problem-data/mybody.hh" +#include "../problem-data/grid/mygrids.hh" +#include "../problem-data/grid/cuboidgeometry.hh" template <class HostGridType, class VectorType> class ThreeBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType>{ @@ -70,6 +70,9 @@ class ThreeBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType void setLevelCouplings() {} void setBoundaryConditions(); + auto& weakPatches() { + return weakPatches_; + } private: static constexpr Dune::FieldVector<double, MY_DIM> zenith_() { #if MY_DIM == 2 diff --git a/src/factories/threeblocksfactory_tmpl.cc b/dune/tectonic/factories/threeblocksfactory_tmpl.cc similarity index 100% rename from src/factories/threeblocksfactory_tmpl.cc rename to dune/tectonic/factories/threeblocksfactory_tmpl.cc diff --git a/dune/tectonic/factories/twoblocksfactory.cc b/dune/tectonic/factories/twoblocksfactory.cc new file mode 100644 index 00000000..f58defd7 --- /dev/null +++ b/dune/tectonic/factories/twoblocksfactory.cc @@ -0,0 +1,199 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <dune/fufem/geometry/convexpolyhedron.hh> + +#include <dune/contact/projections/normalprojection.hh> + +#include "../problem-data/bc.hh" +#include "../problem-data/myglobalfrictiondata.hh" + +#include "../utils/diameter.hh" + +#include "twoblocksfactory.hh" + +template <class HostGridType, class VectorTEMPLATE> +void TwoBlocksFactory<HostGridType, VectorTEMPLATE>::setBodies() { + // set up cuboid geometries + + std::array<double, 2> lengths = {this->parset_.template get<double>("body0.length"), this->parset_.template get<double>("body1.length")}; + std::array<double, 2> heights = {this->parset_.template get<double>("body0.height"), this->parset_.template get<double>("body1.height")}; + + std::array<GlobalCoords, 2> origins; + + const auto& frictionParset = this->parset_.sub("boundary.friction"); + +#if MY_DIM == 3 // TODO: not implemented + std::array<double, 2> depths = {this->parset_.template get<double>("body0.depth"), this->parset_.template get<double>("body1.depth")}; + + origins[0] = {0, 0, 0}; + origins[1] = {lengths[0]/2.0, origins[0][1] + heights[0], 0}; + + cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lengths[0], heights[0], depths[0]); + cuboidGeometries_[0]->addWeakeningPatch(frictionParset, {origins[0][0], origins[0][1]+ heights[0], 0}, {origins[0][0] + lengths[0], origins[0][1]+ heights[0], 0}); + + cuboidGeometries_[1] = std::make_shared<CuboidGeometry>(origins[1], lengths[1], heights[1], depths[1]); + cuboidGeometries_[1]->addWeakeningPatch(frictionParset, origins[1], {origins[1][0] + lengths[1], origins[1][1], 0}); + cuboidGeometries_[1]->addWeakeningPatch(frictionParset, origins[1], {origins[1][0] + lengths[1], origins[1][1] + heights[1], 0}); + +#elif MY_DIM == 2 + origins[0] = {0, 0}; + origins[1] = {lengths[0]/2.0, origins[0][1] + heights[0]}; + + cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lengths[0], heights[0]); + cuboidGeometries_[0]->addWeakeningPatch(frictionParset, {origins[0][0], origins[0][1]+ heights[0]}, {origins[0][0] + lengths[0], origins[0][1]+ heights[0]}); + + cuboidGeometries_[1] = std::make_shared<CuboidGeometry>(origins[1], lengths[1], heights[1]); + cuboidGeometries_[1]->addWeakeningPatch(frictionParset, origins[1], {origins[1][0] + lengths[1], origins[1][1]}); + cuboidGeometries_[1]->addWeakeningPatch(frictionParset, {origins[1][0] + lengths[1], origins[1][1]}, {origins[1][0] + lengths[1], origins[1][1] + heights[1]}); +#else +#error CuboidGeometry only supports 2D and 3D!" +#endif + + // set up reference grids + gridConstructor_ = std::make_unique<GridsConstructor<HostGridType>>(cuboidGeometries_); + auto& grids = gridConstructor_->getGrids(); + + for (size_t i=0; i<this->bodyCount_; i++) { + const auto& cuboidGeometry = *cuboidGeometries_[i]; + + // define weak patch and refine grid + const auto& weakeningRegions = cuboidGeometry.weakeningRegions(); + for (size_t j=0; j<weakeningRegions.size(); j++) { + refine(*grids[i], weakeningRegions[j], this->parset_.template get<double>("boundary.friction.smallestDiameter"), CuboidGeometry::lengthScale()); + } + + // determine minDiameter and maxDiameter + double minDiameter = std::numeric_limits<double>::infinity(); + double maxDiameter = 0.0; + for (auto &&e : elements(grids[i]->leafGridView())) { + auto const geometry = e.geometry(); + auto const diam = diameter(geometry); + minDiameter = std::min(minDiameter, diam); + maxDiameter = std::max(maxDiameter, diam); + } + std::cout << "Grid" << i << " min diameter: " << minDiameter << std::endl; + std::cout << "Grid" << i << " max diameter: " << maxDiameter << std::endl; + } + + bodyData_[0] = std::make_shared<MyBodyData<dim>>(this->parset_.sub("body0"), this->parset_.template get<double>("gravity"), zenith_()); + this->bodies_[0] = std::make_shared<typename Base::LeafBody>(bodyData_[0], grids[0]); + + bodyData_[1] = std::make_shared<MyBodyData<dim>>(this->parset_.sub("body1"), this->parset_.template get<double>("gravity"), zenith_()); + this->bodies_[1] = std::make_shared<typename Base::LeafBody>(bodyData_[1], grids[1]); +} + +template <class HostGridType, class VectorTEMPLATE> +void TwoBlocksFactory<HostGridType, VectorTEMPLATE>::setLevelBodies() { + const size_t maxLevel = std::max({this->bodies_[0]->grid()->maxLevel(), this->bodies_[1]->grid()->maxLevel()}); + + for (size_t l=0; l<=maxLevel; l++) { + std::vector<size_t> bodyLevels(2, l); + this->contactNetwork_.addLevel(bodyLevels, l); + } +} + +template <class HostGridType, class VectorTEMPLATE> +void TwoBlocksFactory<HostGridType, VectorTEMPLATE>::setCouplings() { + for (size_t i=0; i<this->bodyCount_; i++) { + const auto& cuboidGeometry = *cuboidGeometries_[i]; + leafFaces_[i] = std::make_shared<LeafFaces>(this->bodies_[i]->gridView(), cuboidGeometry); + levelFaces_[i] = std::make_shared<LevelFaces>(this->bodies_[i]->grid()->levelGridView(0), cuboidGeometry); + } + + auto contactProjection = std::make_shared<Dune::Contact::NormalProjection<LeafBoundaryPatch>>(); + + nonmortarPatch_[0] = std::make_shared<LevelBoundaryPatch>(levelFaces_[1]->lower); + mortarPatch_[0] = std::make_shared<LevelBoundaryPatch>(levelFaces_[0]->upper); + weakPatches_[0] = std::make_shared<WeakeningRegion>(cuboidGeometries_[1]->weakeningRegions()[0]); + + auto& coupling = this->couplings_[0]; + coupling = std::make_shared<typename Base::FrictionCouplingPair>(); + + coupling->set(1, 0, nonmortarPatch_[0], mortarPatch_[0], 0.1, Base::FrictionCouplingPair::CouplingType::STICK_SLIP, contactProjection, nullptr); + coupling->setWeakeningPatch(weakPatches_[0]); + coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[0], CuboidGeometry::lengthScale())); +} + +template <class HostGridType, class VectorTEMPLATE> +void TwoBlocksFactory<HostGridType, VectorTEMPLATE>::setBoundaryConditions() { + using LeafBoundaryCondition = BoundaryCondition<LeafGridView, dim>; + + using Function = Dune::VirtualFunction<double, double>; + std::shared_ptr<Function> neumannFunction = std::make_shared<NeumannCondition>(); + std::shared_ptr<Function> velocityDirichletFunction = std::make_shared<VelocityDirichletCondition>(); + + const double lengthScale = CuboidGeometry::lengthScale(); + + // body0: Dirichlet boundary (lower) + const auto& body0 = this->contactNetwork_.body(0); + const auto& leafVertexCount0 = body0->nVertices(); + std::shared_ptr<Dune::BitSetVector<dim>> zeroDirichletNodes = std::make_shared<Dune::BitSetVector<dim>>(leafVertexCount0); + for (int j=0; j<leafVertexCount0; j++) { + if (leafFaces_[0]->lower.containsVertex(j)) { + for (size_t d=0; d<dim; d++) { + (*zeroDirichletNodes)[j][d] = true; + } + } + } + + std::shared_ptr<LeafBoundaryCondition> zeroDirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet"); + zeroDirichletBoundary->setBoundaryPatch(body0->gridView(), zeroDirichletNodes); + + std::shared_ptr<Function> zeroFunction = std::make_shared<NeumannCondition>(); + zeroDirichletBoundary->setBoundaryFunction(zeroFunction); + body0->addBoundaryCondition(zeroDirichletBoundary); + + // body1: Dirichlet boundary (upper) + const auto& body1 = this->contactNetwork_.body(1); + const auto& leafVertexCount1 = body1->nVertices(); + std::shared_ptr<Dune::BitSetVector<dim>> velocityDirichletNodes = std::make_shared<Dune::BitSetVector<dim>>(leafVertexCount1); + for (int j=0; j<leafVertexCount1; j++) { + if (leafFaces_[1]->upper.containsVertex(j)) + (*velocityDirichletNodes)[j][0] = true; + + #if MY_DIM == 3 //TODO: wrong, needs revision + if (leafFaces_[1]->front.containsVertex(j) || leafFaces_[1]->back.containsVertex(j)) + zeroDirichletNodes->at(j)[2] = true; + #endif + } + + std::shared_ptr<LeafBoundaryCondition> velocityDirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet"); + + velocityDirichletBoundary->setBoundaryPatch(body1->gridView(), velocityDirichletNodes); + velocityDirichletBoundary->setBoundaryFunction(velocityDirichletFunction); + body1->addBoundaryCondition(velocityDirichletBoundary); + + // body0, body1: natural boundary conditions + for (size_t i=0; i<this->bodyCount_; i++) { + const auto& body = this->contactNetwork_.body(i); + const auto& leafVertexCount = body->nVertices(); + + // Neumann boundary + std::shared_ptr<LeafBoundaryCondition> neumannBoundary = std::make_shared<LeafBoundaryCondition>(std::make_shared<LeafBoundaryPatch>(body->gridView()), neumannFunction, "neumann"); + body->addBoundaryCondition(neumannBoundary); + } + + // body1: Neumann boundary (upper) + // normal load + std::shared_ptr<Dune::BitSetVector<dim>> loadNeumannNodes = std::make_shared<Dune::BitSetVector<dim>>(leafVertexCount1); + for (int j=0; j<leafVertexCount1; j++) { + if (leafFaces_[1]->upper.containsVertex(j)) + (*loadNeumannNodes)[j][1] = true; + + #if MY_DIM == 3 //TODO: wrong, needs revision + if (leafFaces_[1]->front.containsVertex(j) || leafFaces_[1]->back.containsVertex(j)) + zeroDirichletNodes->at(j)[2] = true; + #endif + } + + std::shared_ptr<LeafBoundaryCondition> loadNeumannBoundary = std::make_shared<LeafBoundaryCondition>("neumann"); + std::shared_ptr<Function> constantFunction = std::make_shared<NeumannCondition>(this->parset_.template get<double>("boundary.neumann.sigmaN")); + + loadNeumannBoundary->setBoundaryPatch(body1->gridView(), loadNeumannNodes); + loadNeumannBoundary->setBoundaryFunction(constantFunction); + body1->addBoundaryCondition(loadNeumannBoundary); +} + +#include "twoblocksfactory_tmpl.cc" diff --git a/dune/tectonic/factories/twoblocksfactory.hh b/dune/tectonic/factories/twoblocksfactory.hh new file mode 100644 index 00000000..a02cd74a --- /dev/null +++ b/dune/tectonic/factories/twoblocksfactory.hh @@ -0,0 +1,87 @@ +#ifndef DUNE_TECTONIC_FACTORIES_TWOBLOCKSFACTORY_HH +#define DUNE_TECTONIC_FACTORIES_TWOBLOCKSFACTORY_HH + +#include <dune/common/bitsetvector.hh> +#include <dune/common/function.hh> +#include <dune/common/fvector.hh> + +#include <dune/fufem/boundarypatch.hh> + +#include "contactnetworkfactory.hh" + +#include "../problem-data/mybody.hh" +#include "../problem-data/grid/mygrids.hh" +#include "../problem-data/grid/cuboidgeometry.hh" + +template <class HostGridType, class VectorType> class TwoBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType>{ +private: + using Base = ContactNetworkFactory<HostGridType, VectorType>; + +public: + using ContactNetwork = typename Base::ContactNetwork; + +private: + using GlobalCoords = typename ContactNetwork::LocalVector; + + using LeafGridView = typename ContactNetwork::GridView; + using LevelGridView = typename ContactNetwork::GridType::LevelGridView; + + using LevelBoundaryPatch = BoundaryPatch<LevelGridView>; + using LeafBoundaryPatch = BoundaryPatch<LeafGridView>; + + using LeafFaces = MyFaces<LeafGridView>; + using LevelFaces = MyFaces<LevelGridView>; + + using CuboidGeometry= CuboidGeometry<typename GlobalCoords::field_type>; + using WeakeningRegion = typename CuboidGeometry::WeakeningRegion; + + static const int dim = ContactNetwork::dim; + + std::vector<std::shared_ptr<MyBodyData<dim>>> bodyData_; // material properties of bodies + + std::unique_ptr<GridsConstructor<HostGridType>> gridConstructor_; + + std::vector<std::shared_ptr<CuboidGeometry>> cuboidGeometries_; + + std::vector<std::shared_ptr<LeafFaces>> leafFaces_; + std::vector<std::shared_ptr<LevelFaces>> levelFaces_; + + std::vector<std::shared_ptr<WeakeningRegion>> weakPatches_; + + std::vector<std::shared_ptr<LevelBoundaryPatch>> nonmortarPatch_; + std::vector<std::shared_ptr<LevelBoundaryPatch>> mortarPatch_; + +public: + TwoBlocksFactory(const Dune::ParameterTree& parset) : + Base(parset, 2, 1), + bodyData_(2), + cuboidGeometries_(2), + leafFaces_(2), + levelFaces_(2), + weakPatches_(2), + nonmortarPatch_(1), + mortarPatch_(1) + {} + + void setBodies(); + void setLevelBodies(); + void setCouplings(); + void setLevelCouplings() {} + void setBoundaryConditions(); + + auto& weakPatches() { + return weakPatches_; + } + +private: + static constexpr Dune::FieldVector<double, MY_DIM> zenith_() { + #if MY_DIM == 2 + return {0, 1}; + #elif MY_DIM == 3 + return {0, 1, 0}; + #endif + } +}; +#endif + + diff --git a/dune/tectonic/factories/twoblocksfactory_tmpl.cc b/dune/tectonic/factories/twoblocksfactory_tmpl.cc new file mode 100644 index 00000000..4a373e81 --- /dev/null +++ b/dune/tectonic/factories/twoblocksfactory_tmpl.cc @@ -0,0 +1,8 @@ +#ifndef MY_DIM +#error MY_DIM unset +#endif + +#include "../explicitgrid.hh" +#include "../explicitvectors.hh" + +template class TwoBlocksFactory<Grid, Vector>; diff --git a/src/gridselector.hh b/dune/tectonic/gridselector.hh similarity index 100% rename from src/gridselector.hh rename to dune/tectonic/gridselector.hh diff --git a/dune/tectonic/io/CMakeLists.txt b/dune/tectonic/io/CMakeLists.txt new file mode 100644 index 00000000..c1aada25 --- /dev/null +++ b/dune/tectonic/io/CMakeLists.txt @@ -0,0 +1,16 @@ +add_subdirectory("hdf5") + +add_custom_target(tectonic_dune_io SOURCES + hdf5-bodywriter.hh + hdf5-levelwriter.hh + uniform-grid-writer.cc + vtk.hh + vtk.cc +) + +#install headers +install(FILES + hdf5-bodywriter.hh + hdf5-levelwriter.hh + vtk.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/io/hdf5-bodywriter.hh b/dune/tectonic/io/hdf5-bodywriter.hh similarity index 64% rename from src/io/hdf5-bodywriter.hh rename to dune/tectonic/io/hdf5-bodywriter.hh index 549062c7..dfb2b3aa 100644 --- a/src/io/hdf5-bodywriter.hh +++ b/dune/tectonic/io/hdf5-bodywriter.hh @@ -11,15 +11,17 @@ template <class ProgramState, class VertexBasis, class GridView> class HDF5BodyWriter { private: + using PatchInfoWriter = PatchInfoWriter<ProgramState, VertexBasis, GridView>; + using FrictionalBoundaryWriter = FrictionalBoundaryWriter<ProgramState, GridView>; +public: using VertexCoordinates = typename ProgramState::Vector; using FrictionPatches = std::vector<const BoundaryPatch<GridView>* >; using WeakPatches = std::vector<const ConvexPolyhedron<LocalVector>* >; using LocalVector = typename VertexCoordinates::block_type; - friend class HDF5LevelWriter<ProgramState, VertexBasis, GridView>; + //friend class HDF5LevelWriter<ProgramState, VertexBasis, GridView>; -public: HDF5BodyWriter( HDF5::Grouplike &file, const VertexCoordinates& vertexCoordinates, @@ -37,31 +39,22 @@ class HDF5BodyWriter { for (size_t i=0; i<patchCount_; i++) { #if MY_DIM == 3 - patchInfoWriters_[i] = new PatchInfoWriter<ProgramState, VertexBasis, GridView>(file_, vertexBasis, *frictionPatches[i], *weakPatches[i], i); -#endif - frictionBoundaryWriters_[i] = new FrictionalBoundaryWriter<ProgramState, GridView>(file_, vertexCoordinates, *frictionPatches[i], i); - } - } - - ~HDF5BodyWriter() { - for (size_t i=0; i<patchCount_; i++) { -#if MY_DIM == 3 - delete patchInfoWriters_[i]; + patchInfoWriters_[i] = std::make_unique<PatchInfoWriter>(file_, vertexBasis, *frictionPatches[i], *weakPatches[i], i); #endif - delete frictionBoundaryWriters_[i]; + frictionBoundaryWriters_[i] = std::make_unique<FrictionalBoundaryWriter>(file_, vertexCoordinates, *frictionPatches[i], i); } } template <class Friction> void reportSolution(ProgramState const &programState, // for the friction coefficient - std::vector<std::shared_ptr<Friction>>& friction) { + Friction& friction) { for (size_t i=0; i<patchCount_; i++) { #if MY_DIM == 3 patchInfoWriters_[i]->write(programState); #endif - frictionBoundaryWriters_[i]->write(programState, *friction[i]); + frictionBoundaryWriters_[i]->write(programState, friction); } } @@ -71,9 +64,9 @@ class HDF5BodyWriter { HDF5::Grouplike &file_; #if MY_DIM == 3 - std::vector<PatchInfoWriter<ProgramState, VertexBasis, GridView>* > patchInfoWriters_; + std::vector<std::unique_ptr<PatchInfoWriter>> patchInfoWriters_; #endif - std::vector<FrictionalBoundaryWriter<ProgramState, GridView>* > frictionBoundaryWriters_; + std::vector<std::unique_ptr<FrictionalBoundaryWriter>> frictionBoundaryWriters_; }; #endif diff --git a/src/io/hdf5-levelwriter.hh b/dune/tectonic/io/hdf5-levelwriter.hh similarity index 67% rename from src/io/hdf5-levelwriter.hh rename to dune/tectonic/io/hdf5-levelwriter.hh index 66e3c048..4edabd8b 100644 --- a/src/io/hdf5-levelwriter.hh +++ b/dune/tectonic/io/hdf5-levelwriter.hh @@ -9,16 +9,14 @@ template <class ProgramState, class VertexBasis, class GridView> class HDF5LevelWriter { -private: +public: using HDF5BodyWriter = HDF5BodyWriter<ProgramState, VertexBasis, GridView>; using VertexCoordinates = std::vector<typename HDF5BodyWriter::VertexCoordinates>; - using VertexBases = std::vector<VertexBasis>; + using VertexBases = std::vector<const VertexBasis*>; using FrictionPatches = std::vector<typename HDF5BodyWriter::FrictionPatches>; using WeakPatches = std::vector<typename HDF5BodyWriter::WeakPatches>; - friend class HDF5NetworkWriter<ProgramState, VertexBasis, GridView>; - -public: + //friend class HDF5NetworkWriter<ProgramState, VertexBasis, GridView>; HDF5LevelWriter(HDF5::Grouplike &file, const VertexCoordinates& vertexCoordinates, @@ -32,31 +30,25 @@ class HDF5LevelWriter { bodyWriters_(bodyCount_) { for (size_t i=0; i<bodyCount_; i++) { - bodyWriters_[i] = new HDF5BodyWriter<ProgramState, VertexBasis, GridView>(file_, vertexCoordinates[i], vertexBases[i], frictionBoundaries[i], weakPatches[i]); - } - } - - ~HDF5LevelWriter() { - for (size_t i=0; i<bodyCount_; i++) { - delete bodyWriters_[i]; + bodyWriters_[i] = std::make_unique<HDF5BodyWriter>(file_, vertexCoordinates[i], *vertexBases[i], frictionBoundaries[i], weakPatches[i]); } } template <class Friction> void reportSolution( - ProgramState const &programState, + const ProgramState& programState, // for the friction coefficient - std::vector<std::shared_ptr<Friction>>& friction) { + Friction& friction) { timeWriter_.write(programState); for (size_t i=0; i<bodyCount_; i++) { - bodyWriters_[i]->reportSolution(programState, *friction[i]); //TODO + bodyWriters_[i]->reportSolution(programState, friction); //TODO } } void reportIterations( - ProgramState const &programState, - IterationRegister const &iterationCount) { + const ProgramState& programState, + const IterationRegister& iterationCount) { iterationWriter_.write(programState.timeStep, iterationCount); } @@ -68,6 +60,6 @@ class HDF5LevelWriter { IterationWriter iterationWriter_; TimeWriter<ProgramState> timeWriter_; - std::vector<HDF5BodyWriter* > bodyWriters_; + std::vector<std::unique_ptr<HDF5BodyWriter>> bodyWriters_; }; #endif diff --git a/dune/tectonic/io/hdf5/CMakeLists.txt b/dune/tectonic/io/hdf5/CMakeLists.txt new file mode 100644 index 00000000..511ce682 --- /dev/null +++ b/dune/tectonic/io/hdf5/CMakeLists.txt @@ -0,0 +1,26 @@ +add_custom_target(tectonic_dune_io_hdf5 SOURCES + frictionalboundary-writer.hh + frictionalboundary-writer.cc + iteration-writer.hh + iteration-writer.cc + patchinfo-writer.hh + patchinfo-writer.cc + restart-io.hh + restart-io.cc + restrict.hh + surface-writer.hh + surface-writer.cc + time-writer.hh + time-writer.cc +) + +#install headers +install(FILES + frictionalboundary-writer.hh + iteration-writer.hh + patchinfo-writer.hh + restart-io.hh + restrict.hh + surface-writer.hh + time-writer.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/io/hdf5/frictionalboundary-writer.cc b/dune/tectonic/io/hdf5/frictionalboundary-writer.cc similarity index 93% rename from src/io/hdf5/frictionalboundary-writer.cc rename to dune/tectonic/io/hdf5/frictionalboundary-writer.cc index 19641aa5..0cb5e01a 100644 --- a/src/io/hdf5/frictionalboundary-writer.cc +++ b/dune/tectonic/io/hdf5/frictionalboundary-writer.cc @@ -52,12 +52,13 @@ void FrictionalBoundaryWriter<ProgramState, GridView>::write( addEntry(frictionalBoundaryStateWriter_, programState.timeStep, frictionalBoundaryStates); - friction.updateAlpha(programState.alpha); + //TODO: needs to transform programState.v to relative velocities with nBodyAssembler + /*friction.updateAlpha(programState.alpha); auto const c = friction.coefficientOfFriction(programState.v[id_]); auto const frictionalBoundaryCoefficient = restrictToSurface(c, frictionalBoundary_); addEntry(frictionalBoundaryCoefficientWriter_, programState.timeStep, - frictionalBoundaryCoefficient); + frictionalBoundaryCoefficient);*/ } #include "frictionalboundary-writer_tmpl.cc" diff --git a/src/io/hdf5/frictionalboundary-writer.hh b/dune/tectonic/io/hdf5/frictionalboundary-writer.hh similarity index 100% rename from src/io/hdf5/frictionalboundary-writer.hh rename to dune/tectonic/io/hdf5/frictionalboundary-writer.hh diff --git a/src/io/hdf5/frictionalboundary-writer_tmpl.cc b/dune/tectonic/io/hdf5/frictionalboundary-writer_tmpl.cc similarity index 100% rename from src/io/hdf5/frictionalboundary-writer_tmpl.cc rename to dune/tectonic/io/hdf5/frictionalboundary-writer_tmpl.cc diff --git a/src/io/hdf5/iteration-writer.cc b/dune/tectonic/io/hdf5/iteration-writer.cc similarity index 100% rename from src/io/hdf5/iteration-writer.cc rename to dune/tectonic/io/hdf5/iteration-writer.cc diff --git a/src/io/hdf5/iteration-writer.hh b/dune/tectonic/io/hdf5/iteration-writer.hh similarity index 100% rename from src/io/hdf5/iteration-writer.hh rename to dune/tectonic/io/hdf5/iteration-writer.hh diff --git a/src/io/hdf5/patchinfo-writer.cc b/dune/tectonic/io/hdf5/patchinfo-writer.cc similarity index 89% rename from src/io/hdf5/patchinfo-writer.cc rename to dune/tectonic/io/hdf5/patchinfo-writer.cc index 82b394ea..c7a38dda 100644 --- a/src/io/hdf5/patchinfo-writer.cc +++ b/dune/tectonic/io/hdf5/patchinfo-writer.cc @@ -8,19 +8,19 @@ #include "patchinfo-writer.hh" template <class LocalVector, class GridView> -GridEvaluator<LocalVector, GridView>::GridEvaluator( +GridEvaluator<LocalVector, GridView>::GridEvaluator(const CuboidGeometry& cuboidGeometry, ConvexPolyhedron<LocalVector> const &weakPatch, GridView const &gridView) { - double const bufferWidth = 0.05 * MyGeometry::lengthScale; + double const bufferWidth = 0.05 * cuboidGeometry.lengthScale(); auto const xminmax = std::minmax_element( weakPatch.vertices.begin(), weakPatch.vertices.end(), [](LocalVector const &a, LocalVector const &b) { return a[0] < b[0]; }); double const xmin = (*xminmax.first)[0] - bufferWidth; double const xspan = (*xminmax.second)[0] + bufferWidth - xmin; - double const zmin = -MyGeometry::depth / 2.0; - double const zspan = MyGeometry::depth; + double const zmin = -cuboidGeometry.depth() / 2.0; + double const zspan = cuboidGeometry.depth(); - double spatialResolution = 0.01 * MyGeometry::lengthScale; + double spatialResolution = 0.01 * cuboidGeometry.lengthScale(); size_t const xsteps = std::round(xspan / spatialResolution); size_t const zsteps = std::round(zspan / spatialResolution); @@ -32,7 +32,7 @@ GridEvaluator<LocalVector, GridView>::GridEvaluator( zCoordinates[zi] = zmin + zi * zspan / zsteps; HierarchicApproximation<typename GridView::Grid, GridView> const - hApproximation(gridView.grid(), gridView, 1e-6 * MyGeometry::lengthScale); + hApproximation(gridView.grid(), gridView, 1e-6 * cuboidGeometry.lengthScale()); LocalVector global(0); localInfo.resize(xsteps + 1); diff --git a/src/io/hdf5/patchinfo-writer.hh b/dune/tectonic/io/hdf5/patchinfo-writer.hh similarity index 83% rename from src/io/hdf5/patchinfo-writer.hh rename to dune/tectonic/io/hdf5/patchinfo-writer.hh index cd446534..567c36e9 100644 --- a/src/io/hdf5/patchinfo-writer.hh +++ b/dune/tectonic/io/hdf5/patchinfo-writer.hh @@ -8,14 +8,16 @@ #include <dune/fufem/geometry/convexpolyhedron.hh> #include <dune/fufem/hdf5/sequenceio.hh> -#include "../../one-body-problem-data/mygeometry.hh" +#include "../../problem-data/grid/cuboidgeometry.hh" template <class LocalVector, class GridView> class GridEvaluator { using Element = typename GridView::Grid::template Codim<0>::Entity; + using CuboidGeometry = CuboidGeometry<typename LocalVector::field_type>; public: - GridEvaluator(ConvexPolyhedron<LocalVector> const &weakPatch, - GridView const &gridView); + GridEvaluator(const CuboidGeometry& cuboidGeometry, + const ConvexPolyhedron<LocalVector>& weakPatch, + const GridView& gridView); template <class Function> Dune::Matrix<typename Function::RangeType> evaluate(Function const &f) const; diff --git a/src/io/hdf5/patchinfo-writer_tmpl.cc b/dune/tectonic/io/hdf5/patchinfo-writer_tmpl.cc similarity index 100% rename from src/io/hdf5/patchinfo-writer_tmpl.cc rename to dune/tectonic/io/hdf5/patchinfo-writer_tmpl.cc diff --git a/src/io/hdf5/restart-io.cc b/dune/tectonic/io/hdf5/restart-io.cc similarity index 100% rename from src/io/hdf5/restart-io.cc rename to dune/tectonic/io/hdf5/restart-io.cc diff --git a/src/io/hdf5/restart-io.hh b/dune/tectonic/io/hdf5/restart-io.hh similarity index 100% rename from src/io/hdf5/restart-io.hh rename to dune/tectonic/io/hdf5/restart-io.hh diff --git a/src/io/hdf5/restart-io_tmpl.cc b/dune/tectonic/io/hdf5/restart-io_tmpl.cc similarity index 100% rename from src/io/hdf5/restart-io_tmpl.cc rename to dune/tectonic/io/hdf5/restart-io_tmpl.cc diff --git a/src/io/hdf5/restrict.hh b/dune/tectonic/io/hdf5/restrict.hh similarity index 100% rename from src/io/hdf5/restrict.hh rename to dune/tectonic/io/hdf5/restrict.hh diff --git a/src/io/hdf5/surface-writer.cc b/dune/tectonic/io/hdf5/surface-writer.cc similarity index 100% rename from src/io/hdf5/surface-writer.cc rename to dune/tectonic/io/hdf5/surface-writer.cc diff --git a/src/io/hdf5/surface-writer.hh b/dune/tectonic/io/hdf5/surface-writer.hh similarity index 100% rename from src/io/hdf5/surface-writer.hh rename to dune/tectonic/io/hdf5/surface-writer.hh diff --git a/src/io/hdf5/surface-writer_tmpl.cc b/dune/tectonic/io/hdf5/surface-writer_tmpl.cc similarity index 100% rename from src/io/hdf5/surface-writer_tmpl.cc rename to dune/tectonic/io/hdf5/surface-writer_tmpl.cc diff --git a/src/io/hdf5/time-writer.cc b/dune/tectonic/io/hdf5/time-writer.cc similarity index 100% rename from src/io/hdf5/time-writer.cc rename to dune/tectonic/io/hdf5/time-writer.cc diff --git a/src/io/hdf5/time-writer.hh b/dune/tectonic/io/hdf5/time-writer.hh similarity index 100% rename from src/io/hdf5/time-writer.hh rename to dune/tectonic/io/hdf5/time-writer.hh diff --git a/src/io/hdf5/time-writer_tmpl.cc b/dune/tectonic/io/hdf5/time-writer_tmpl.cc similarity index 100% rename from src/io/hdf5/time-writer_tmpl.cc rename to dune/tectonic/io/hdf5/time-writer_tmpl.cc diff --git a/src/io/uniform-grid-writer.cc b/dune/tectonic/io/uniform-grid-writer.cc similarity index 100% rename from src/io/uniform-grid-writer.cc rename to dune/tectonic/io/uniform-grid-writer.cc diff --git a/src/io/vtk.cc b/dune/tectonic/io/vtk.cc similarity index 100% rename from src/io/vtk.cc rename to dune/tectonic/io/vtk.cc diff --git a/src/io/vtk.hh b/dune/tectonic/io/vtk.hh similarity index 100% rename from src/io/vtk.hh rename to dune/tectonic/io/vtk.hh diff --git a/src/io/vtk_tmpl.cc b/dune/tectonic/io/vtk_tmpl.cc similarity index 100% rename from src/io/vtk_tmpl.cc rename to dune/tectonic/io/vtk_tmpl.cc diff --git a/dune/tectonic/minimisation.hh b/dune/tectonic/minimisation.hh deleted file mode 100644 index 7933b7d8..00000000 --- a/dune/tectonic/minimisation.hh +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef DUNE_TECTONIC_MINIMISATION_HH -#define DUNE_TECTONIC_MINIMISATION_HH - -#include <dune/common/fmatrix.hh> -#include <dune/common/fvector.hh> -#include <dune/common/stdstreams.hh> - -#include <dune/fufem/arithmetic.hh> -#include <dune/fufem/interval.hh> -#include <dune/tnnmg/problem-classes/bisection.hh> - -#include <dune/tectonic/mydirectionalconvexfunction.hh> - -// Warning: this exploits the property v*x = 0 -template <class Functional> -double lineSearch(Functional const &J, - typename Functional::LocalVector const &x, - typename Functional::LocalVector const &v, - Bisection const &bisection) { - MyDirectionalConvexFunction<typename Functional::Nonlinearity> const JRest( - J.alpha * v.two_norm2(), J.b * v, J.phi, x, v); - int count; - return bisection.minimize(JRest, 0.0, 0.0, count); -} - -/** Minimise a quadratic problem, for which both the quadratic and the - nonlinear term have gradients which point in the direction of - their arguments */ -template <class Functional> -void minimise(Functional const &J, typename Functional::LocalVector &x, - Bisection const &bisection) { - auto v = J.b; - double const vnorm = v.two_norm(); - if (vnorm <= 0.0) - return; - v /= vnorm; - - double const alpha = lineSearch(J, x, v, bisection); - Arithmetic::addProduct(x, alpha, v); -} -#endif diff --git a/dune/tectonic/myblockproblem.hh b/dune/tectonic/myblockproblem.hh deleted file mode 100644 index 78cf36f4..00000000 --- a/dune/tectonic/myblockproblem.hh +++ /dev/null @@ -1,273 +0,0 @@ -#ifndef DUNE_TECTONIC_MYBLOCKPROBLEM_HH -#define DUNE_TECTONIC_MYBLOCKPROBLEM_HH - -// Based on dune/tnnmg/problem-classes/blocknonlineartnnmgproblem.hh - -#include <dune/common/bitsetvector.hh> -#include <dune/common/parametertree.hh> -#include <dune/common/fmatrixev.hh> - -#include <dune/fufem/arithmetic.hh> -#include <dune/solvers/common/interval.hh> -#include <dune/solvers/computeenergy.hh> -#include <dune/tnnmg/problem-classes/bisection.hh> -#include <dune/tnnmg/problem-classes/blocknonlineargsproblem.hh> - -#include <dune/tectonic/globalfriction.hh> -#include <dune/tectonic/minimisation.hh> -#include <dune/tectonic/mydirectionalconvexfunction.hh> -#include <dune/tectonic/quadraticenergy.hh> - -/** \brief Base class for problems where each block can be solved with a - * modified gradient method */ -template <class ConvexProblem> -class MyBlockProblem : /* not public */ BlockNonlinearGSProblem<ConvexProblem> { -private: - typedef BlockNonlinearGSProblem<ConvexProblem> Base; - -public: - using typename Base::ConvexProblemType; - using typename Base::LocalMatrixType; - using typename Base::LocalVectorType; - using typename Base::MatrixType; - using typename Base::VectorType; - - size_t static const block_size = ConvexProblem::block_size; - size_t static const coarse_block_size = block_size; - - /** \brief Solves one local system */ - class IterateObject; - - struct Linearization { - size_t static const block_size = coarse_block_size; - - using LocalMatrix = typename MyBlockProblem<ConvexProblem>::LocalMatrixType; - using MatrixType = Dune::BCRSMatrix<typename Linearization::LocalMatrix>; - using VectorType = - Dune::BlockVector<Dune::FieldVector<double, Linearization::block_size>>; - using BitVectorType = Dune::BitSetVector<Linearization::block_size>; - - typename Linearization::MatrixType A; - typename Linearization::VectorType b; - typename Linearization::BitVectorType ignore; - - Dune::BitSetVector<Linearization::block_size> truncation; - }; - - MyBlockProblem(Dune::ParameterTree const &parset, ConvexProblem &problem) - : Base(parset, problem), - maxEigenvalues_(problem.f.size()), - localBisection(0.0, 1.0, 0.0, 0.0) { - for (size_t i = 0; i < problem.f.size(); ++i) { - LocalVectorType eigenvalues; - Dune::FMatrixHelp::eigenValues(problem.A[i][i], eigenvalues); - maxEigenvalues_[i] = - *std::max_element(std::begin(eigenvalues), std::end(eigenvalues)); - } - } - - std::string getOutput(bool header = false) const { - if (header) { - outStream.str(""); - for (size_t j = 0; j < block_size; ++j) - outStream << " trunc" << std::setw(2) << j; - } - std::string s = outStream.str(); - outStream.str(""); - return s; - } - - double computeEnergy(const VectorType &v) const { - return 0.0; // FIXME - // return ::computeEnergy(problem_.A, v, problem_.f) + problem_.phi(v); - } - - void projectCoarseCorrection(VectorType const &u, - typename Linearization::VectorType const &v, - VectorType &projected_v, - Linearization const &linearization) const { - projected_v = v; - for (size_t i = 0; i < v.size(); ++i) - for (size_t j = 0; j < block_size; ++j) - if (linearization.truncation[i][j]) - projected_v[i][j] = 0; - } - - double computeDampingParameter(VectorType const &u, - VectorType const &projected_v) const { - VectorType v = projected_v; - - double const vnorm = v.two_norm(); - if (vnorm <= 0) - return 1.0; - - v /= vnorm; // Rescale for numerical stability - - auto const psi = restrict(problem_.A, problem_.f, u, v, problem_.phi); - Dune::Solvers::Interval<double> D; - psi.subDiff(0, D); - if (D[1] > 0) // NOTE: Numerical instability can actually get us here - return 0; - - int bisectionsteps = 0; - Bisection const globalBisection; // NOTE: defaults - return globalBisection.minimize(psi, vnorm, 0.0, bisectionsteps) / vnorm; - } - - void assembleTruncate(VectorType const &u, Linearization &linearization, - Dune::BitSetVector<block_size> const &ignore) const { - // we can just copy the ignore information - linearization.ignore = ignore; - - // determine truncation pattern - linearization.truncation.resize(u.size()); - linearization.truncation.unsetAll(); - for (size_t i = 0; i < u.size(); ++i) { - if (problem_.phi.regularity(i, u[i]) > 1e8) { // TODO: Make customisable - linearization.truncation[i] = true; - continue; - } - - for (size_t j = 0; j < block_size; ++j) - if (linearization.ignore[i][j]) - linearization.truncation[i][j] = true; - } - - // construct sparsity pattern for linearization - Dune::MatrixIndexSet indices(problem_.A.N(), problem_.A.M()); - indices.import(problem_.A); - problem_.phi.addHessianIndices(indices); - - // construct matrix from pattern and initialize it - indices.exportIdx(linearization.A); - linearization.A = 0.0; - - // compute quadratic part of hessian (linearization.A += problem_.A) - for (size_t i = 0; i < problem_.A.N(); ++i) { - auto const end = std::end(problem_.A[i]); - for (auto it = std::begin(problem_.A[i]); it != end; ++it) - linearization.A[i][it.index()] += *it; - } - - // compute nonlinearity part of hessian - problem_.phi.addHessian(u, linearization.A); - - // compute quadratic part of gradient - linearization.b.resize(u.size()); - problem_.A.mv(u, linearization.b); - linearization.b -= problem_.f; - - // compute nonlinearity part of gradient - problem_.phi.addGradient(u, linearization.b); - - // -grad is needed for Newton step - linearization.b *= -1.0; - - // apply truncation to stiffness matrix and rhs - for (size_t row = 0; row < linearization.A.N(); ++row) { - auto const col_end = std::end(linearization.A[row]); - for (auto col_it = std::begin(linearization.A[row]); col_it != col_end; - ++col_it) { - size_t const col = col_it.index(); - for (size_t i = 0; i < col_it->N(); ++i) { - auto const blockEnd = std::end((*col_it)[i]); - for (auto blockIt = std::begin((*col_it)[i]); blockIt != blockEnd; - ++blockIt) - if (linearization.truncation[row][i] or - linearization.truncation[col][blockIt.index()]) - *blockIt = 0.0; - } - } - for (size_t j = 0; j < block_size; ++j) - if (linearization.truncation[row][j]) - linearization.b[row][j] = 0.0; - } - for (size_t j = 0; j < block_size; ++j) - outStream << std::setw(9) << linearization.truncation.countmasked(j); - } - - /** \brief Constructs and returns an iterate object */ - IterateObject getIterateObject() { - return IterateObject(localBisection, problem_, maxEigenvalues_); - } - -private: - std::vector<double> maxEigenvalues_; - - // problem data - using Base::problem_; - - Bisection const localBisection; - - mutable std::ostringstream outStream; -}; - -/** \brief Solves one local system using a scalar Gauss-Seidel method */ -template <class ConvexProblem> -class MyBlockProblem<ConvexProblem>::IterateObject { - friend class MyBlockProblem; - -protected: - /** \brief Constructor, protected so only friends can instantiate it - * \param bisection The class used to do a scalar bisection - * \param problem The problem including quadratic part and nonlinear part - */ - IterateObject(Bisection const &bisection, ConvexProblem const &problem, - std::vector<double> const &maxEigenvalues) - : problem(problem), - maxEigenvalues_(maxEigenvalues), - bisection_(bisection) {} - -public: - /** \brief Set the current iterate */ - void setIterate(VectorType &u) { - this->u = u; - return; - } - - /** \brief Update the i-th block of the current iterate */ - void updateIterate(LocalVectorType const &ui, size_t i) { - u[i] = ui; - return; - } - - /** \brief Minimise a local problem - * \param[out] ui The solution - * \param m Block number - * \param ignore Set of degrees of freedom to leave untouched - */ - void solveLocalProblem( - LocalVectorType &ui, size_t m, - typename Dune::BitSetVector<block_size>::const_reference ignore) { - { - LocalVectorType localb = problem.f[m]; - auto const end = std::end(problem.A[m]); - for (auto it = std::begin(problem.A[m]); it != end; ++it) { - size_t const j = it.index(); - Arithmetic::subtractProduct(localb, *it, u[j]); // also the diagonal! - } - Arithmetic::addProduct(localb, maxEigenvalues_[m], u[m]); - - // We minimise over an affine subspace - for (size_t j = 0; j < block_size; ++j) - if (ignore[j]) - localb[j] = 0; - else - ui[j] = 0; - - QuadraticEnergy< - typename ConvexProblem::NonlinearityType::LocalNonlinearity> - localJ(maxEigenvalues_[m], localb, problem.phi.restriction(m)); - minimise(localJ, ui, bisection_); - } - } - -private: - ConvexProblem const &problem; - std::vector<double> maxEigenvalues_; - Bisection const bisection_; - // state data for smoothing procedure used by: - // setIterate, updateIterate, solveLocalProblem - VectorType u; -}; -#endif diff --git a/dune/tectonic/problem-data/CMakeLists.txt b/dune/tectonic/problem-data/CMakeLists.txt new file mode 100644 index 00000000..8b975765 --- /dev/null +++ b/dune/tectonic/problem-data/CMakeLists.txt @@ -0,0 +1,22 @@ +add_subdirectory("grid") + +add_custom_target(tectonic_dune_problem-data SOURCES + bc.hh + gravity.hh + midpoint.hh + mybody.hh + myglobalfrictiondata.hh + patchfunction.hh + segmented-function.hh +) + +#install headers +install(FILES + bc.hh + gravity.hh + midpoint.hh + mybody.hh + myglobalfrictiondata.hh + patchfunction.hh + segmented-function.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/multi-body-problem-data/bc.hh b/dune/tectonic/problem-data/bc.hh similarity index 69% rename from src/multi-body-problem-data/bc.hh rename to dune/tectonic/problem-data/bc.hh index f9e167ac..2d478035 100644 --- a/src/multi-body-problem-data/bc.hh +++ b/dune/tectonic/problem-data/bc.hh @@ -7,14 +7,14 @@ class VelocityDirichletCondition : public Dune::VirtualFunction<double, double> { void evaluate(double const &relativeTime, double &y) const { // Assumed to vanish at time zero - double const finalVelocity = -5e-5; + double const finalVelocity = 5e-5; //std::cout << "VelocityDirichletCondition::evaluate()" << std::endl; - if (relativeTime <= 0.1) + /*if (relativeTime <= 0.1) std::cout << "- loading phase" << std::endl; else - std::cout << "- final velocity reached" << std::endl; + std::cout << "- final velocity reached" << std::endl;*/ y = (relativeTime <= 0.1) ? finalVelocity * (1.0 - std::cos(relativeTime * M_PI / 0.1)) / 2.0 @@ -23,6 +23,11 @@ class VelocityDirichletCondition }; class NeumannCondition : public Dune::VirtualFunction<double, double> { - void evaluate(double const &relativeTime, double &y) const { y = 0.0; } + public: + NeumannCondition(double c = 0.0) : c_(c) {} + void evaluate(double const &relativeTime, double &y) const { y = c_; } + + private: + double c_; }; #endif diff --git a/dune/tectonic/gravity.hh b/dune/tectonic/problem-data/gravity.hh similarity index 100% rename from dune/tectonic/gravity.hh rename to dune/tectonic/problem-data/gravity.hh diff --git a/dune/tectonic/problem-data/grid/CMakeLists.txt b/dune/tectonic/problem-data/grid/CMakeLists.txt new file mode 100644 index 00000000..e0fd59ba --- /dev/null +++ b/dune/tectonic/problem-data/grid/CMakeLists.txt @@ -0,0 +1,25 @@ +add_custom_target(tectonic_dune_problem-data_grid SOURCES + cube.hh + cube.cc + cubefaces.hh + cubefaces.cc + cubegridconstructor.hh + cuboidgeometry.hh + cuboidgeometry.cc + gridconstructor.hh + mygrids.hh + mygrids.cc + simplexmanager.hh + simplexmanager.cc +) + +#install headers +install(FILES + cube.hh + cubefaces.hh + cubegridconstructor.hh + cuboidgeometry.hh + gridconstructor.hh + mygrids.hh + simplexmanager.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/multi-body-problem-data/grid/cube.cc b/dune/tectonic/problem-data/grid/cube.cc similarity index 100% rename from src/multi-body-problem-data/grid/cube.cc rename to dune/tectonic/problem-data/grid/cube.cc diff --git a/src/multi-body-problem-data/grid/cube.hh b/dune/tectonic/problem-data/grid/cube.hh similarity index 100% rename from src/multi-body-problem-data/grid/cube.hh rename to dune/tectonic/problem-data/grid/cube.hh diff --git a/src/multi-body-problem-data/grid/cube_tmpl.cc b/dune/tectonic/problem-data/grid/cube_tmpl.cc similarity index 100% rename from src/multi-body-problem-data/grid/cube_tmpl.cc rename to dune/tectonic/problem-data/grid/cube_tmpl.cc diff --git a/src/multi-body-problem-data/grid/cubefaces.cc b/dune/tectonic/problem-data/grid/cubefaces.cc similarity index 100% rename from src/multi-body-problem-data/grid/cubefaces.cc rename to dune/tectonic/problem-data/grid/cubefaces.cc diff --git a/src/multi-body-problem-data/grid/cubefaces.hh b/dune/tectonic/problem-data/grid/cubefaces.hh similarity index 100% rename from src/multi-body-problem-data/grid/cubefaces.hh rename to dune/tectonic/problem-data/grid/cubefaces.hh diff --git a/src/multi-body-problem-data/grid/cubefaces_tmpl.cc b/dune/tectonic/problem-data/grid/cubefaces_tmpl.cc similarity index 100% rename from src/multi-body-problem-data/grid/cubefaces_tmpl.cc rename to dune/tectonic/problem-data/grid/cubefaces_tmpl.cc diff --git a/src/multi-body-problem-data/grid/cubegridconstructor.hh b/dune/tectonic/problem-data/grid/cubegridconstructor.hh similarity index 100% rename from src/multi-body-problem-data/grid/cubegridconstructor.hh rename to dune/tectonic/problem-data/grid/cubegridconstructor.hh diff --git a/src/multi-body-problem-data/grid/cuboidgeometry.cc b/dune/tectonic/problem-data/grid/cuboidgeometry.cc similarity index 94% rename from src/multi-body-problem-data/grid/cuboidgeometry.cc rename to dune/tectonic/problem-data/grid/cuboidgeometry.cc index 2fe7b2b5..3b86bc10 100644 --- a/src/multi-body-problem-data/grid/cuboidgeometry.cc +++ b/dune/tectonic/problem-data/grid/cuboidgeometry.cc @@ -16,9 +16,9 @@ template <class ctype> CuboidGeometry<ctype>::CuboidGeometry(const GlobalCoords& origin, const double length = 1.00, const double height = 0.27, const double depth = 0.60) : - length_(length*lengthScale), - height_(height*lengthScale), - depth_(depth*lengthScale), + length_(length*lengthScale()), + height_(height*lengthScale()), + depth_(depth*lengthScale()), lowerLeft_(origin), lowerRight_({origin[0]+length_, origin[1], 0}), upperRight_({origin[0]+length_, origin[1]+height_, 0}), @@ -29,8 +29,8 @@ CuboidGeometry<ctype>::CuboidGeometry(const GlobalCoords& origin, template <class ctype> CuboidGeometry<ctype>::CuboidGeometry(const GlobalCoords& origin, const double length, const double height) : - length_(length*lengthScale), - height_(height*lengthScale), + length_(length*lengthScale()), + height_(height*lengthScale()), lowerLeft_(origin), lowerRight_({origin[0]+length_, origin[1]}), upperRight_({origin[0]+length_, origin[1]+height_}), @@ -61,8 +61,8 @@ void CuboidGeometry<ctype>::addWeakeningPatch(const Dune::ParameterTree& parset, case Config::Rectangular: break; case Config::Trapezoidal: - weakPatch.vertices[1][0] += 0.05 * lengthScale; - weakPatch.vertices[3][0] -= 0.05 * lengthScale; + weakPatch.vertices[1][0] += 0.05 * lengthScale(); + weakPatch.vertices[3][0] -= 0.05 * lengthScale(); break; default: assert(false); diff --git a/src/multi-body-problem-data/grid/cuboidgeometry.hh b/dune/tectonic/problem-data/grid/cuboidgeometry.hh similarity index 95% rename from src/multi-body-problem-data/grid/cuboidgeometry.hh rename to dune/tectonic/problem-data/grid/cuboidgeometry.hh index 56998355..2b382ac1 100644 --- a/src/multi-body-problem-data/grid/cuboidgeometry.hh +++ b/dune/tectonic/problem-data/grid/cuboidgeometry.hh @@ -14,7 +14,9 @@ class CuboidGeometry { typedef Dune::FieldVector<ctype, MY_DIM> GlobalCoords; using WeakeningRegion = ConvexPolyhedron<GlobalCoords>; - constexpr static double const lengthScale = 1.0; // scaling factor + static constexpr double lengthScale() { + return 1.0; + } // scaling factor private: const ctype length_; diff --git a/src/multi-body-problem-data/grid/cuboidgeometry_tmpl.cc b/dune/tectonic/problem-data/grid/cuboidgeometry_tmpl.cc similarity index 100% rename from src/multi-body-problem-data/grid/cuboidgeometry_tmpl.cc rename to dune/tectonic/problem-data/grid/cuboidgeometry_tmpl.cc diff --git a/src/multi-body-problem-data/grid/gridconstructor.hh b/dune/tectonic/problem-data/grid/gridconstructor.hh similarity index 100% rename from src/multi-body-problem-data/grid/gridconstructor.hh rename to dune/tectonic/problem-data/grid/gridconstructor.hh diff --git a/src/multi-body-problem-data/grid/mygrids.cc b/dune/tectonic/problem-data/grid/mygrids.cc similarity index 97% rename from src/multi-body-problem-data/grid/mygrids.cc rename to dune/tectonic/problem-data/grid/mygrids.cc index 874f4c6e..e3179f2a 100644 --- a/src/multi-body-problem-data/grid/mygrids.cc +++ b/dune/tectonic/problem-data/grid/mygrids.cc @@ -115,11 +115,11 @@ bool MyFaces<GridView>::xyBoxed(Vector const &v1, Vector const &v2, auto const minmax0 = std::minmax(v1[0], v2[0]); auto const minmax1 = std::minmax(v1[1], v2[1]); - if (minmax0.first - 1e-14 * cuboidGeometry.lengthScale > x[0] or - x[0] > minmax0.second + 1e-14 * cuboidGeometry.lengthScale) + if (minmax0.first - 1e-14 * cuboidGeometry.lengthScale() > x[0] or + x[0] > minmax0.second + 1e-14 * cuboidGeometry.lengthScale()) return false; - if (minmax1.first - 1e-14 * cuboidGeometry.lengthScale > x[1] or - x[1] > minmax1.second + 1e-14 * cuboidGeometry.lengthScale) + if (minmax1.first - 1e-14 * cuboidGeometry.lengthScale() > x[1] or + x[1] > minmax1.second + 1e-14 * cuboidGeometry.lengthScale()) return false; return true; diff --git a/src/multi-body-problem-data/grid/mygrids.hh b/dune/tectonic/problem-data/grid/mygrids.hh similarity index 93% rename from src/multi-body-problem-data/grid/mygrids.hh rename to dune/tectonic/problem-data/grid/mygrids.hh index 574efa1d..62b440f5 100644 --- a/src/multi-body-problem-data/grid/mygrids.hh +++ b/dune/tectonic/problem-data/grid/mygrids.hh @@ -26,12 +26,12 @@ template <class GridView> struct MyFaces { const CuboidGeometry<typename GridView::ctype>& cuboidGeometry; bool isClose(double a, double b) { - return std::abs(a - b) < 1e-14 * cuboidGeometry.lengthScale; + return std::abs(a - b) < 1e-14 * cuboidGeometry.lengthScale(); } bool isClose2(double a, double b) { return std::abs(a - b) < - 1e-14 * cuboidGeometry.lengthScale * cuboidGeometry.lengthScale; + 1e-14 * cuboidGeometry.lengthScale() * cuboidGeometry.lengthScale(); } template <class Vector> diff --git a/src/multi-body-problem-data/grid/mygrids_tmpl.cc b/dune/tectonic/problem-data/grid/mygrids_tmpl.cc similarity index 100% rename from src/multi-body-problem-data/grid/mygrids_tmpl.cc rename to dune/tectonic/problem-data/grid/mygrids_tmpl.cc diff --git a/src/multi-body-problem-data/grid/simplexmanager.cc b/dune/tectonic/problem-data/grid/simplexmanager.cc similarity index 100% rename from src/multi-body-problem-data/grid/simplexmanager.cc rename to dune/tectonic/problem-data/grid/simplexmanager.cc diff --git a/src/multi-body-problem-data/grid/simplexmanager.hh b/dune/tectonic/problem-data/grid/simplexmanager.hh similarity index 100% rename from src/multi-body-problem-data/grid/simplexmanager.hh rename to dune/tectonic/problem-data/grid/simplexmanager.hh diff --git a/src/multi-body-problem-data/midpoint.hh b/dune/tectonic/problem-data/midpoint.hh similarity index 100% rename from src/multi-body-problem-data/midpoint.hh rename to dune/tectonic/problem-data/midpoint.hh diff --git a/src/multi-body-problem-data/mybody.hh b/dune/tectonic/problem-data/mybody.hh similarity index 65% rename from src/multi-body-problem-data/mybody.hh rename to dune/tectonic/problem-data/mybody.hh index c0160dde..e50e1793 100644 --- a/src/multi-body-problem-data/mybody.hh +++ b/dune/tectonic/problem-data/mybody.hh @@ -5,9 +5,8 @@ #include <dune/fufem/functions/constantfunction.hh> -#include <dune/tectonic/bodydata.hh> -#include <dune/tectonic/gravity.hh> - +#include "../data-structures/body/bodydata.hh" +#include "gravity.hh" #include "grid/cuboidgeometry.hh" #include "segmented-function.hh" @@ -16,21 +15,21 @@ template <int dimension> class MyBodyData : public BodyData<dimension> { using typename BodyData<dimension>::VectorField; public: - MyBodyData(Dune::ParameterTree const &parset, const Dune::FieldVector<double, dimension>& zenith) - : poissonRatio_(parset.get<double>("body.poissonRatio")), - youngModulus_(3.0 * parset.get<double>("body.bulkModulus") * + MyBodyData(Dune::ParameterTree const &parset, const double gravity, const Dune::FieldVector<double, dimension>& zenith) + : poissonRatio_(parset.get<double>("poissonRatio")), + youngModulus_(3.0 * parset.get<double>("bulkModulus") * (1.0 - 2.0 * poissonRatio_)), zenith_(zenith), shearViscosityField_( - parset.get<double>("body.elastic.shearViscosity"), - parset.get<double>("body.viscoelastic.shearViscosity")), + parset.get<double>("elastic.shearViscosity"), + parset.get<double>("viscoelastic.shearViscosity")), bulkViscosityField_( - parset.get<double>("body.elastic.bulkViscosity"), - parset.get<double>("body.viscoelastic.bulkViscosity")), - densityField_(parset.get<double>("body.elastic.density"), - parset.get<double>("body.viscoelastic.density")), + parset.get<double>("elastic.bulkViscosity"), + parset.get<double>("viscoelastic.bulkViscosity")), + densityField_(parset.get<double>("elastic.density"), + parset.get<double>("viscoelastic.density")), gravityField_(densityField_, zenith_, - parset.get<double>("gravity")) {} + gravity) {} double getPoissonRatio() const override { return poissonRatio_; } double getYoungModulus() const override { return youngModulus_; } diff --git a/src/multi-body-problem-data/myglobalfrictiondata.hh b/dune/tectonic/problem-data/myglobalfrictiondata.hh similarity index 95% rename from src/multi-body-problem-data/myglobalfrictiondata.hh rename to dune/tectonic/problem-data/myglobalfrictiondata.hh index 7666a467..f416f492 100644 --- a/src/multi-body-problem-data/myglobalfrictiondata.hh +++ b/dune/tectonic/problem-data/myglobalfrictiondata.hh @@ -3,7 +3,7 @@ #include <dune/common/function.hh> -#include <dune/tectonic/globalfrictiondata.hh> +#include "../data-structures/friction/globalfrictiondata.hh" #include "patchfunction.hh" diff --git a/src/multi-body-problem-data/patchfunction.hh b/dune/tectonic/problem-data/patchfunction.hh similarity index 100% rename from src/multi-body-problem-data/patchfunction.hh rename to dune/tectonic/problem-data/patchfunction.hh diff --git a/src/multi-body-problem-data/segmented-function.hh b/dune/tectonic/problem-data/segmented-function.hh similarity index 100% rename from src/multi-body-problem-data/segmented-function.hh rename to dune/tectonic/problem-data/segmented-function.hh diff --git a/dune/tectonic/quadraticenergy.hh b/dune/tectonic/quadraticenergy.hh deleted file mode 100644 index 9f3b8c9e..00000000 --- a/dune/tectonic/quadraticenergy.hh +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef DUNE_TECTONIC_QUADRATICENERGY_HH -#define DUNE_TECTONIC_QUADRATICENERGY_HH - -#include <memory> - -template <class NonlinearityTEMPLATE> class QuadraticEnergy { -public: - using Nonlinearity = NonlinearityTEMPLATE; - using LocalVector = typename Nonlinearity::VectorType; - - QuadraticEnergy(double alpha, LocalVector const &b, Nonlinearity const &phi) - : alpha(alpha), b(b), phi(phi) {} - - double const alpha; - LocalVector const &b; - Nonlinearity const φ -}; -#endif diff --git a/dune/tectonic/spatial-solving/CMakeLists.txt b/dune/tectonic/spatial-solving/CMakeLists.txt new file mode 100644 index 00000000..75fd6237 --- /dev/null +++ b/dune/tectonic/spatial-solving/CMakeLists.txt @@ -0,0 +1,15 @@ +add_subdirectory("tnnmg") +add_subdirectory("preconditioners") + +add_custom_target(tectonic_dune_spatial-solving SOURCES + fixedpointiterator.hh + fixedpointiterator.cc + solverfactory.hh + solverfactory.cc +) + +#install headers +install(FILES + fixedpointiterator.hh + solverfactory.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/spatial-solving/fixedpointiterator.cc b/dune/tectonic/spatial-solving/fixedpointiterator.cc similarity index 61% rename from src/spatial-solving/fixedpointiterator.cc rename to dune/tectonic/spatial-solving/fixedpointiterator.cc index 43df107c..298e2f94 100644 --- a/src/spatial-solving/fixedpointiterator.cc +++ b/dune/tectonic/spatial-solving/fixedpointiterator.cc @@ -25,7 +25,7 @@ #include "../data-structures/enums.hh" #include "../data-structures/enumparser.hh" -#include "fixedpointiterator.hh" + #include "../utils/tobool.hh" #include "../utils/debugutils.hh" @@ -38,7 +38,8 @@ #include "tnnmg/functional.hh" #include "tnnmg/zerononlinearity.hh" -#include "solverfactory.hh" + +#include "fixedpointiterator.hh" void FixedPointIterationCounter::operator+=( FixedPointIterationCounter const &other) { @@ -46,16 +47,16 @@ void FixedPointIterationCounter::operator+=( multigridIterations += other.multigridIterations; } -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> -FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::FixedPointIterator( +template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> +FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::FixedPointIterator( Dune::ParameterTree const &parset, - const ContactNetwork& contactNetwork, + const NBodyAssembler& nBodyAssembler, const IgnoreVector& ignoreNodes, GlobalFriction& globalFriction, const std::vector<const BitVector*>& bodywiseNonmortarBoundaries, const ErrorNorms& errorNorms) : parset_(parset), - contactNetwork_(contactNetwork), + nBodyAssembler_(nBodyAssembler), ignoreNodes_(ignoreNodes), globalFriction_(globalFriction), bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries), @@ -67,24 +68,23 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::FixedPointIte verbosity_(parset.get<Solver::VerbosityMode>("v.solver.verbosity")), errorNorms_(errorNorms) {} -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> +template <class LinearSolver> FixedPointIterationCounter -FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run( - Updaters updaters, +FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::run( + Updaters updaters, std::shared_ptr<LinearSolver>& linearSolver, const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs, std::vector<Vector>& velocityIterates) { - std::cout << "FixedPointIterator::run()" << std::endl; - - const auto& nBodyAssembler = contactNetwork_.nBodyAssembler(); + //std::cout << "FixedPointIterator::run()" << std::endl; // debugging - const auto& contactCouplings = nBodyAssembler.getContactCouplings(); + /*const auto& contactCouplings = nBodyAssembler_.getContactCouplings(); for (size_t i=0; i<contactCouplings.size(); i++) { print(*contactCouplings[i]->nonmortarBoundary().getVertices(), "nonmortarBoundaries:"); - } + }*/ - const auto nBodies = nBodyAssembler.nGrids(); + const auto nBodies = nBodyAssembler_.nGrids(); std::vector<const Matrix*> matrices_ptr(nBodies); for (int i=0; i<nBodies; i++) { @@ -93,17 +93,17 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run( // assemble full global contact problem Matrix bilinearForm; - nBodyAssembler.assembleJacobian(matrices_ptr, bilinearForm); + nBodyAssembler_.assembleJacobian(matrices_ptr, bilinearForm); - print(bilinearForm, "bilinearForm:"); + //print(bilinearForm, "bilinearForm:"); Vector totalRhs; - nBodyAssembler.assembleRightHandSide(velocityRHSs, totalRhs); + nBodyAssembler_.assembleRightHandSide(velocityRHSs, totalRhs); - print(totalRhs, "totalRhs:"); + //print(totalRhs, "totalRhs:"); // get lower and upper obstacles - const auto& totalObstacles = nBodyAssembler.totalObstacles_; + const auto& totalObstacles = nBodyAssembler_.totalObstacles_; Vector lower(totalObstacles.size()); Vector upper(totalObstacles.size()); @@ -117,159 +117,160 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run( } } - print(totalObstacles, "totalObstacles:"); + //print(totalObstacles, "totalObstacles:"); - print(lower, "lower obstacles:"); - print(upper, "upper obstacles:"); + //print(lower, "lower obstacles:"); + //print(upper, "upper obstacles:"); // compute velocity obstacles - Vector vLower, vUpper; + /*Vector vLower, vUpper; std::vector<Vector> u0, v0; updaters.rate_->extractOldVelocity(v0); updaters.rate_->extractOldDisplacement(u0); Vector totalu0, totalv0; - nBodyAssembler.concatenateVectors(u0, totalu0); - nBodyAssembler.concatenateVectors(v0, totalv0); + nBodyAssembler_.concatenateVectors(u0, totalu0); + nBodyAssembler_.concatenateVectors(v0, totalv0); updaters.rate_->velocityObstacles(totalu0, lower, totalv0, vLower); - updaters.rate_->velocityObstacles(totalu0, upper, totalv0, vUpper); - - print(vLower, "vLower obstacles:"); - print(vUpper, "vUpper obstacles:"); + updaters.rate_->velocityObstacles(totalu0, upper, totalv0, vUpper); */ - std::cout << "- Problem assembled: success" << std::endl; + //print(vLower, "vLower obstacles:"); + //print(vUpper, "vUpper obstacles:"); - using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, IgnoreVector>; - using TransferOperator = NBodyContactTransfer<ContactNetwork, Vector>; - using TransferOperators = std::vector<std::shared_ptr<TransferOperator>>; + //std::cout << "- Problem assembled: success" << std::endl; - TransferOperators transfer(contactNetwork_.nLevels()-1); - for (size_t i=0; i<transfer.size(); i++) { - transfer[i] = std::make_shared<TransferOperator>(); - transfer[i]->setup(contactNetwork_, i, i+1); - } - - // Remove any recompute filed so that initially the full transferoperator is assembled - for (size_t i=0; i<transfer.size(); i++) - std::dynamic_pointer_cast<TruncatedMGTransfer<Vector> >(transfer[i])->setRecomputeBitField(nullptr); - - auto smoother = TruncatedBlockGSStep<Matrix, Vector>{}; - auto linearMultigridStep = std::make_shared<Dune::Solvers::MultigridStep<Matrix, Vector> >(); - linearMultigridStep->setMGType(1, 3, 3); - linearMultigridStep->setSmoother(smoother); - linearMultigridStep->setTransferOperators(transfer); - - EnergyNorm<Matrix, Vector> mgNorm(*linearMultigridStep); - LinearSolver mgSolver(linearMultigridStep, parset_.get<size_t>("solver.tnnmg.linear.maximumIterations"), parset_.get<double>("solver.tnnmg.linear.tolerance"), mgNorm, Solver::QUIET); - - print(ignoreNodes_, "ignoreNodes:"); + //print(ignoreNodes_, "ignoreNodes:"); // set up functional and TNMMG solver - using ZeroSolverFactory = SolverFactory<Functional, IgnoreVector>; - Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), vLower, vUpper); - ZeroSolverFactory solverFactory(parset_.sub("solver.tnnmg"), J, mgSolver, ignoreNodes_); - /*Functional J(bilinearForm, totalRhs, globalFriction_, vLower, vUpper); - Factory solverFactory(parset_.sub("solver.tnnmg"), J, mgSolver, ignoreNodes_);*/ + //using ZeroSolverFactory = SolverFactory<Functional, IgnoreVector>; + //Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), vLower, vUpper); + //ZeroSolverFactory solverFactory(parset_.sub("solver.tnnmg"), J, mgSolver, ignoreNodes_); + Functional J(bilinearForm, totalRhs, globalFriction_, lower, upper); + Factory solverFactory(parset_.sub("solver.tnnmg"), J, ignoreNodes_); + solverFactory.build(linearSolver); + auto step = solverFactory.step(); - std::cout << "- Functional and TNNMG step setup: success" << std::endl; + //std::cout << "- Functional and TNNMG step setup: success" << std::endl; EnergyNorm<Matrix, Vector> energyNorm(bilinearForm); LoopSolver<Vector> velocityProblemSolver(*step.get(), velocityMaxIterations_, velocityTolerance_, energyNorm, - verbosity_, false); // absolute error + verbosity_); size_t fixedPointIteration; size_t multigridIterations = 0; std::vector<ScalarVector> alpha(nBodies); updaters.state_->extractAlpha(alpha); + + Vector totalVelocityIterate; + nBodyAssembler_.nodalToTransformed(velocityIterates, totalVelocityIterate); + + // project in onto admissible set + const size_t blocksize = Vector::block_type::dimension; + for (size_t i=0; i<totalVelocityIterate.size(); i++) { + for (size_t j=0; j<blocksize; j++) { + if (totalVelocityIterate[i][j] < lower[i][j]) { + totalVelocityIterate[i][j] = lower[i][j]; + } + + if (totalVelocityIterate[i][j] > upper[i][j]) { + totalVelocityIterate[i][j] = upper[i][j]; + } + } + } + + Vector old_v = totalVelocityIterate; + for (fixedPointIteration = 0; fixedPointIteration < fixedPointMaxIterations_; ++fixedPointIteration) { - print(alpha, "alpha:"); + //print(alpha, "alpha:"); // contribution from nonlinearity globalFriction_.updateAlpha(alpha); - Vector totalVelocityIterate; - nBodyAssembler.nodalToTransformed(velocityIterates, totalVelocityIterate); - //print(velocityIterates, "velocityIterates:"); //print(totalVelocityIterate, "totalVelocityIterate:"); - std::cout << "- FixedPointIteration iterate" << std::endl; + //std::cout << "- FixedPointIteration iterate" << std::endl; // solve a velocity problem solverFactory.setProblem(totalVelocityIterate); - std::cout << "- Velocity problem set" << std::endl; + //std::cout << "- Velocity problem set" << std::endl; velocityProblemSolver.preprocess(); - std::cout << "-- Preprocessed" << std::endl; + //std::cout << "-- Preprocessed" << std::endl; velocityProblemSolver.solve(); - std::cout << "-- Solved" << std::endl; + //std::cout << "-- Solved" << std::endl; const auto& tnnmgSol = step->getSol(); - std::cout << "FixPointIterator: Energy of TNNMG solution: " << J(tnnmgSol) << std::endl; + //std::cout << "FixPointIterator: Energy of TNNMG solution: " << J(tnnmgSol) << std::endl; - nBodyAssembler.postprocess(tnnmgSol, velocityIterates); - //nBodyAssembler.postprocess(totalVelocityIterate, velocityIterates); + nBodyAssembler_.postprocess(tnnmgSol, velocityIterates); + //nBodyAssembler_.postprocess(totalVelocityIterate, velocityIterates); - print(totalVelocityIterate, "totalVelocityIterate:"); - print(velocityIterates, "velocityIterates:"); + //print(totalVelocityIterate, "totalVelocityIterate:"); + //print(velocityIterates, "velocityIterates:"); //DUNE_THROW(Dune::Exception, "Just need to stop here!"); multigridIterations += velocityProblemSolver.getResult().iterations; - std::vector<Vector> v_m; - updaters.rate_->extractOldVelocity(v_m); - - for (size_t i=0; i<v_m.size(); i++) { - v_m[i] *= 1.0 - lambda_; - Dune::MatrixVector::addProduct(v_m[i], lambda_, velocityIterates[i]); - } + Vector v_m = old_v; + v_m *= 1.0 - lambda_; + Dune::MatrixVector::addProduct(v_m, lambda_, tnnmgSol); // extract relative velocities in mortar basis std::vector<Vector> v_rel; - relativeVelocities(tnnmgSol, v_rel); + relativeVelocities(v_m, v_rel); + + //print(v_m, "v_m: "); //print(v_rel, "v_rel"); - std::cout << "- State problem set" << std::endl; + //std::cout << "- State problem set" << std::endl; // solve a state problem updaters.state_->solve(v_rel); - std::cout << "-- Solved" << std::endl; + //std::cout << "-- Solved" << std::endl; std::vector<ScalarVector> newAlpha(nBodies); updaters.state_->extractAlpha(newAlpha); + //print(newAlpha, "new alpha:"); + bool breakCriterion = true; for (int i=0; i<nBodies; i++) { if (alpha[i].size()==0 || newAlpha[i].size()==0) continue; - print(alpha[i], "alpha i:"); - print(newAlpha[i], "new alpha i:"); + //print(alpha[i], "alpha i:"); + //print(newAlpha[i], "new alpha i:"); if (errorNorms_[i]->diff(alpha[i], newAlpha[i]) >= fixedPointTolerance_) { breakCriterion = false; - std::cout << "fixedPoint error: " << errorNorms_[i]->diff(alpha[i], newAlpha[i]) << std::endl; + //std::cout << "fixedPoint error: " << errorNorms_[i]->diff(alpha[i], newAlpha[i]) << std::endl; break; } } if (lambda_ < 1e-12 or breakCriterion) { - std::cout << "-FixedPointIteration finished! " << (lambda_ < 1e-12 ? "lambda" : "breakCriterion") << std::endl; + //std::cout << "-FixedPointIteration finished! " << (lambda_ < 1e-12 ? "lambda" : "breakCriterion") << std::endl; fixedPointIteration++; break; } alpha = newAlpha; } - std::cout << "-FixedPointIteration finished! " << std::endl; + //TODO: recently added, might be wrong or superfluous + globalFriction_.updateAlpha(alpha); + + //print(alpha, "alpha: "); + + //std::cout << "-FixedPointIteration finished! " << std::endl; if (fixedPointIteration == fixedPointMaxIterations_) DUNE_THROW(Dune::Exception, "FPI failed to converge"); @@ -284,19 +285,18 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run( return ret; } -std::ostream &operator<<(std::ostream &stream, +/*std::ostream &operator<<(std::ostream &stream, FixedPointIterationCounter const &fpic) { return stream << "(" << fpic.iterations << "," << fpic.multigridIterations << ")"; -} +}*/ -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> -void FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::relativeVelocities( +template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> +void FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::relativeVelocities( const Vector& v, std::vector<Vector>& v_rel) const { - const auto& nBodyAssembler = contactNetwork_.nBodyAssembler(); - const size_t nBodies = nBodyAssembler.nGrids(); + const size_t nBodies = nBodyAssembler_.nGrids(); // const auto& contactCouplings = nBodyAssembler.getContactCouplings(); size_t globalIdx = 0; @@ -345,5 +345,4 @@ void FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::relative }*/ } - #include "fixedpointiterator_tmpl.cc" diff --git a/src/spatial-solving/fixedpointiterator.hh b/dune/tectonic/spatial-solving/fixedpointiterator.hh similarity index 86% rename from src/spatial-solving/fixedpointiterator.hh rename to dune/tectonic/spatial-solving/fixedpointiterator.hh index c4839a79..ae0912ad 100644 --- a/src/spatial-solving/fixedpointiterator.hh +++ b/dune/tectonic/spatial-solving/fixedpointiterator.hh @@ -27,13 +27,13 @@ struct FixedPointIterationCounter { std::ostream &operator<<(std::ostream &stream, FixedPointIterationCounter const &fpic); -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> class FixedPointIterator { using ScalarVector = typename Updaters::StateUpdater::ScalarVector; using Vector = typename Factory::Vector; using Matrix = typename Factory::Matrix; - using Functional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, double>; //typename Factory::Functional; + using Functional = typename Factory::Functional; //Functional<Matrix&, Vector&, &, Vector&, Vector&, double>; //; using Nonlinearity = typename Factory::Functional::Nonlinearity; const static int dims = Vector::block_type::dimension; @@ -51,20 +51,22 @@ class FixedPointIterator { public: FixedPointIterator(const Dune::ParameterTree& parset, - const ContactNetwork& contactNetwork, + const NBodyAssembler& nBodyAssembler, const IgnoreVector& ignoreNodes, GlobalFriction& globalFriction, const std::vector<const BitVector*>& bodywiseNonmortarBoundaries, const ErrorNorms& errorNorms); + template <class LinearSolver> FixedPointIterationCounter run(Updaters updaters, + std::shared_ptr<LinearSolver>& linearSolver, const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs, std::vector<Vector>& velocityIterates); private: const Dune::ParameterTree& parset_; - const ContactNetwork& contactNetwork_; + const NBodyAssembler& nBodyAssembler_; const IgnoreVector& ignoreNodes_; GlobalFriction& globalFriction_; @@ -79,4 +81,5 @@ class FixedPointIterator { Solver::VerbosityMode verbosity_; const ErrorNorms& errorNorms_; }; + #endif diff --git a/dune/tectonic/spatial-solving/fixedpointiterator_tmpl.cc b/dune/tectonic/spatial-solving/fixedpointiterator_tmpl.cc new file mode 100644 index 00000000..bae2cc32 --- /dev/null +++ b/dune/tectonic/spatial-solving/fixedpointiterator_tmpl.cc @@ -0,0 +1,41 @@ +#ifndef MY_DIM +#error MY_DIM unset +#endif + +#include "../explicitgrid.hh" +#include "../explicitvectors.hh" + +#include <dune/solvers/norms/energynorm.hh> +#include <dune/solvers/solvers/loopsolver.hh> + +#include "../spatial-solving/solverfactory.hh" +#include "../data-structures/network/contactnetwork.hh" +#include "../data-structures/friction/globalfriction.hh" + +#include "tnnmg/functional.hh" + +#include "../time-stepping/rate/rateupdater.hh" +#include "../time-stepping/state/stateupdater.hh" +#include "../time-stepping/updaters.hh" + +using MyContactNetwork = ContactNetwork<Grid, Vector>; + +using BoundaryNodes = typename MyContactNetwork::BoundaryNodes; +using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions; + +using MyStateUpdater = StateUpdater<ScalarVector, Vector>; +using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>; +using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>; + +using LinearSolver = Dune::Solvers::LoopSolver<Vector>; +using ErrorNorms = typename MyContactNetwork::StateEnergyNorms; +using NBodyAssembler = typename MyContactNetwork::NBodyAssembler; + +using MyGlobalFriction = GlobalFriction<Matrix, Vector>; +using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>; +using MySolverFactory = SolverFactory<MyFunctional, BitVector>; + +template class FixedPointIterator<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>; + +template FixedPointIterationCounter FixedPointIterator<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>::run<LinearSolver>( + MyUpdaters, std::shared_ptr<LinearSolver>&, const std::vector<Matrix>&, const std::vector<Vector>&, std::vector<Vector>&); diff --git a/dune/tectonic/spatial-solving/preconditioners/CMakeLists.txt b/dune/tectonic/spatial-solving/preconditioners/CMakeLists.txt new file mode 100644 index 00000000..bcff7b9f --- /dev/null +++ b/dune/tectonic/spatial-solving/preconditioners/CMakeLists.txt @@ -0,0 +1,19 @@ +add_custom_target(tectonic_dune_spatial-solving_preconditioners SOURCES + hierarchicleveliterator.hh + levelpatchpreconditioner.hh + patchproblem.hh + multilevelpatchpreconditioner.hh + nbodycontacttransfer.hh + nbodycontacttransfer.cc + supportpatchfactory.hh +) + +#install headers +install(FILES + hierarchicleveliterator.hh + levelpatchpreconditioner.hh + patchproblem.hh + multilevelpatchpreconditioner.hh + nbodycontacttransfer.hh + supportpatchfactory.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/spatial-solving/preconditioners/hierarchicleveliterator.hh b/dune/tectonic/spatial-solving/preconditioners/hierarchicleveliterator.hh similarity index 100% rename from src/spatial-solving/preconditioners/hierarchicleveliterator.hh rename to dune/tectonic/spatial-solving/preconditioners/hierarchicleveliterator.hh diff --git a/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh b/dune/tectonic/spatial-solving/preconditioners/levelpatchpreconditioner.hh similarity index 72% rename from src/spatial-solving/preconditioners/levelpatchpreconditioner.hh rename to dune/tectonic/spatial-solving/preconditioners/levelpatchpreconditioner.hh index a515f6e5..5ac982f6 100644 --- a/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh +++ b/dune/tectonic/spatial-solving/preconditioners/levelpatchpreconditioner.hh @@ -10,8 +10,9 @@ #include <dune/solvers/iterationsteps/lineariterationstep.hh> #include <dune/solvers/common/numproc.hh> -#include "../../data-structures/levelcontactnetwork.hh" +#include "../../data-structures/network/levelcontactnetwork.hh" +#include "patchproblem.hh" #include "supportpatchfactory.hh" #include <dune/localfunctions/lagrange/pqkfactory.hh> @@ -49,6 +50,7 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy using PatchFactory = SupportPatchFactory<LevelContactNetwork>; using Patch = typename PatchFactory::Patch; + using PatchProblem = PatchProblem<MatrixType, VectorType>; const MPPMode mode_; @@ -59,7 +61,7 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy PatchFactory patchFactory_; std::vector<Patch> patches_; - + std::vector<std::unique_ptr<PatchProblem>> patchProblems_; std::shared_ptr<PatchSolver> patchSolver_; size_t patchDepth_; @@ -113,7 +115,7 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy for (const auto& e : elements(gridView)) { const auto& refElement = Dune::ReferenceElements<double, dim>::general(e.type()); - for (size_t i=0; i<refElement.size(dim); i++) { + for (int i=0; i<refElement.size(dim); i++) { auto globalIdx = levelIndices.vertexIndex(bodyIdx, e, i); if (!vertexVisited[globalIdx][0]) { @@ -148,7 +150,18 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy this->verbosity_ = verbosity; } - virtual void iterate() { + void setMatrix(const MatrixType& mat) override { + Base::setMatrix(mat); + + patchProblems_.resize(patches_.size()); + for (size_t i=0; i<patches_.size(); i++) { + patchProblems_[i] = std::make_unique<PatchProblem>(mat, patches_[i]); + } + + //std::cout << "matrix set!" << std::endl; + } + + void iterate() override { if (mode_ == additive) iterateAdd(); else @@ -159,9 +172,20 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy *(this->x_) = 0; VectorType x = *(this->x_); - for (const auto& p : patches_) { + Dune::Timer timer; + timer.start(); + + size_t systemSize = 0; + size_t count = 0; + + //std::cout << "level::iterate() ... patches: " << patches_.size() << " level size: " << x.size() << std::endl; + + for (size_t i=0; i<patches_.size(); i++) { x = 0; + /* + const auto& p = patches_[i]; + auto ignore = this->ignore(); for (size_t i=0; i<ignore.size(); i++) { for (size_t d=0; d<dim; d++) { @@ -172,14 +196,46 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy auto& step = patchSolver_->getIterationStep(); dynamic_cast<LinearIterationStep<MatrixType, VectorType>&>(step).setProblem(*this->mat_, x, *this->rhs_); + step.setIgnore(ignore);*/ + + const auto& patchMat = patchProblems_[i]->mat(); + + patchProblems_[i]->setRhs(*this->rhs_); + const auto& patchRhs = patchProblems_[i]->rhs(); + + VectorType patchX(patchMat.M()); + patchX = 0; + + auto& step = patchSolver_->getIterationStep(); + dynamic_cast<LinearIterationStep<MatrixType, VectorType>&>(step).setProblem(patchMat, patchX, patchRhs); + + // empty ignore + Dune::Solvers::DefaultBitVector_t<VectorType> ignore(patchX.size()); + ignore.unsetAll(); step.setIgnore(ignore); patchSolver_->check(); patchSolver_->preprocess(); patchSolver_->solve(); + patchProblems_[i]->prolong(patchX, x); + *(this->x_) += x; + + /*if (count*1.0/patches_.size() >= 0.1) { + std::cout << (int) (i*1.0/patches_.size()*100) << " %. Elapsed time: " << timer.elapsed() << std::endl; + count = 0; + } + count++; + systemSize += patchX.size();*/ } + + /* timer.stop(); + + std::cout << "Total elapsed time: " << timer.elapsed() << std::endl; + std::cout << "Average time per patch: " << timer.elapsed()*1.0/patches_.size() << std::endl; + std::cout << "Average patch size: " << systemSize*1.0/patches_.size() << std::endl; + std::cout << "-------------------------------" << std::endl << std::endl;*/ } void iterateMult() { diff --git a/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh b/dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh similarity index 86% rename from src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh rename to dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh index b187da53..88de3c32 100644 --- a/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh +++ b/dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh @@ -10,25 +10,22 @@ #include <dune/solvers/norms/energynorm.hh> #include <dune/solvers/solvers/loopsolver.hh> -#include <dune/solvers/solvers/umfpacksolver.hh> #include <dune/solvers/iterationsteps/blockgssteps.hh> -//#include <dune/solvers/iterationsteps/blockgsstep.hh> #include <dune/solvers/iterationsteps/cgstep.hh> #include <dune/solvers/iterationsteps/lineariterationstep.hh> #include <dune/solvers/iterationsteps/truncatedblockgsstep.hh> #include "nbodycontacttransfer.hh" #include "levelpatchpreconditioner.hh" -#include "localproblem.hh" template <class ContactNetwork, class MatrixType, class VectorType> class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorType> { private: using Base = LinearIterationStep<MatrixType, VectorType>; - using PatchSolver = LoopSolver<Vector, BitVector>; + using PatchSolver = LoopSolver<VectorType>; using PatchSolverStep = TruncatedBlockGSStep<MatrixType, VectorType>; - using CoarseSolver = Dune::Solvers::UMFPackSolver<MatrixType, VectorType>; + using Norm = EnergyNorm<MatrixType, VectorType>; using LevelContactNetwork = typename ContactNetwork::LevelContactNetwork; using LevelPatchPreconditioner = LevelPatchPreconditioner<LevelContactNetwork, PatchSolver, MatrixType, VectorType>; @@ -54,7 +51,6 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec std::vector<std::shared_ptr<EnergyNorm<MatrixType, VectorType>>> levelErrorNorms_; std::vector<std::shared_ptr<LinearIterationStep<MatrixType, VectorType>>> levelItSteps_; std::vector<std::shared_ptr<PatchSolver>> levelSolvers_; - CoarseSolver coarseSolver_; //std::vector<BitVector> recompute_; std::vector<std::shared_ptr<MGTransfer>> mgTransfer_; @@ -100,15 +96,23 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec levelItSteps_.resize(size()); levelErrorNorms_.resize(size()); + // set basesolver + levelItSteps_[0] = std::make_shared<PatchSolverStep>(); + levelErrorNorms_[0] = std::make_shared<Norm>(*levelItSteps_[0].get()); + levelSolvers_[0] = std::make_shared<PatchSolver>(*levelItSteps_[0].get(), + parset.get<size_t>("basesolver.maximumIterations"), + parset.get<double>("basesolver.tolerance"), + *levelErrorNorms_[0].get(), + parset.get<Solver::VerbosityMode>("basesolver.verbosity")); + for (size_t i=1; i<levelSolvers_.size(); i++) { - //auto gsStep = Dune::Solvers::BlockGSStepFactory<MatrixType, VectorType>::create(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0)); - levelItSteps_[i] = std::make_shared<TruncatedBlockGSStep<MatrixType, VectorType>>(); //Dune::Solvers::BlockGSStepFactory<MatrixType, VectorType>::createPtr(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0)); - levelErrorNorms_[i] = std::make_shared<EnergyNorm<MatrixType, VectorType>>(*levelItSteps_[i].get()); + levelItSteps_[i] = std::make_shared<PatchSolverStep>(); + levelErrorNorms_[i] = std::make_shared<Norm>(*levelItSteps_[i].get()); levelSolvers_[i] = std::make_shared<PatchSolver>(*levelItSteps_[i].get(), - parset.get<size_t>("maximumIterations"), - parset.get<double>("tolerance"), + parset.get<size_t>("patchsolver.maximumIterations"), + parset.get<double>("patchsolver.tolerance"), *levelErrorNorms_[i].get(), - parset.get<Solver::VerbosityMode>("verbosity")); + parset.get<Solver::VerbosityMode>("patchsolver.verbosity")); levelPatchPreconditioners_[i]->setPatchSolver(levelSolvers_[i]); } @@ -171,7 +175,9 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec Dune::MatrixVector::resize(levelX_[0], levelMat_[0]); } - void iterate() { + void iterate() override { + //std::cout << "multi::iterate()" << std::endl; + size_t maxLevel = levelPatchPreconditioners_.size()-1; levelX_[maxLevel] = *this->getIterate(); levelRhs_[maxLevel] = *Base::rhs_; @@ -201,13 +207,21 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec VectorType x; // solve coarse global problem - LocalProblem<MatrixType, VectorType> localProblem(levelMat_[0], levelRhs_[0], ignoreHierarchy_[0]); - Vector newR; + /*LocalProblem<MatrixType, VectorType> localProblem(levelMat_[0], levelRhs_[0], ignoreHierarchy_[0]); + VectorType newR; localProblem.getLocalRhs(levelX_[0], newR); coarseSolver_.setProblem(localProblem.getMat(), levelX_[0], newR); coarseSolver_.preprocess(); - coarseSolver_.solve(); + coarseSolver_.solve(); */ + + auto& step = levelSolvers_[0]->getIterationStep(); + dynamic_cast<LinearIterationStep<MatrixType, VectorType>&>(step).setProblem(levelMat_[0], levelX_[0], levelRhs_[0]); + step.setIgnore(ignoreHierarchy_[0]); + + levelSolvers_[0]->check(); + levelSolvers_[0]->preprocess(); + levelSolvers_[0]->solve(); mgTransfer_[0]->prolong(levelX_[0], x); diff --git a/src/spatial-solving/preconditioners/nbodycontacttransfer.cc b/dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.cc similarity index 97% rename from src/spatial-solving/preconditioners/nbodycontacttransfer.cc rename to dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.cc index 1bb9ce37..347e2a22 100644 --- a/src/spatial-solving/preconditioners/nbodycontacttransfer.cc +++ b/dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.cc @@ -12,7 +12,7 @@ #include <dune/solvers/transferoperators/densemultigridtransfer.hh> template<class ContactNetwork, class VectorType> -void NBodyContactTransfer<ContactNetwork, VectorType>::setup(const ContactNetwork& contactNetwork, const int coarseLevel, const int fineLevel) { +void NBodyContactTransfer<ContactNetwork, VectorType>::setup(const ContactNetwork& contactNetwork, const size_t coarseLevel, const size_t fineLevel) { const size_t nBodies = contactNetwork.nBodies(); const size_t nCouplings = contactNetwork.nCouplings(); @@ -75,11 +75,11 @@ void NBodyContactTransfer<ContactNetwork, VectorType>::setup(const ContactNetwor const auto& nBodyAssembler = contactNetwork.nBodyAssembler(); const auto& contactCouplings = nBodyAssembler.getContactCouplings(); - std::vector<const MatrixType*> mortarTransferOperators(nBodyAssembler.nCouplings()); - std::vector<const Dune::BitSetVector<1>*> fineHasObstacle(nBodyAssembler.nCouplings()); - std::vector<std::array<int,2> > gridIdx(nBodyAssembler.nCouplings()); + std::vector<const MatrixType*> mortarTransferOperators(nCouplings); + std::vector<const Dune::BitSetVector<1>*> fineHasObstacle(nCouplings); + std::vector<std::array<int,2> > gridIdx(nCouplings); - for (size_t i=0; i<nBodyAssembler.nCouplings(); i++) { + for (size_t i=0; i<nCouplings; i++) { mortarTransferOperators[i] = &contactCouplings[i]->mortarLagrangeMatrix(); fineHasObstacle[i] = contactCouplings[i]->nonmortarBoundary().getVertices(); gridIdx[i] = nBodyAssembler.getCoupling(i).gridIdx_; diff --git a/src/spatial-solving/preconditioners/nbodycontacttransfer.hh b/dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.hh similarity index 97% rename from src/spatial-solving/preconditioners/nbodycontacttransfer.hh rename to dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.hh index 61d4e7c0..855851e2 100644 --- a/src/spatial-solving/preconditioners/nbodycontacttransfer.hh +++ b/dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.hh @@ -58,7 +58,7 @@ class NBodyContactTransfer : public TruncatedDenseMGTransfer<VectorType> { * \param fineHasObstacle Bitfields determining for each coupling which fine grid nodes belong to the nonmortar boundary. * \param gridIdx For each coupling store the indices of the nonmortar and mortar grid. */ - void setup(const ContactNetwork& contactNetwork, const int coarseLevel, const int fineLevel); + void setup(const ContactNetwork& contactNetwork, const size_t coarseLevel, const size_t fineLevel); protected: diff --git a/dune/tectonic/spatial-solving/preconditioners/patchproblem.hh b/dune/tectonic/spatial-solving/preconditioners/patchproblem.hh new file mode 100644 index 00000000..321a96f3 --- /dev/null +++ b/dune/tectonic/spatial-solving/preconditioners/patchproblem.hh @@ -0,0 +1,115 @@ +#ifndef SRC_SPATIAL_SOLVING_PRECONDITIONERS_PATCH_PROBLEM_HH +#define SRC_SPATIAL_SOLVING_PRECONDITIONERS_PATCH_PROBLEM_HH + +#include <math.h> +#include <dune/common/fmatrix.hh> +#include <dune/common/function.hh> +#include <dune/common/timer.hh> + +#include <dune/istl/matrixindexset.hh> +//#include <dune/istl/superlu.hh> +#include <dune/istl/umfpack.hh> + +#include <dune/fufem/assemblers/localoperatorassembler.hh> + +#include "../../utils/debugutils.hh" + +template <class MatrixType, class DomainType, class RangeType = DomainType> +class PatchProblem { + +private: + const static size_t dim = DomainType::block_type::dimension; + + using BitVector = Dune::BitSetVector<dim>; + + const MatrixType& mat_; + + std::vector<size_t> localToGlobal_; + + MatrixType localMat_; + RangeType localRhs_; + + +public: + PatchProblem(const MatrixType& mat, const Dune::BitSetVector<1>& patch) : + mat_(mat) { + + // construct localToGlobal map + localToGlobal_.clear(); + for (size_t i=0; i<patch.size(); ++i) { + if (!patch[i][0]) { + localToGlobal_.push_back(i); + } + } + + // build local matrix + auto localDim = localToGlobal_.size(); + Dune::MatrixIndexSet localIdxSet(localDim, localDim); + + for(size_t rowIdx=0; rowIdx<localDim; rowIdx++) { + const auto globalRowIdx = localToGlobal_[rowIdx]; + const auto& row = mat_[globalRowIdx]; + + const auto cEndIt = row.end(); + for(auto cIt=row.begin(); cIt!=cEndIt; ++cIt) { + const auto globalColIdx = cIt.index(); + + auto localColIdx = std::find(localToGlobal_.begin(), localToGlobal_.end(), globalColIdx); + if (localColIdx!=localToGlobal_.end()) { + localIdxSet.add(rowIdx, localColIdx-localToGlobal_.begin()); + } + } + } + + localIdxSet.exportIdx(localMat_); + + for(size_t rowIdx=0; rowIdx<localMat_.N(); rowIdx++) { + auto& row = localMat_[rowIdx]; + const auto& globalRow = mat_[localToGlobal_[rowIdx]]; + + + const auto cEndIt = row.end(); + for(auto cIt=row.begin(); cIt!=cEndIt; ++cIt) { + row[cIt.index()] = globalRow[localToGlobal_[cIt.index()]]; + } + } + + // init local rhs + localRhs_.resize(localDim); + localRhs_ = 0; + } + + const MatrixType& mat() { + return localMat_; + } + + const RangeType& rhs() { + return localRhs_; + } + + void setRhs(const RangeType& rhs){ + for (size_t i=0; i<localRhs_.size(); i++) { + localRhs_[i] = rhs[localToGlobal_[i]]; + } + } + + void prolong(const DomainType& x, DomainType& res){ + res.resize(mat_.N()); + res = 0; + + for (size_t i=0; i<x.size(); i++) { + res[localToGlobal_[i]] = x[i]; + } + } + + void restrict(const RangeType& x, RangeType& res){ + res.resize(localToGlobal_.size()); + res = 0; + + for (size_t i=0; i<res.size(); i++) { + res[i] = x[localToGlobal_[i]]; + } + } +}; + +#endif diff --git a/src/spatial-solving/preconditioners/supportpatchfactory.hh b/dune/tectonic/spatial-solving/preconditioners/supportpatchfactory.hh similarity index 98% rename from src/spatial-solving/preconditioners/supportpatchfactory.hh rename to dune/tectonic/spatial-solving/preconditioners/supportpatchfactory.hh index 3dbc81d5..06c478cf 100644 --- a/src/spatial-solving/preconditioners/supportpatchfactory.hh +++ b/dune/tectonic/spatial-solving/preconditioners/supportpatchfactory.hh @@ -105,7 +105,7 @@ class SupportPatchFactory static const int dim = LevelContactNetwork::dim; //TODO using ctype = typename LevelContactNetwork::ctype; - using Patch = Dune::BitSetVector<dim>; + using Patch = Dune::BitSetVector<1>; private: using Element = typename LevelContactNetwork::GridView::template Codim<0>::Entity; @@ -216,7 +216,6 @@ class SupportPatchFactory //std::cout << "elemID: " << coarseIndices_.elementIndex(i, e) << std::endl; //std::cout << "vertexIDs: "; const int dimElement = Element::dimension; - const auto& refElement = Dune::ReferenceElements<double, dimElement>::general(e.type()); /*for (int j=0; j<refElement.size(dim); j++) { std::cout << coarseIndices_.vertexIndex(i, e, j) << " "; @@ -423,8 +422,6 @@ class SupportPatchFactory for (size_t i=0; i<patchElements.size(); ++i) { const auto& coarseElem = patchElements[i]; - size_t elemIdx = coarseIndices_.elementIndex(coarseElem.bodyID, coarseElem.element); - const auto& grid = coarseContactNetwork_.body(coarseElem.bodyID)->gridView().grid(); const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID)->level(); @@ -545,7 +542,7 @@ class SupportPatchFactory } } - auto coarseFather(const Element& fineElem, const size_t coarseLevel) const { + auto coarseFather(const Element& fineElem, const int coarseLevel) const { Element coarseElem = fineElem; while (coarseElem.level() > coarseLevel) { coarseElem = coarseElem.father(); diff --git a/dune/tectonic/spatial-solving/solverfactory.cc b/dune/tectonic/spatial-solving/solverfactory.cc new file mode 100644 index 00000000..004253db --- /dev/null +++ b/dune/tectonic/spatial-solving/solverfactory.cc @@ -0,0 +1,46 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <dune/solvers/common/wrapownshare.hh> +#include <dune/solvers/iterationsteps/blockgssteps.hh> +#include <dune/solvers/solvers/umfpacksolver.hh> + +#include "solverfactory.hh" + +#include "../utils/debugutils.hh" + +template <class Functional, class BitVector> +SolverFactory<Functional, BitVector>::SolverFactory( + const Dune::ParameterTree& parset, + Functional& J, + const BitVector& ignoreNodes) : + parset_(parset), + J_(Dune::Solvers::wrap_own_share<const Functional>(std::forward<Functional>(J))), + ignoreNodes_(ignoreNodes) +{} + +template <class Functional, class BitVector> +template <class LinearSolver> +void SolverFactory<Functional, BitVector>::build(std::shared_ptr<LinearSolver>& linearSolver) { + nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, LocalSolver()); + + tnnmgStep_ = std::make_shared<Step>(*J_, dummyIterate_, nonlinearSmoother_, linearSolver, DefectProjection(), LineSearchSolver()); + tnnmgStep_->setPreSmoothingSteps(parset_.get<int>("main.pre")); + tnnmgStep_->setIgnore(ignoreNodes_); +} + +template <class Functional, class BitVector> +void SolverFactory<Functional, BitVector>::setProblem(Vector& x) { + nonlinearSmoother_->setProblem(x); + tnnmgStep_->setProblem(x); +} + + +template <class Functional, class BitVector> +auto SolverFactory<Functional, BitVector>::step() +-> std::shared_ptr<Step> { + return tnnmgStep_; +} + +#include "solverfactory_ex.cc" diff --git a/src/spatial-solving/solverfactory.hh b/dune/tectonic/spatial-solving/solverfactory.hh similarity index 69% rename from src/spatial-solving/solverfactory.hh rename to dune/tectonic/spatial-solving/solverfactory.hh index 703d0f9a..a93b65d8 100644 --- a/src/spatial-solving/solverfactory.hh +++ b/dune/tectonic/spatial-solving/solverfactory.hh @@ -15,12 +15,11 @@ #include <dune/tnnmg/projections/obstacledefectprojection.hh> #include <dune/tnnmg/localsolvers/scalarobstaclesolver.hh> -//#include "tnnmg/tnnmgstep.hh" #include "tnnmg/linearization.hh" #include "tnnmg/linesearchsolver.hh" #include "tnnmg/localbisectionsolver.hh" -template <class FunctionalTEMPLATE, class BitVectorType, class ContactNetwork> +template <class FunctionalTEMPLATE, class BitVectorType> class SolverFactory { public: using Functional = FunctionalTEMPLATE; @@ -28,28 +27,30 @@ class SolverFactory { using Vector = typename Functional::Vector; using BitVector = BitVectorType; - using LocalSolver = LocalBisectionSolver; //Dune::TNNMG::ScalarObstacleSolver;//LocalBisectionSolver; - using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, LocalBisectionSolver, BitVector>; //Dune::TNNMG::NonlinearGSStep<Functional, Dune::TNNMG::GaussSeidelLocalSolver<LocalSolver>, BitVector>; + using LocalSolver = LocalBisectionSolver; + using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, LocalBisectionSolver, BitVector>; using Linearization = Linearization<Functional, BitVector>; using DefectProjection = typename Dune::TNNMG::ObstacleDefectProjection; - using Step = Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver, ContactNetwork>; - //using Step = Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, Dune::TNNMG::ScalarObstacleSolver>; + using Step = Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver>; - template <class LinearSolver> SolverFactory(const Dune::ParameterTree&, Functional&, - LinearSolver&&, - const BitVector&, - const ContactNetwork&); + const BitVector&); + + template <class LinearSolver> + void build(std::shared_ptr<LinearSolver>& linearSolver); void setProblem(Vector& x); auto step() -> std::shared_ptr<Step>; private: + const Dune::ParameterTree& parset_; + Vector dummyIterate_; std::shared_ptr<const Functional> J_; + const BitVector& ignoreNodes_; // nonlinear smoother std::shared_ptr<NonlinearSmoother> nonlinearSmoother_; @@ -58,6 +59,4 @@ class SolverFactory { std::shared_ptr<Step> tnnmgStep_; }; -#include "solverfactory.cc" - #endif diff --git a/dune/tectonic/spatial-solving/solverfactory_ex.cc b/dune/tectonic/spatial-solving/solverfactory_ex.cc new file mode 100644 index 00000000..73811d05 --- /dev/null +++ b/dune/tectonic/spatial-solving/solverfactory_ex.cc @@ -0,0 +1,17 @@ +#ifndef MY_DIM +#error MY_DIM unset +#endif + +#include <dune/solvers/solvers/loopsolver.hh> + +#include "solverfactory_tmpl.cc" + +using MyLinearSolver = Dune::Solvers::LoopSolver<Vector, BitVector>; + +template class SolverFactory<MyFunctional, BitVector>; +template void SolverFactory<MyFunctional, BitVector>::build<MyLinearSolver>(std::shared_ptr<MyLinearSolver>&); + +template class SolverFactory<MyZeroFunctional, BitVector>; +template void SolverFactory<MyZeroFunctional, BitVector>::build<MyLinearSolver>(std::shared_ptr<MyLinearSolver>&); + + diff --git a/dune/tectonic/spatial-solving/solverfactory_tmpl.cc b/dune/tectonic/spatial-solving/solverfactory_tmpl.cc new file mode 100644 index 00000000..d86fa485 --- /dev/null +++ b/dune/tectonic/spatial-solving/solverfactory_tmpl.cc @@ -0,0 +1,21 @@ +#ifndef MY_DIM +#error MY_DIM unset +#endif + +#include "../explicitgrid.hh" +#include "../explicitvectors.hh" + +#include "../data-structures/friction/globalfriction.hh" +#include "tnnmg/functional.hh" +#include "tnnmg/zerononlinearity.hh" + +#include "solverfactory.hh" + +using MyLinearSolver = Dune::Solvers::LoopSolver<Vector, BitVector>; +using MyGlobalFriction = GlobalFriction<Matrix, Vector>; + +using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>; +using MySolverFactory = SolverFactory<MyFunctional, BitVector>; + +using MyZeroFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, double>; +using MyZeroSolverFactory = SolverFactory<MyZeroFunctional, BitVector>; diff --git a/dune/tectonic/spatial-solving/tnnmg/CMakeLists.txt b/dune/tectonic/spatial-solving/tnnmg/CMakeLists.txt new file mode 100644 index 00000000..ee2910cf --- /dev/null +++ b/dune/tectonic/spatial-solving/tnnmg/CMakeLists.txt @@ -0,0 +1,18 @@ +add_custom_target(tectonic_dune_spatial-solving_tnnmg SOURCES + functional.hh + linearcorrection.hh + linearization.hh + linesearchsolver.hh + localbisectionsolver.hh + zerononlinearity.hh +) + +#install headers +install(FILES + functional.hh + linearcorrection.hh + linearization.hh + linesearchsolver.hh + localbisectionsolver.hh + zerononlinearity.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/spatial-solving/tnnmg/functional.hh b/dune/tectonic/spatial-solving/tnnmg/functional.hh similarity index 100% rename from src/spatial-solving/tnnmg/functional.hh rename to dune/tectonic/spatial-solving/tnnmg/functional.hh diff --git a/src/spatial-solving/tnnmg/linearcorrection.hh b/dune/tectonic/spatial-solving/tnnmg/linearcorrection.hh similarity index 100% rename from src/spatial-solving/tnnmg/linearcorrection.hh rename to dune/tectonic/spatial-solving/tnnmg/linearcorrection.hh diff --git a/src/spatial-solving/tnnmg/linearization.hh b/dune/tectonic/spatial-solving/tnnmg/linearization.hh similarity index 100% rename from src/spatial-solving/tnnmg/linearization.hh rename to dune/tectonic/spatial-solving/tnnmg/linearization.hh diff --git a/src/spatial-solving/tnnmg/linesearchsolver.hh b/dune/tectonic/spatial-solving/tnnmg/linesearchsolver.hh similarity index 100% rename from src/spatial-solving/tnnmg/linesearchsolver.hh rename to dune/tectonic/spatial-solving/tnnmg/linesearchsolver.hh diff --git a/src/spatial-solving/tnnmg/localbisectionsolver.hh b/dune/tectonic/spatial-solving/tnnmg/localbisectionsolver.hh similarity index 100% rename from src/spatial-solving/tnnmg/localbisectionsolver.hh rename to dune/tectonic/spatial-solving/tnnmg/localbisectionsolver.hh diff --git a/src/spatial-solving/tnnmg/zerononlinearity.hh b/dune/tectonic/spatial-solving/tnnmg/zerononlinearity.hh similarity index 100% rename from src/spatial-solving/tnnmg/zerononlinearity.hh rename to dune/tectonic/spatial-solving/tnnmg/zerononlinearity.hh diff --git a/src/tests/CMakeLists.txt b/dune/tectonic/tests/CMakeLists.txt similarity index 81% rename from src/tests/CMakeLists.txt rename to dune/tectonic/tests/CMakeLists.txt index b2004776..ef87c47f 100644 --- a/src/tests/CMakeLists.txt +++ b/dune/tectonic/tests/CMakeLists.txt @@ -2,3 +2,4 @@ dune_add_test(SOURCES globalfrictioncontainertest.cc) dune_add_test(SOURCES gridgluefrictiontest.cc) dune_add_test(SOURCES nodalweightstest.cc) dune_add_test(SOURCES supportpatchfactorytest.cc) +dune_add_test(SOURCES solverfactorytest.cc) diff --git a/src/tests/common.hh b/dune/tectonic/tests/common.hh similarity index 100% rename from src/tests/common.hh rename to dune/tectonic/tests/common.hh diff --git a/src/tests/couplingtest.hh b/dune/tectonic/tests/couplingtest.hh similarity index 100% rename from src/tests/couplingtest.hh rename to dune/tectonic/tests/couplingtest.hh diff --git a/src/tests/globalfrictioncontainertest.cc b/dune/tectonic/tests/globalfrictioncontainertest.cc similarity index 100% rename from src/tests/globalfrictioncontainertest.cc rename to dune/tectonic/tests/globalfrictioncontainertest.cc diff --git a/src/tests/gridgluefrictiontest.cc b/dune/tectonic/tests/gridgluefrictiontest.cc similarity index 100% rename from src/tests/gridgluefrictiontest.cc rename to dune/tectonic/tests/gridgluefrictiontest.cc diff --git a/src/nodalweights.cc b/dune/tectonic/tests/nodalweights.cc similarity index 100% rename from src/nodalweights.cc rename to dune/tectonic/tests/nodalweights.cc diff --git a/src/nodalweights.hh b/dune/tectonic/tests/nodalweights.hh similarity index 100% rename from src/nodalweights.hh rename to dune/tectonic/tests/nodalweights.hh diff --git a/src/tests/nodalweightstest.cc b/dune/tectonic/tests/nodalweightstest.cc similarity index 100% rename from src/tests/nodalweightstest.cc rename to dune/tectonic/tests/nodalweightstest.cc diff --git a/src/tests/nonoverlappingcouplingtest.cc b/dune/tectonic/tests/nonoverlappingcouplingtest.cc similarity index 100% rename from src/tests/nonoverlappingcouplingtest.cc rename to dune/tectonic/tests/nonoverlappingcouplingtest.cc diff --git a/src/solverfactorytest.cc b/dune/tectonic/tests/solverfactorytest.cc similarity index 95% rename from src/solverfactorytest.cc rename to dune/tectonic/tests/solverfactorytest.cc index ef3ad5a5..07e919f7 100644 --- a/src/solverfactorytest.cc +++ b/dune/tectonic/tests/solverfactorytest.cc @@ -159,7 +159,7 @@ void solveProblem(const ContactNetwork& contactNetwork, using Linearization = Dune::TNNMG::BoxConstrainedQuadraticFunctionalConstrainedLinearization<ContactFunctional, BitVector>; using DefectProjection = Dune::TNNMG::ObstacleDefectProjection; - using Step = Dune::TNNMG::TNNMGStep<ContactFunctional, BitVector, Linearization, DefectProjection, LocalSolver, ContactNetwork>; + using Step = Dune::TNNMG::TNNMGStep<ContactFunctional, BitVector, Linearization, DefectProjection, LocalSolver>; // set multigrid solver auto smoother = TruncatedBlockGSStep<Matrix, Vector>(); @@ -183,12 +183,11 @@ void solveProblem(const ContactNetwork& contactNetwork, linearMultigridStep->setTransferOperators(transfer); int mu = parset.get<int>("solver.tnnmg.main.multi"); // #multigrid steps in Newton step - auto step = Step(I, refX, nonlinearSmoother, linearMultigridStep, mu, DefectProjection(), LocalSolver(), contactNetwork); + auto step = Step(I, refX, nonlinearSmoother, linearMultigridStep, mu, DefectProjection(), LocalSolver()); // compute reference solution with generic functional and solver auto norm = Norm(mat); - if (initial) { auto refSolver = Solver(step, parset.get<size_t>("u0.solver.maximumIterations"), parset.get<double>("u0.solver.tolerance"), norm, Solver::FULL); @@ -235,22 +234,10 @@ void solveProblem(const ContactNetwork& contactNetwork, //print(refX, "refX: "); - x = refX; - return; - } // set up solver factory solver - using PatchSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>; using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, Matrix, Vector>; - const auto& preconditionerParset = parset.sub("solver.tnnmg.linear.preconditioner"); - - auto gsStep = Dune::Solvers::BlockGSStepFactory<Matrix, Vector>::create(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0)); - PatchSolver patchSolver(gsStep, - preconditionerParset.get<size_t>("maximumIterations"), - preconditionerParset.get<double>("tolerance"), - nullptr, - preconditionerParset.get<Solver::VerbosityMode>("verbosity"), - false); // absolute error + const auto& preconditionerParset = parset.sub("solver.tnnmg.preconditioner"); Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), true); Preconditioner preconditioner(preconditionerParset, contactNetwork, activeLevels); @@ -270,10 +257,10 @@ void solveProblem(const ContactNetwork& contactNetwork, print(ignore, "ignore: ");*/ - using MyFunctional = Functional<Matrix&, Vector&, std::decay_t<decltype(globalFriction)>&, Vector&, Vector&, typename Matrix::field_type>; - MyFunctional J(mat, rhs, globalFriction, lower, upper); - //using MyFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity, Vector&, Vector&, typename Matrix::field_type>; - //MyFunctional J(mat, rhs, ZeroNonlinearity(), lower, upper); + //using MyFunctional = Functional<Matrix&, Vector&, std::decay_t<decltype(globalFriction)>&, Vector&, Vector&, typename Matrix::field_type>; + //MyFunctional J(mat, rhs, globalFriction, lower, upper); + using MyFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity, Vector&, Vector&, typename Matrix::field_type>; + MyFunctional J(mat, rhs, ZeroNonlinearity(), lower, upper); //std::cout << "ref energy: " << J(refX) << std::endl; @@ -282,10 +269,11 @@ void solveProblem(const ContactNetwork& contactNetwork, //Norm mgNorm(*linearMultigridStep); //auto mgSolver = std::make_shared<Solver>(linearMultigridStep, parset.get<size_t>("solver.tnnmg.linear.maximumIterations"), parset.get<double>("solver.tnnmg.linear.tolerance"), mgNorm, Solver::QUIET); Norm mgNorm(*cgStep); - auto mgSolver = std::make_shared<Solver>(cgStep, parset.get<int>("solver.tnnmg.main.multi"), parset.get<double>("solver.tnnmg.linear.tolerance"), mgNorm, Solver::QUIET); + auto mgSolver = std::make_shared<Solver>(cgStep, parset.get<int>("solver.tnnmg.main.multi"), parset.get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), mgNorm, Solver::QUIET); - using Factory = SolverFactory<MyFunctional, BitVector, ContactNetwork>; - Factory factory(parset.sub("solver.tnnmg"), J, *mgSolver, ignore, contactNetwork); + using Factory = SolverFactory<MyFunctional, BitVector>; + Factory factory(parset.sub("solver.tnnmg"), J, ignore); + factory.build(mgSolver); /* std::vector<BitVector> bodyDirichletNodes; nBodyAssembler.postprocess(_dirichletNodes, bodyDirichletNodes); @@ -311,7 +299,7 @@ void solveProblem(const ContactNetwork& contactNetwork, }, " energy "); - double initialEnergy = J(x); + initialEnergy = J(x); solver.addCriterion( [&](){ static double oldEnergy=initialEnergy; @@ -335,10 +323,10 @@ void solveProblem(const ContactNetwork& contactNetwork, " truncated "); - std::vector<double> factors; + /*std::vector<double> factors; solver.addCriterion(reductionFactorCriterion(*tnnmgStep, norm, factors)); - solver.addCriterion(energyCriterion(*tnnmgStep, J, factors)); + solver.addCriterion(energyCriterion(*tnnmgStep, J, factors));*/ solver.preprocess(); solver.solve(); diff --git a/src/tests/supportpatchfactorytest.cc b/dune/tectonic/tests/supportpatchfactorytest.cc similarity index 100% rename from src/tests/supportpatchfactorytest.cc rename to dune/tectonic/tests/supportpatchfactorytest.cc diff --git a/dune/tectonic/time-stepping/CMakeLists.txt b/dune/tectonic/time-stepping/CMakeLists.txt new file mode 100644 index 00000000..f316e155 --- /dev/null +++ b/dune/tectonic/time-stepping/CMakeLists.txt @@ -0,0 +1,23 @@ +add_subdirectory("rate") +add_subdirectory("state") + +add_custom_target(tectonic_dune_time-stepping SOURCES + adaptivetimestepper.hh + adaptivetimestepper.cc + coupledtimestepper.hh + coupledtimestepper.cc + rate.hh + rate.cc + state.hh + state.cc + updaters.hh +) + +#install headers +install(FILES + adaptivetimestepper.hh + coupledtimestepper.hh + rate.hh + state.hh + updaters.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/dune/tectonic/time-stepping/adaptivetimestepper.cc b/dune/tectonic/time-stepping/adaptivetimestepper.cc new file mode 100644 index 00000000..79bad14f --- /dev/null +++ b/dune/tectonic/time-stepping/adaptivetimestepper.cc @@ -0,0 +1,276 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <dune/solvers/norms/energynorm.hh> +#include <dune/solvers/iterationsteps/cgstep.hh> +#include <dune/solvers/solvers/loopsolver.hh> + +#include "../spatial-solving/preconditioners/multilevelpatchpreconditioner.hh" + +#include "adaptivetimestepper.hh" + +void IterationRegister::registerCount(FixedPointIterationCounter count) { + totalCount += count; +} + +void IterationRegister::registerFinalCount(FixedPointIterationCounter count) { + finalCount = count; +} + +void IterationRegister::reset() { + totalCount = FixedPointIterationCounter(); + finalCount = FixedPointIterationCounter(); +} + +template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::AdaptiveTimeStepper( + Dune::ParameterTree const &parset, + ContactNetwork& contactNetwork, + const IgnoreVector& ignoreNodes, + GlobalFriction& globalFriction, + const std::vector<const BitVector*>& bodywiseNonmortarBoundaries, + Updaters ¤t, + double relativeTime, + double relativeTau, + ExternalForces& externalForces, + const ErrorNorms& errorNorms, + std::function<bool(Updaters &, Updaters &)> mustRefine) + : relativeTime_(relativeTime), + relativeTau_(relativeTau), + finalTime_(parset.get<double>("problem.finalTime")), + parset_(parset), + contactNetwork_(contactNetwork), + ignoreNodes_(ignoreNodes), + globalFriction_(globalFriction), + bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries), + current_(current), + R1_(), + externalForces_(externalForces), + mustRefine_(mustRefine), + errorNorms_(errorNorms) {} + +template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +bool AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::reachedEnd() { + return relativeTime_ >= 1.0; +} + +template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +auto AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::makeLinearSolver() const { + // make linear solver for linear correction in TNNMGStep + using Norm = EnergyNorm<Matrix, Vector>; + using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, Matrix, Vector>; + using LinearSolver = typename Dune::Solvers::LoopSolver<Vector>; + + const auto& preconditionerParset = parset_.sub("solver.tnnmg.linear.preconditioner"); + + Dune::BitSetVector<1> activeLevels(contactNetwork_.nLevels(), true); + Preconditioner preconditioner(preconditionerParset, contactNetwork_, activeLevels); + preconditioner.setPatchDepth(preconditionerParset.template get<size_t>("patchDepth")); + preconditioner.build(); + + auto cgStep = std::make_shared<Dune::Solvers::CGStep<Matrix, Vector>>(); + cgStep->setPreconditioner(preconditioner); + + Norm norm(*cgStep); + + return std::make_shared<LinearSolver>(cgStep, parset_.template get<int>("solver.tnnmg.main.multi"), parset_.template get<double>("solver.tnnmg.linear.tolerance"), norm, Solver::QUIET); +} + +template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +IterationRegister AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::advance() { + /* + | C | We check here if making the step R1 of size tau is a + | R1 | R2 | good idea. To check if we can coarsen, we compare + |F1|F2| | the result of (R1+R2) with C, i.e. two steps of size + tau with one of size 2*tau. To check if we need to + refine, we compare the result of (F1+F2) with R1, i.e. two steps + of size tau/2 with one of size tau. The method makes multiple + coarsening/refining attempts, with coarsening coming first. */ + + std::cout << "AdaptiveTimeStepper::advance()" << std::endl; + + // patch preconditioner only needs to be computed once per advance() + // make linear solver for linear correction in TNNMGStep + using Norm = EnergyNorm<Matrix, Vector>; + using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, Matrix, Vector>; + using LinearSolver = typename Dune::Solvers::LoopSolver<Vector>; + + /*const auto& preconditionerParset = parset_.sub("solver.tnnmg.preconditioner"); + + Dune::BitSetVector<1> activeLevels(contactNetwork_.nLevels(), true); + Preconditioner preconditioner(preconditionerParset, contactNetwork_, activeLevels); + preconditioner.setPatchDepth(preconditionerParset.template get<size_t>("patchDepth")); + preconditioner.build(); + + auto cgStep = std::make_shared<Dune::Solvers::CGStep<Matrix, Vector>>(); + cgStep->setPreconditioner(preconditioner); + + Norm norm(*cgStep); + + auto linearSolver = std::make_shared<LinearSolver>(cgStep, parset_.template get<int>("solver.tnnmg.main.multi"), parset_.template get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), norm, Solver::QUIET); +*/ + // set multigrid solver + auto smoother = TruncatedBlockGSStep<Matrix, Vector>(); + + using TransferOperator = NBodyContactTransfer<ContactNetwork, Vector>; + using TransferOperators = std::vector<std::shared_ptr<TransferOperator>>; + + TransferOperators transfer(contactNetwork_.nLevels()-1); + for (size_t i=0; i<transfer.size(); i++) { + transfer[i] = std::make_shared<TransferOperator>(); + transfer[i]->setup(contactNetwork_, i, i+1); + } + + // Remove any recompute filed so that initially the full transferoperator is assembled + for (size_t i=0; i<transfer.size(); i++) + std::dynamic_pointer_cast<TruncatedMGTransfer<Vector> >(transfer[i])->setRecomputeBitField(nullptr); + + auto linearMultigridStep = std::make_shared<Dune::Solvers::MultigridStep<Matrix, Vector> >(); + linearMultigridStep->setMGType(1, 3, 3); + linearMultigridStep->setSmoother(smoother); + linearMultigridStep->setTransferOperators(transfer); + + Norm norm(*linearMultigridStep); + + auto linearSolver = std::make_shared<LinearSolver>(linearMultigridStep, parset_.template get<int>("solver.tnnmg.main.multi"), parset_.template get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), norm, Solver::QUIET); + + const auto& currentNBodyAssembler = contactNetwork_.nBodyAssembler(); + + if (R1_.updaters == Updaters()) { + //setDeformation(current_); + R1_ = step(current_, currentNBodyAssembler, linearSolver, relativeTime_, relativeTau_); + } + + //std::cout << "AdaptiveTimeStepper Step 1" << std::endl; + + size_t coarseningCount = 0; + size_t refineCount = 0; + + bool didCoarsen = false; + iterationRegister_.reset(); + UpdatersWithCount R2; + UpdatersWithCount C; + + while (relativeTime_ + relativeTau_ <= 1.0) { + std::cout << "tau: " << relativeTau_ << std::endl; + + setDeformation(current_); + C = step(current_, currentNBodyAssembler, linearSolver, relativeTime_, 2 * relativeTau_); + std::cout << "AdaptiveTimeStepper C computed!" << std::endl << std::endl; + + /*using ScalarVector = typename Updaters::StateUpdater::ScalarVector; + std::vector<ScalarVector> cAlpha(contactNetwork_.nBodies()); + C.updaters.state_->extractAlpha(cAlpha); + print(cAlpha, "cAlpha: ");*/ + + setDeformation(R1_.updaters); + auto&& nBodyAssembler = step(currentNBodyAssembler); + R2 = step(R1_.updaters, nBodyAssembler, linearSolver, relativeTime_ + relativeTau_, relativeTau_); + std::cout << "AdaptiveTimeStepper R2 computed!" << std::endl << std::endl; + + + /*std::vector<ScalarVector> rAlpha(contactNetwork_.nBodies()); + R2.updaters.state_->extractAlpha(rAlpha); + print(rAlpha, "rAlpha: ");*/ + + + if (mustRefine_(C.updaters, R2.updaters)) + break; + + didCoarsen = true; + relativeTau_ *= 2; + R1_ = C; + + coarseningCount++; + } + + UpdatersWithCount F1; + UpdatersWithCount F2; + if (!didCoarsen) { + while (true) { + setDeformation(current_); + F1 = step(current_, currentNBodyAssembler, linearSolver, relativeTime_, relativeTau_ / 2.0); + std::cout << "AdaptiveTimeStepper F1 computed!" << std::endl << std::endl; + + setDeformation(F1.updaters); + auto&& nBodyAssembler = step(currentNBodyAssembler); + F2 = step(F1.updaters, nBodyAssembler, linearSolver, relativeTime_ + relativeTau_ / 2.0, + relativeTau_ / 2.0); + std::cout << "AdaptiveTimeStepper F2 computed!" << std::endl << std::endl; + if (!mustRefine_(R1_.updaters, F2.updaters)) { + std::cout << "Sufficiently refined!" << std::endl; + break; + } + + relativeTau_ /= 2.0; + R1_ = F1; + R2 = F2; + + refineCount++; + } + } + + std::cout << "AdaptiveTimeStepper::advance() ..."; + + iterationRegister_.registerFinalCount(R1_.count); + relativeTime_ += relativeTau_; + current_ = R1_.updaters; + + //UpdatersWithCount emptyR1; + //R1_ = emptyR1; + R1_ = R2; + + std::cout << " done with coarseningCount: " << coarseningCount << " and refineCount: " << refineCount << std::endl; + + return iterationRegister_; +} + +template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +void AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::setDeformation(const Updaters& updaters) { + std::vector<Vector> u; + updaters.rate_->extractDisplacement(u); + + for (size_t i=0; i<contactNetwork_.nBodies(); i++) { + contactNetwork_.body(i)->setDeformation(u[i]); + } + + // note: levelContactNetworks are not up-to-date; build() has to be called in order to update; + // unnecessary for standard multigrid as linear solver, might have to be called for patch preconditioner +} + +template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +typename AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::NBodyAssembler +AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step(const NBodyAssembler& oldNBodyAssembler) const { + NBodyAssembler nBodyAssembler = oldNBodyAssembler; + + nBodyAssembler.assembleTransferOperator(); + nBodyAssembler.assembleObstacle(); + + return nBodyAssembler; +} + +template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +template <class LinearSolver> +typename AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::UpdatersWithCount +AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step( + const Updaters& oldUpdaters, const NBodyAssembler& nBodyAssembler, std::shared_ptr<LinearSolver>& linearSolver, double rTime, double rTau) { + + UpdatersWithCount newUpdatersAndCount = {oldUpdaters.clone(), {}}; + + MyCoupledTimeStepper coupledTimeStepper(finalTime_, parset_, nBodyAssembler, + ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_, + newUpdatersAndCount.updaters, errorNorms_, externalForces_); + + newUpdatersAndCount.count = coupledTimeStepper.step(linearSolver, rTime, rTau); + iterationRegister_.registerCount(newUpdatersAndCount.count); + + /*using ScalarVector = typename Updaters::StateUpdater::ScalarVector; + std::vector<ScalarVector> alpha(contactNetwork_.nBodies()); + newUpdatersAndCount.updaters.state_->extractAlpha(alpha); + print(alpha, "step alpha: "); + */ + return newUpdatersAndCount; +} + +#include "adaptivetimestepper_tmpl.cc" diff --git a/src/time-stepping/adaptivetimestepper.hh b/dune/tectonic/time-stepping/adaptivetimestepper.hh similarity index 75% rename from src/time-stepping/adaptivetimestepper.hh rename to dune/tectonic/time-stepping/adaptivetimestepper.hh index ce090c01..391170a0 100644 --- a/src/time-stepping/adaptivetimestepper.hh +++ b/dune/tectonic/time-stepping/adaptivetimestepper.hh @@ -23,11 +23,14 @@ class AdaptiveTimeStepper { }; using Vector = typename Factory::Vector; + using Matrix = typename Factory::Matrix; using IgnoreVector = typename Factory::BitVector; //using ConvexProblem = typename Factory::ConvexProblem; //using Nonlinearity = typename Factory::Nonlinearity; - using MyCoupledTimeStepper = CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>; + using NBodyAssembler = typename ContactNetwork::NBodyAssembler; + + using MyCoupledTimeStepper = CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>; using GlobalFriction = typename MyCoupledTimeStepper::GlobalFriction; using BitVector = typename MyCoupledTimeStepper::BitVector; @@ -36,7 +39,7 @@ class AdaptiveTimeStepper { public: AdaptiveTimeStepper( Dune::ParameterTree const &parset, - const ContactNetwork& contactNetwork, + ContactNetwork& contactNetwork, const IgnoreVector& ignoreNodes, GlobalFriction& globalFriction, const std::vector<const BitVector*>& bodywiseNonmortarBoundaries, @@ -49,18 +52,27 @@ class AdaptiveTimeStepper { bool reachedEnd(); + auto makeLinearSolver() const; + IterationRegister advance(); double relativeTime_; double relativeTau_; private: - UpdatersWithCount step(Updaters const &oldUpdaters, double rTime, - double rTau); + void setDeformation(const Updaters& updaters); + + NBodyAssembler step(const NBodyAssembler& oldNBodyAssembler) const; + + + template <class LinearSolver> + UpdatersWithCount step(const Updaters& oldUpdaters, const NBodyAssembler& nBodyAssembler, + std::shared_ptr<LinearSolver>& linearSolver, + double rTime, double rTau); double finalTime_; Dune::ParameterTree const &parset_; - const ContactNetwork& contactNetwork_; + ContactNetwork& contactNetwork_; const IgnoreVector& ignoreNodes_; GlobalFriction& globalFriction_; @@ -74,4 +86,5 @@ class AdaptiveTimeStepper { IterationRegister iterationRegister_; }; + #endif diff --git a/dune/tectonic/time-stepping/adaptivetimestepper_tmpl.cc b/dune/tectonic/time-stepping/adaptivetimestepper_tmpl.cc new file mode 100644 index 00000000..0e7cd4f9 --- /dev/null +++ b/dune/tectonic/time-stepping/adaptivetimestepper_tmpl.cc @@ -0,0 +1,42 @@ +#ifndef MY_DIM +#error MY_DIM unset +#endif + +#include "../explicitgrid.hh" +#include "../explicitvectors.hh" + +#include <dune/solvers/norms/energynorm.hh> +#include <dune/solvers/solvers/loopsolver.hh> + +#include "../spatial-solving/tnnmg/functional.hh" +#include "../spatial-solving/solverfactory.hh" + +#include "../data-structures/network/contactnetwork.hh" +#include "../data-structures/friction/globalfriction.hh" + +#include "rate/rateupdater.hh" +#include "state/stateupdater.hh" +#include "updaters.hh" + +using MyContactNetwork = ContactNetwork<Grid, Vector>; + +using BoundaryNodes = typename MyContactNetwork::BoundaryNodes; +using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions; + +using MyStateUpdater = StateUpdater<ScalarVector, Vector>; +using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>; +using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>; + +using LinearSolver = Dune::Solvers::LoopSolver<Vector>; +using ErrorNorms = typename MyContactNetwork::StateEnergyNorms; +using NBodyAssembler = typename MyContactNetwork::NBodyAssembler; + +using MyGlobalFriction = GlobalFriction<Matrix, Vector>; +using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>; +using MySolverFactory = SolverFactory<MyFunctional, BitVector>; + +template class AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>; + +template typename AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>::UpdatersWithCount +AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>::step<LinearSolver>( + const MyUpdaters&, const NBodyAssembler&, std::shared_ptr<LinearSolver>&, double, double); diff --git a/src/time-stepping/coupledtimestepper.cc b/dune/tectonic/time-stepping/coupledtimestepper.cc similarity index 63% rename from src/time-stepping/coupledtimestepper.cc rename to dune/tectonic/time-stepping/coupledtimestepper.cc index 1df54774..42659d41 100644 --- a/src/time-stepping/coupledtimestepper.cc +++ b/dune/tectonic/time-stepping/coupledtimestepper.cc @@ -4,10 +4,12 @@ #include "coupledtimestepper.hh" -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> -CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::CoupledTimeStepper( +#include "../utils/debugutils.hh" + +template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> +CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::CoupledTimeStepper( double finalTime, Dune::ParameterTree const &parset, - const ContactNetwork& contactNetwork, + const NBodyAssembler& nBodyAssembler, const IgnoreVector& ignoreNodes, GlobalFriction& globalFriction, const std::vector<const BitVector*>& bodywiseNonmortarBoundaries, @@ -16,7 +18,7 @@ CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::CoupledTimeSt ExternalForces& externalForces) : finalTime_(finalTime), parset_(parset), - contactNetwork_(contactNetwork), + nBodyAssembler_(nBodyAssembler), ignoreNodes_(ignoreNodes), globalFriction_(globalFriction), bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries), @@ -24,12 +26,13 @@ CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::CoupledTimeSt externalForces_(externalForces), errorNorms_(errorNorms) {} -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> +template <class LinearSolver> FixedPointIterationCounter -CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step(double relativeTime, +CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::step(std::shared_ptr<LinearSolver>& linearSolver, double relativeTime, double relativeTau) { - std::cout << "CoupledTimeStepper::step()" << std::endl; + //std::cout << "CoupledTimeStepper::step()" << std::endl; updaters_.state_->nextTimeStep(); updaters_.rate_->nextTimeStep(); @@ -48,9 +51,17 @@ CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step(double r updaters_.state_->setup(tau); updaters_.rate_->setup(ell, tau, newRelativeTime, velocityRHS, velocityIterate, velocityMatrix); +/* std::cout << "tau: " << tau << std::endl; + print(ell, "ell: "); + print(velocityRHS, "velocityRHS: "); + print(velocityIterate, "velocityIterate: "); + for (size_t i=0; i<velocityMatrix.size(); i++) { + print(velocityMatrix[i], "velocityMatrix: "); + }*/ + FixedPointIterator fixedPointIterator( - parset_, contactNetwork_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_, errorNorms_); - auto const iterations = fixedPointIterator.run(updaters_, + parset_, nBodyAssembler_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_, errorNorms_); + auto const iterations = fixedPointIterator.template run<LinearSolver>(updaters_, linearSolver, velocityMatrix, velocityRHS, velocityIterate); return iterations; } diff --git a/src/time-stepping/coupledtimestepper.hh b/dune/tectonic/time-stepping/coupledtimestepper.hh similarity index 77% rename from src/time-stepping/coupledtimestepper.hh rename to dune/tectonic/time-stepping/coupledtimestepper.hh index fc619036..07391d9f 100644 --- a/src/time-stepping/coupledtimestepper.hh +++ b/dune/tectonic/time-stepping/coupledtimestepper.hh @@ -8,12 +8,12 @@ #include "../spatial-solving/fixedpointiterator.hh" -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> +template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> class CoupledTimeStepper { using Vector = typename Factory::Vector; using Matrix = typename Factory::Matrix; using IgnoreVector = typename Factory::BitVector; - using FixedPointIterator = FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>; + using FixedPointIterator = FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>; public: using GlobalFriction = typename FixedPointIterator::GlobalFriction; @@ -23,7 +23,7 @@ class CoupledTimeStepper { public: CoupledTimeStepper(double finalTime, Dune::ParameterTree const &parset, - const ContactNetwork& contactNetwork, + const NBodyAssembler& nBodyAssembler, const IgnoreVector& ignoreNodes, GlobalFriction& globalFriction, const std::vector<const BitVector*>& bodywiseNonmortarBoundaries, @@ -31,12 +31,13 @@ class CoupledTimeStepper { const ErrorNorms& errorNorms, ExternalForces& externalForces); - FixedPointIterationCounter step(double relativeTime, double relativeTau); + template <class LinearSolver> + FixedPointIterationCounter step(std::shared_ptr<LinearSolver>& linearSolver, double relativeTime, double relativeTau); private: double finalTime_; Dune::ParameterTree const &parset_; - const ContactNetwork& contactNetwork_; + const NBodyAssembler& nBodyAssembler_; const IgnoreVector& ignoreNodes_; GlobalFriction& globalFriction_; @@ -46,4 +47,5 @@ class CoupledTimeStepper { ExternalForces& externalForces_; const ErrorNorms& errorNorms_; }; + #endif diff --git a/dune/tectonic/time-stepping/coupledtimestepper_tmpl.cc b/dune/tectonic/time-stepping/coupledtimestepper_tmpl.cc new file mode 100644 index 00000000..e09f3f89 --- /dev/null +++ b/dune/tectonic/time-stepping/coupledtimestepper_tmpl.cc @@ -0,0 +1,40 @@ +#ifndef MY_DIM +#error MY_DIM unset +#endif + +#include "../explicitgrid.hh" +#include "../explicitvectors.hh" + +#include <dune/solvers/norms/energynorm.hh> +#include <dune/solvers/solvers/loopsolver.hh> + +#include "../spatial-solving/tnnmg/functional.hh" +#include "../spatial-solving/solverfactory.hh" + +#include "../data-structures/network/contactnetwork.hh" +#include "../data-structures/friction/globalfriction.hh" + +#include "rate/rateupdater.hh" +#include "state/stateupdater.hh" +#include "updaters.hh" + +using MyContactNetwork = ContactNetwork<Grid, Vector>; + +using BoundaryNodes = typename MyContactNetwork::BoundaryNodes; +using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions; + +using MyStateUpdater = StateUpdater<ScalarVector, Vector>; +using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>; +using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>; + +using LinearSolver = Dune::Solvers::LoopSolver<Vector>; +using ErrorNorms = typename MyContactNetwork::StateEnergyNorms; +using NBodyAssembler = typename MyContactNetwork::NBodyAssembler; + +using MyGlobalFriction = GlobalFriction<Matrix, Vector>; +using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>; +using MySolverFactory = SolverFactory<MyFunctional, BitVector>; + +template class CoupledTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>; + +template FixedPointIterationCounter CoupledTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>::step<LinearSolver>(std::shared_ptr<LinearSolver>&, double, double); diff --git a/src/time-stepping/rate.cc b/dune/tectonic/time-stepping/rate.cc similarity index 100% rename from src/time-stepping/rate.cc rename to dune/tectonic/time-stepping/rate.cc diff --git a/src/time-stepping/rate.hh b/dune/tectonic/time-stepping/rate.hh similarity index 100% rename from src/time-stepping/rate.hh rename to dune/tectonic/time-stepping/rate.hh diff --git a/dune/tectonic/time-stepping/rate/CMakeLists.txt b/dune/tectonic/time-stepping/rate/CMakeLists.txt new file mode 100644 index 00000000..a4b6508b --- /dev/null +++ b/dune/tectonic/time-stepping/rate/CMakeLists.txt @@ -0,0 +1,15 @@ +add_custom_target(tectonic_dune_time-stepping_rate SOURCES + backward_euler.hh + backward_euler.cc + newmark.hh + newmark.cc + rateupdater.hh + rateupdater.cc +) + +#install headers +install(FILES + backward_euler.hh + newmark.hh + rateupdater.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/time-stepping/rate/backward_euler.cc b/dune/tectonic/time-stepping/rate/backward_euler.cc similarity index 100% rename from src/time-stepping/rate/backward_euler.cc rename to dune/tectonic/time-stepping/rate/backward_euler.cc diff --git a/src/time-stepping/rate/backward_euler.hh b/dune/tectonic/time-stepping/rate/backward_euler.hh similarity index 100% rename from src/time-stepping/rate/backward_euler.hh rename to dune/tectonic/time-stepping/rate/backward_euler.hh diff --git a/src/time-stepping/rate/newmark.cc b/dune/tectonic/time-stepping/rate/newmark.cc similarity index 100% rename from src/time-stepping/rate/newmark.cc rename to dune/tectonic/time-stepping/rate/newmark.cc diff --git a/src/time-stepping/rate/newmark.hh b/dune/tectonic/time-stepping/rate/newmark.hh similarity index 100% rename from src/time-stepping/rate/newmark.hh rename to dune/tectonic/time-stepping/rate/newmark.hh diff --git a/src/time-stepping/rate/rateupdater.cc b/dune/tectonic/time-stepping/rate/rateupdater.cc similarity index 100% rename from src/time-stepping/rate/rateupdater.cc rename to dune/tectonic/time-stepping/rate/rateupdater.cc diff --git a/src/time-stepping/rate/rateupdater.hh b/dune/tectonic/time-stepping/rate/rateupdater.hh similarity index 100% rename from src/time-stepping/rate/rateupdater.hh rename to dune/tectonic/time-stepping/rate/rateupdater.hh diff --git a/src/time-stepping/rate/rateupdater_tmpl.cc b/dune/tectonic/time-stepping/rate/rateupdater_tmpl.cc similarity index 80% rename from src/time-stepping/rate/rateupdater_tmpl.cc rename to dune/tectonic/time-stepping/rate/rateupdater_tmpl.cc index 09299039..b626865f 100644 --- a/src/time-stepping/rate/rateupdater_tmpl.cc +++ b/dune/tectonic/time-stepping/rate/rateupdater_tmpl.cc @@ -5,7 +5,9 @@ #include "../../explicitgrid.hh" #include "../../explicitvectors.hh" -#include "../../data-structures/contactnetwork_tmpl.cc" +#include "../../data-structures/network/contactnetwork.hh" + +using MyContactNetwork = ContactNetwork<Grid, Vector>; using BoundaryNodes = typename MyContactNetwork::BoundaryNodes; using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions; diff --git a/src/time-stepping/rate_tmpl.cc b/dune/tectonic/time-stepping/rate_tmpl.cc similarity index 77% rename from src/time-stepping/rate_tmpl.cc rename to dune/tectonic/time-stepping/rate_tmpl.cc index 771a1a0c..a2daf9d7 100644 --- a/src/time-stepping/rate_tmpl.cc +++ b/dune/tectonic/time-stepping/rate_tmpl.cc @@ -1,5 +1,12 @@ -#include "../data-structures/contactnetwork_tmpl.cc" +#ifndef MY_DIM +#error MY_DIM unset +#endif + +#include "../explicitgrid.hh" #include "../explicitvectors.hh" +#include "../data-structures/network/contactnetwork.hh" + +using MyContactNetwork = ContactNetwork<Grid, Vector>; using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions; using BoundaryNodes = typename MyContactNetwork::BoundaryNodes; diff --git a/src/time-stepping/state.cc b/dune/tectonic/time-stepping/state.cc similarity index 100% rename from src/time-stepping/state.cc rename to dune/tectonic/time-stepping/state.cc diff --git a/src/time-stepping/state.hh b/dune/tectonic/time-stepping/state.hh similarity index 100% rename from src/time-stepping/state.hh rename to dune/tectonic/time-stepping/state.hh diff --git a/dune/tectonic/time-stepping/state/CMakeLists.txt b/dune/tectonic/time-stepping/state/CMakeLists.txt new file mode 100644 index 00000000..9fe69dc1 --- /dev/null +++ b/dune/tectonic/time-stepping/state/CMakeLists.txt @@ -0,0 +1,14 @@ +add_custom_target(tectonic_dune_time-stepping_state SOURCES + ageinglawstateupdater.hh + ageinglawstateupdater.cc + sliplawstateupdater.hh + sliplawstateupdater.cc + stateupdater.hh +) + +#install headers +install(FILES + ageinglawstateupdater.hh + sliplawstateupdater.hh + stateupdater.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/time-stepping/state/ageinglawstateupdater.cc b/dune/tectonic/time-stepping/state/ageinglawstateupdater.cc similarity index 100% rename from src/time-stepping/state/ageinglawstateupdater.cc rename to dune/tectonic/time-stepping/state/ageinglawstateupdater.cc diff --git a/src/time-stepping/state/ageinglawstateupdater.hh b/dune/tectonic/time-stepping/state/ageinglawstateupdater.hh similarity index 100% rename from src/time-stepping/state/ageinglawstateupdater.hh rename to dune/tectonic/time-stepping/state/ageinglawstateupdater.hh diff --git a/src/time-stepping/state/calculation.wxm b/dune/tectonic/time-stepping/state/calculation.wxm similarity index 100% rename from src/time-stepping/state/calculation.wxm rename to dune/tectonic/time-stepping/state/calculation.wxm diff --git a/dune/tectonic/time-stepping/state/explicit.aux b/dune/tectonic/time-stepping/state/explicit.aux new file mode 100644 index 00000000..f23e5468 --- /dev/null +++ b/dune/tectonic/time-stepping/state/explicit.aux @@ -0,0 +1 @@ +\relax diff --git a/dune/tectonic/time-stepping/state/explicit.log b/dune/tectonic/time-stepping/state/explicit.log new file mode 100644 index 00000000..5f51474a --- /dev/null +++ b/dune/tectonic/time-stepping/state/explicit.log @@ -0,0 +1,285 @@ +This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016/Debian) (preloaded format=pdflatex 2018.9.22) 2 SEP 2019 17:19 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**explicit.tex +(./explicit.tex +LaTeX2e <2017/01/01> patch level 3 +Babel <3.9r> and hyphenation patterns for 83 language(s) loaded. +(/usr/share/texlive/texmf-dist/tex/latex/standalone/standalone.cls +Document Class: standalone 2015/07/15 v1.2 Class to compile TeX sub-files stand +alone +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifluatex.sty +Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO) +Package ifluatex Info: LuaTeX not detected. +) +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifpdf.sty +Package: ifpdf 2016/05/14 v3.1 Provides the ifpdf switch +) +(/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty +Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional +) +(/usr/share/texlive/texmf-dist/tex/latex/xkeyval/xkeyval.sty +Package: xkeyval 2014/12/03 v2.7a package option processing (HA) + +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkeyval.tex +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkvutils.tex +\XKV@toks=\toks14 +\XKV@tempa@toks=\toks15 + +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/keyval.tex)) +\XKV@depth=\count79 +File: xkeyval.tex 2014/12/03 v2.7a key=value parser (HA) +)) +\sa@internal=\count80 +\c@sapage=\count81 + +(/usr/share/texlive/texmf-dist/tex/latex/standalone/standalone.cfg +File: standalone.cfg 2015/07/15 v1.2 Default configuration file for 'standalone +' class +) +(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls +Document Class: article 2014/09/29 v1.4h Standard LaTeX document class +(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo +File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option) +) +\c@part=\count82 +\c@section=\count83 +\c@subsection=\count84 +\c@subsubsection=\count85 +\c@paragraph=\count86 +\c@subparagraph=\count87 +\c@figure=\count88 +\c@table=\count89 +\abovecaptionskip=\skip41 +\belowcaptionskip=\skip42 +\bibindent=\dimen102 +) +(/usr/share/texmf/tex/latex/preview/preview.sty +Package: preview 2010/02/14 11.90 (AUCTeX/preview-latex) + +(/usr/share/texmf/tex/latex/preview/prtightpage.def +\PreviewBorder=\dimen103 +) +\pr@snippet=\count90 +\pr@box=\box26 +\pr@output=\toks16 +)) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty +Package: amsmath 2016/11/05 v2.16a AMS math features +\@mathmargin=\skip43 + +For additional information on amsmath, use the `?' option. +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty +Package: amstext 2000/06/29 v2.01 AMS text + +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty +File: amsgen.sty 1999/11/30 v2.0 generic functions +\@emptytoks=\toks17 +\ex@=\dimen104 +)) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty +Package: amsbsy 1999/11/29 v1.2d Bold Symbols +\pmbraise@=\dimen105 +) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty +Package: amsopn 2016/03/08 v2.02 operator names +) +\inf@bad=\count91 +LaTeX Info: Redefining \frac on input line 213. +\uproot@=\count92 +\leftroot@=\count93 +LaTeX Info: Redefining \overline on input line 375. +\classnum@=\count94 +\DOTSCASE@=\count95 +LaTeX Info: Redefining \ldots on input line 472. +LaTeX Info: Redefining \dots on input line 475. +LaTeX Info: Redefining \cdots on input line 596. +\Mathstrutbox@=\box27 +\strutbox@=\box28 +\big@size=\dimen106 +LaTeX Font Info: Redeclaring font encoding OML on input line 712. +LaTeX Font Info: Redeclaring font encoding OMS on input line 713. +\macc@depth=\count96 +\c@MaxMatrixCols=\count97 +\dotsspace@=\muskip10 +\c@parentequation=\count98 +\dspbrk@lvl=\count99 +\tag@help=\toks18 +\row@=\count100 +\column@=\count101 +\maxfields@=\count102 +\andhelp@=\toks19 +\eqnshift@=\dimen107 +\alignsep@=\dimen108 +\tagshift@=\dimen109 +\tagwidth@=\dimen110 +\totwidth@=\dimen111 +\lineht@=\dimen112 +\@envbody=\toks20 +\multlinegap=\skip44 +\multlinetaggap=\skip45 +\mathdisplay@stack=\toks21 +LaTeX Info: Redefining \[ on input line 2817. +LaTeX Info: Redefining \] on input line 2818. +) +(/usr/share/texlive/texmf-dist/tex/latex/mathtools/mathtools.sty +Package: mathtools 2015/11/12 v1.18 mathematical typesetting tools + +(/usr/share/texlive/texmf-dist/tex/latex/tools/calc.sty +Package: calc 2014/10/28 v4.3 Infix arithmetic (KKT,FJ) +\calc@Acount=\count103 +\calc@Bcount=\count104 +\calc@Adimen=\dimen113 +\calc@Bdimen=\dimen114 +\calc@Askip=\skip46 +\calc@Bskip=\skip47 +LaTeX Info: Redefining \setlength on input line 80. +LaTeX Info: Redefining \addtolength on input line 81. +\calc@Ccount=\count105 +\calc@Cskip=\skip48 +) +(/usr/share/texlive/texmf-dist/tex/latex/mathtools/mhsetup.sty +Package: mhsetup 2010/01/21 v1.2a programming setup (MH) +) +LaTeX Info: Thecontrolsequence`\('isalreadyrobust on input line 129. +LaTeX Info: Thecontrolsequence`\)'isalreadyrobust on input line 129. +LaTeX Info: Thecontrolsequence`\['isalreadyrobust on input line 129. +LaTeX Info: Thecontrolsequence`\]'isalreadyrobust on input line 129. +\g_MT_multlinerow_int=\count106 +\l_MT_multwidth_dim=\dimen115 +\origjot=\skip49 +\l_MT_shortvdotswithinadjustabove_dim=\dimen116 +\l_MT_shortvdotswithinadjustbelow_dim=\dimen117 +\l_MT_above_intertext_sep=\dimen118 +\l_MT_below_intertext_sep=\dimen119 +\l_MT_above_shortintertext_sep=\dimen120 +\l_MT_below_shortintertext_sep=\dimen121 +) +No file explicit.aux. +\openout1 = `explicit.aux'. + +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 6. +LaTeX Font Info: ... okay on input line 6. +Preview: Fontsize 10pt +Preview: PDFoutput 1 +(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty +Package: graphicx 2014/10/28 v1.0g Enhanced LaTeX Graphics (DPC,SPQR) + +(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty +Package: graphics 2016/10/09 v1.0u Standard LaTeX Graphics (DPC,SPQR) + +(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty +Package: trig 2016/01/03 v1.10 sin cos tan (DPC) +) +(/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg +File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration +) +Package graphics Info: Driver file: pdftex.def on input line 99. + +(/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def +File: pdftex.def 2017/01/12 v0.06k Graphics/color for pdfTeX + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/infwarerr.sty +Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO) +) +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty +Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO) +) +\Gread@gobject=\count107 + +(/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count108 +\scratchdimen=\dimen122 +\scratchbox=\box29 +\nofMPsegments=\count109 +\nofMParguments=\count110 +\everyMPshowfont=\toks22 +\MPscratchCnt=\count111 +\MPscratchDim=\dimen123 +\MPnumerator=\count112 +\makeMPintoPDFobject=\count113 +\everyMPtoPDFconversion=\toks23 +))) (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/pdftexcmds.sty +Package: pdftexcmds 2016/05/21 v0.22 Utility functions of pdfTeX for LuaTeX (HO +) +Package pdftexcmds Info: LuaTeX not detected. +Package pdftexcmds Info: \pdf@primitive is available. +Package pdftexcmds Info: \pdf@ifprimitive is available. +Package pdftexcmds Info: \pdfdraftmode found. +) +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty +Package: epstopdf-base 2016/05/15 v2.6 Base part for package epstopdf + +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty +Package: grfext 2016/05/16 v1.2 Manage graphics extensions (HO) + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvdefinekeys.sty +Package: kvdefinekeys 2016/05/16 v1.4 Define keys (HO) +)) +(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty +Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO) + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvsetkeys.sty +Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO) + +(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/etexcmds.sty +Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO) +Package etexcmds Info: Could not find \expanded. +(etexcmds) That can mean that you are not using pdfTeX 1.50 or +(etexcmds) that some package has redefined \expanded. +(etexcmds) In the latter case, load this package earlier. +))) +Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4 +38. +Package grfext Info: Graphics extension search list: +(grfext) [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE +G,.JBIG2,.JB2,.eps] +(grfext) \AppendGraphicsExtensions on input line 456. + +(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv +e +)) +\Gin@req@height=\dimen124 +\Gin@req@width=\dimen125 +) +Preview: Tightpage 0 0 0 0 +[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./explicit.aux) ) +Here is how much of TeX's memory you used: + 3166 strings out of 493013 + 46673 string characters out of 6135682 + 112782 words of memory out of 5000000 + 6679 multiletter control sequences out of 15000+600000 + 4094 words of font info for 16 fonts, out of 8000000 for 9000 + 1141 hyphenation exceptions out of 8191 + 53i,12n,56p,255b,147s stack positions out of 5000i,500n,10000p,200000b,80000s +</usr/ +share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb></usr/share/ +texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/share/texliv +e/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi5.pfb></usr/share/texlive/texmf +-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/share/texlive/texmf-dist/f +onts/type1/public/amsfonts/cm/cmr10.pfb></usr/share/texlive/texmf-dist/fonts/ty +pe1/public/amsfonts/cm/cmr5.pfb></usr/share/texlive/texmf-dist/fonts/type1/publ +ic/amsfonts/cm/cmr7.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfo +nts/cm/cmsy10.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm +/cmsy5.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7. +pfb> +Output written on explicit.pdf (1 page, 82543 bytes). +PDF statistics: + 48 PDF objects out of 1000 (max. 8388607) + 34 compressed objects within 1 object stream + 0 named destinations out of 1000 (max. 500000) + 1 words of extra memory for PDF output out of 10000 (max. 10000000) + diff --git a/dune/tectonic/time-stepping/state/explicit.pdf b/dune/tectonic/time-stepping/state/explicit.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6fc65f44258d5ae805d73b226c4f89a33a3fa730 GIT binary patch literal 82543 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 ZC5c5P6-B9OToy)#CYD^Ps;>TSTmX6=DDnUR literal 0 HcmV?d00001 diff --git a/dune/tectonic/time-stepping/state/explicit.synctex.gz b/dune/tectonic/time-stepping/state/explicit.synctex.gz new file mode 100644 index 0000000000000000000000000000000000000000..187abd95b93a078a4fa804ae4b3fde5124d9a8d6 GIT binary patch literal 2143 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 literal 0 HcmV?d00001 diff --git a/src/time-stepping/state/explicit.tex b/dune/tectonic/time-stepping/state/explicit.tex similarity index 100% rename from src/time-stepping/state/explicit.tex rename to dune/tectonic/time-stepping/state/explicit.tex diff --git a/src/time-stepping/state/sliplawstateupdater.cc b/dune/tectonic/time-stepping/state/sliplawstateupdater.cc similarity index 100% rename from src/time-stepping/state/sliplawstateupdater.cc rename to dune/tectonic/time-stepping/state/sliplawstateupdater.cc diff --git a/src/time-stepping/state/sliplawstateupdater.hh b/dune/tectonic/time-stepping/state/sliplawstateupdater.hh similarity index 100% rename from src/time-stepping/state/sliplawstateupdater.hh rename to dune/tectonic/time-stepping/state/sliplawstateupdater.hh diff --git a/src/time-stepping/state/stateupdater.hh b/dune/tectonic/time-stepping/state/stateupdater.hh similarity index 85% rename from src/time-stepping/state/stateupdater.hh rename to dune/tectonic/time-stepping/state/stateupdater.hh index ed7a5241..016e08c0 100644 --- a/src/time-stepping/state/stateupdater.hh +++ b/dune/tectonic/time-stepping/state/stateupdater.hh @@ -65,7 +65,13 @@ template <class ScalarVectorTEMPLATE, class Vector> class StateUpdater { } std::shared_ptr<StateUpdater<ScalarVector, Vector>> virtual clone() const { - return std::make_shared<StateUpdater<ScalarVector, Vector>>(*this); + auto updater = std::make_shared<StateUpdater<ScalarVector, Vector>>(); + + for (size_t i=0; i<localStateUpdaters_.size(); i++) { + auto localUpdater = localStateUpdaters_[i]->clone(); + updater->addLocalUpdater(localUpdater); + } + return updater; // std::make_shared<StateUpdater<ScalarVector, Vector>>(*this); } private: diff --git a/src/time-stepping/state_tmpl.cc b/dune/tectonic/time-stepping/state_tmpl.cc similarity index 93% rename from src/time-stepping/state_tmpl.cc rename to dune/tectonic/time-stepping/state_tmpl.cc index 39fd6bd4..d4d99038 100644 --- a/src/time-stepping/state_tmpl.cc +++ b/dune/tectonic/time-stepping/state_tmpl.cc @@ -4,7 +4,7 @@ #include <dune/common/promotiontraits.hh> #include <dune/contact/assemblers/dualmortarcoupling.hh> -#include "../frictioncouplingpair.hh" +#include "../data-structures/friction/frictioncouplingpair.hh" using field_type = typename Dune::PromotionTraits<typename Vector::field_type, typename DeformedGrid::ctype>::PromotedType; diff --git a/src/time-stepping/updaters.hh b/dune/tectonic/time-stepping/updaters.hh similarity index 100% rename from src/time-stepping/updaters.hh rename to dune/tectonic/time-stepping/updaters.hh diff --git a/dune/tectonic/utils/CMakeLists.txt b/dune/tectonic/utils/CMakeLists.txt new file mode 100644 index 00000000..c5498570 --- /dev/null +++ b/dune/tectonic/utils/CMakeLists.txt @@ -0,0 +1,18 @@ +add_custom_target(tectonic_dune_utils SOURCES + almostequal.hh + debugutils.hh + diameter.hh + geocoordinate.hh + index-in-sorted-range.hh + tobool.hh +) + +#install headers +install(FILES + almostequal.hh + debugutils.hh + diameter.hh + geocoordinate.hh + index-in-sorted-range.hh + tobool.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic) diff --git a/src/utils/almostequal.hh b/dune/tectonic/utils/almostequal.hh similarity index 100% rename from src/utils/almostequal.hh rename to dune/tectonic/utils/almostequal.hh diff --git a/src/utils/debugutils.hh b/dune/tectonic/utils/debugutils.hh similarity index 100% rename from src/utils/debugutils.hh rename to dune/tectonic/utils/debugutils.hh diff --git a/src/utils/diameter.hh b/dune/tectonic/utils/diameter.hh similarity index 100% rename from src/utils/diameter.hh rename to dune/tectonic/utils/diameter.hh diff --git a/dune/tectonic/geocoordinate.hh b/dune/tectonic/utils/geocoordinate.hh similarity index 100% rename from dune/tectonic/geocoordinate.hh rename to dune/tectonic/utils/geocoordinate.hh diff --git a/dune/tectonic/index-in-sorted-range.hh b/dune/tectonic/utils/index-in-sorted-range.hh similarity index 100% rename from dune/tectonic/index-in-sorted-range.hh rename to dune/tectonic/utils/index-in-sorted-range.hh diff --git a/src/utils/tobool.hh b/dune/tectonic/utils/tobool.hh similarity index 100% rename from src/utils/tobool.hh rename to dune/tectonic/utils/tobool.hh diff --git a/program_structure.txt b/program_structure.txt deleted file mode 100644 index a2db29cd..00000000 --- a/program_structure.txt +++ /dev/null @@ -1,29 +0,0 @@ --------------------------- --- Program structure: -- --------------------------- - - -1. build n-body system - - contains grids, couplings, gridViews, assembler - - Data structure: LevelContactNetwork - Factories: StackedBlocksFactory - -2. initialize/set up program state - - holds bodyStates, u, v, a, alpha for each body - - defines time, timeStep - - computes initial conditions - - Data structure: ProgramState - --- tested until here - -3. assemble RSD friction - -4. set up TNNMG solver - - rate updater - - state updater - -5. adaptive time stepper - - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b45d06d1..e41c1f9a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,113 +1,19 @@ -add_subdirectory("tests") -add_subdirectory("spatial-solving") - -set(SW_SOURCE_FILES - assemblers.cc - data-structures/body.cc - data-structures/enumparser.cc - io/vtk.cc - io/hdf5/frictionalboundary-writer.cc - io/hdf5/iteration-writer.cc - io/hdf5/patchinfo-writer.cc - io/hdf5/restart-io.cc - io/hdf5/surface-writer.cc - io/hdf5/time-writer.cc -# one-body-problem-data/mygeometry.cc -# one-body-problem-data/mygrid.cc -# one-body-problem.cc - spatial-solving/fixedpointiterator.cc - spatial-solving/solverfactory.cc - time-stepping/adaptivetimestepper.cc - time-stepping/coupledtimestepper.cc - time-stepping/rate.cc - time-stepping/rate/rateupdater.cc - time-stepping/state.cc -) - -set(MSW_SOURCE_FILES - assemblers.cc - #nodalweights.cc - data-structures/body.cc - data-structures/levelcontactnetwork.cc - data-structures/contactnetwork.cc - data-structures/enumparser.cc - #factories/cantorfactory.cc - factories/threeblocksfactory.cc - factories/stackedblocksfactory.cc - io/vtk.cc - io/hdf5/frictionalboundary-writer.cc - io/hdf5/iteration-writer.cc - io/hdf5/patchinfo-writer.cc - io/hdf5/restart-io.cc - io/hdf5/surface-writer.cc - io/hdf5/time-writer.cc - #multi-body-problem-data/grid/cube.cc - #multi-body-problem-data/grid/cubefaces.cc - multi-body-problem-data/grid/cuboidgeometry.cc - multi-body-problem-data/grid/mygrids.cc - multi-body-problem-data/grid/simplexmanager.cc - multi-body-problem.cc - #spatial-solving/solverfactory.cc - spatial-solving/fixedpointiterator.cc - #spatial-solving/solverfactory_old.cc - time-stepping/adaptivetimestepper.cc - time-stepping/coupledtimestepper.cc - time-stepping/rate.cc - time-stepping/rate/rateupdater.cc - time-stepping/state.cc -) +add_subdirectory("foam") +add_subdirectory("multi-body-problem") set(UGW_SOURCE_FILES - assemblers.cc # FIXME - io/uniform-grid-writer.cc - io/vtk.cc - one-body-problem-data/mygrid.cc -) - -set(SFT_SOURCE_FILES - assemblers.cc - data-structures/body.cc - data-structures/levelcontactnetwork.cc - data-structures/contactnetwork.cc - data-structures/enumparser.cc - factories/stackedblocksfactory.cc - io/vtk.cc - multi-body-problem-data/grid/cuboidgeometry.cc - multi-body-problem-data/grid/mygrids.cc - multi-body-problem-data/grid/simplexmanager.cc - #spatial-solving/solverfactory.cc - #spatial-solving/fixedpointiterator.cc - #spatial-solving/solverfactory_old.cc - #time-stepping/adaptivetimestepper.cc - #time-stepping/coupledtimestepper.cc - time-stepping/rate.cc - time-stepping/rate/rateupdater.cc - time-stepping/state.cc - solverfactorytest.cc + ../dune/tectonic/assemblers.cc # FIXME + ../dune/tectonic/io/uniform-grid-writer.cc + ../dune/tectonic/io/vtk.cc + ../dune/tectonic/problem-data/grid/mygrids.cc ) foreach(_dim 2 3) - set(_sw_target one-body-problem-${_dim}D) - set(_msw_target multi-body-problem-${_dim}D) set(_ugw_target uniform-grid-writer-${_dim}D) - set(_sft_target solverfactorytest-${_dim}D) - add_executable(${_sw_target} ${SW_SOURCE_FILES}) - add_executable(${_msw_target} ${MSW_SOURCE_FILES}) add_executable(${_ugw_target} ${UGW_SOURCE_FILES}) - add_executable(${_sft_target} ${SFT_SOURCE_FILES}) - add_dune_ug_flags(${_sw_target}) - add_dune_ug_flags(${_msw_target}) + add_dune_ug_flags(${_ugw_target}) - add_dune_ug_flags(${_sft_target}) - - add_dune_hdf5_flags(${_sw_target}) - add_dune_hdf5_flags(${_msw_target}) - set_property(TARGET ${_sw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}") - set_property(TARGET ${_msw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}") - #set_property(TARGET ${_msw_target} APPEND PROPERTY COMPILE_DEFINITIONS "NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY=1") set_property(TARGET ${_ugw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}") - set_property(TARGET ${_sft_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}") - #set_property(TARGET ${_sft_target} APPEND PROPERTY COMPILE_DEFINITIONS "NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY=1") endforeach() diff --git a/src/data-structures/contactnetwork_tmpl.cc b/src/data-structures/contactnetwork_tmpl.cc deleted file mode 100644 index 03374e69..00000000 --- a/src/data-structures/contactnetwork_tmpl.cc +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef MY_DIM -#error MY_DIM unset -#endif - -#include "../explicitgrid.hh" -#include "../explicitvectors.hh" - -#include "contactnetwork.hh" - -using MyContactNetwork = ContactNetwork<Grid, Vector>; - -template class ContactNetwork<Grid, Vector>; diff --git a/src/foam/CMakeLists.txt b/src/foam/CMakeLists.txt new file mode 100644 index 00000000..ab24974c --- /dev/null +++ b/src/foam/CMakeLists.txt @@ -0,0 +1,43 @@ +add_custom_target(tectonic_src_foam SOURCES + foam.cfg + foam-2D.cfg +) + +set(FOAM_SOURCE_FILES + ../../dune/tectonic/assemblers.cc + ../../dune/tectonic/data-structures/body/body.cc + ../../dune/tectonic/data-structures/network/levelcontactnetwork.cc + ../../dune/tectonic/data-structures/network/contactnetwork.cc + ../../dune/tectonic/data-structures/enumparser.cc + ../../dune/tectonic/factories/twoblocksfactory.cc + ../../dune/tectonic/io/vtk.cc + ../../dune/tectonic/io/hdf5/frictionalboundary-writer.cc + ../../dune/tectonic/io/hdf5/iteration-writer.cc + #../../dune/tectonic/io/hdf5/patchinfo-writer.cc + ../../dune/tectonic/io/hdf5/restart-io.cc + ../../dune/tectonic/io/hdf5/surface-writer.cc + ../../dune/tectonic/io/hdf5/time-writer.cc + ../../dune/tectonic/problem-data/grid/cuboidgeometry.cc + ../../dune/tectonic/problem-data/grid/mygrids.cc + ../../dune/tectonic/problem-data/grid/simplexmanager.cc + ../../dune/tectonic/spatial-solving/solverfactory.cc + ../../dune/tectonic/spatial-solving/fixedpointiterator.cc + ../../dune/tectonic/time-stepping/coupledtimestepper.cc + ../../dune/tectonic/time-stepping/adaptivetimestepper.cc + ../../dune/tectonic/time-stepping/rate.cc + ../../dune/tectonic/time-stepping/rate/rateupdater.cc + ../../dune/tectonic/time-stepping/state.cc + foam.cc +) + +foreach(_dim 2 3) + set(_foam_target foam-${_dim}D) + + add_executable(${_foam_target} ${FOAM_SOURCE_FILES}) + + add_dune_ug_flags(${_foam_target}) + add_dune_hdf5_flags(${_foam_target}) + + set_property(TARGET ${_foam_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}") + #set_property(TARGET ${_foam_target} APPEND PROPERTY COMPILE_DEFINITIONS "NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY=1") +endforeach() diff --git a/src/one-body-problem-2D.cfg b/src/foam/foam-2D.cfg similarity index 55% rename from src/one-body-problem-2D.cfg rename to src/foam/foam-2D.cfg index a61cfba2..6efcb38b 100644 --- a/src/one-body-problem-2D.cfg +++ b/src/foam/foam-2D.cfg @@ -1,9 +1,9 @@ # -*- mode:conf -*- [boundary.friction] -smallestDiameter= 2e-3 # [m] +smallestDiameter = 0.005 # 2e-3 [m] [timeSteps] -refinementTolerance = 1e-5 +refinementTolerance = 1e-5 # 1e-5 [u0.solver] tolerance = 1e-8 @@ -17,5 +17,8 @@ tolerance = 1e-8 [v.fpi] tolerance = 1e-5 -[solver.tnnmg.linear] +[solver.tnnmg.preconditioner.basesolver] +tolerance = 1e-10 + +[solver.tnnmg.preconditioner.patchsolver] tolerance = 1e-10 diff --git a/src/foam/foam.cc b/src/foam/foam.cc new file mode 100644 index 00000000..fe95424f --- /dev/null +++ b/src/foam/foam.cc @@ -0,0 +1,483 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_IPOPT +#undef HAVE_IPOPT +#endif + +#include <atomic> +#include <cmath> +#include <csignal> +#include <exception> +#include <fstream> +#include <iostream> +#include <iomanip> +#include <memory> + +#include <dune/common/bitsetvector.hh> +#include <dune/common/exceptions.hh> +#include <dune/common/fmatrix.hh> +#include <dune/common/function.hh> +#include <dune/common/fvector.hh> +#include <dune/common/parallel/mpihelper.hh> +#include <dune/common/parametertree.hh> +#include <dune/common/parametertreeparser.hh> + +#include <dune/grid/common/mcmgmapper.hh> +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/bvector.hh> + +#include <dune/fufem/boundarypatch.hh> +#include <dune/fufem/geometry/convexpolyhedron.hh> +#include <dune/fufem/formatstring.hh> +#include <dune/fufem/hdf5/file.hh> + +#include <dune/solvers/norms/energynorm.hh> +#include <dune/solvers/solvers/loopsolver.hh> +#include <dune/solvers/iterationsteps/blockgssteps.hh> + +#include <dune/contact/common/deformedcontinuacomplex.hh> +#include <dune/contact/common/couplingpair.hh> +#include <dune/contact/projections/normalprojection.hh> + + +#include <dune/tectonic/assemblers.hh> +#include <dune/tectonic/gridselector.hh> +#include <dune/tectonic/explicitgrid.hh> +#include <dune/tectonic/explicitvectors.hh> + +#include <dune/tectonic/data-structures/enumparser.hh> +#include <dune/tectonic/data-structures/enums.hh> +#include <dune/tectonic/data-structures/network/contactnetwork.hh> +#include <dune/tectonic/data-structures/matrices.hh> +#include <dune/tectonic/data-structures/program_state.hh> +#include <dune/tectonic/data-structures/friction/globalfriction.hh> + +#include <dune/tectonic/factories/twoblocksfactory.hh> + +#include <dune/tectonic/io/hdf5-levelwriter.hh> +#include <dune/tectonic/io/hdf5/restart-io.hh> +#include <dune/tectonic/io/vtk.hh> + +#include <dune/tectonic/problem-data/bc.hh> +#include <dune/tectonic/problem-data/mybody.hh> +#include <dune/tectonic/problem-data/grid/mygrids.hh> + +#include <dune/tectonic/spatial-solving/tnnmg/functional.hh> +//#include <dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh> +#include <dune/tectonic/spatial-solving/tnnmg/localbisectionsolver.hh> +#include <dune/tectonic/spatial-solving/solverfactory.hh> + +#include <dune/tectonic/time-stepping/adaptivetimestepper.hh> +#include <dune/tectonic/time-stepping/rate.hh> +#include <dune/tectonic/time-stepping/state.hh> +#include <dune/tectonic/time-stepping/updaters.hh> + +#include <dune/tectonic/utils/debugutils.hh> +#include <dune/tectonic/utils/diameter.hh> +#include <dune/tectonic/utils/geocoordinate.hh> + +// for getcwd +#include <unistd.h> + +//#include <tbb/tbb.h> //TODO multi threading preconditioner? +//#include <pthread.h> + +size_t const dims = MY_DIM; + +Dune::ParameterTree getParameters(int argc, char *argv[]) { + Dune::ParameterTree parset; + Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/foam/foam.cfg", parset); + Dune::ParameterTreeParser::readINITree( + Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/foam/foam-%dD.cfg", dims), parset); + Dune::ParameterTreeParser::readOptions(argc, argv, parset); + return parset; +} + +static std::atomic<bool> terminationRequested(false); +void handleSignal(int signum) { terminationRequested = true; } + +int main(int argc, char *argv[]) { + try { + Dune::MPIHelper::instance(argc, argv); + + char buffer[256]; + char *val = getcwd(buffer, sizeof(buffer)); + if (val) { + std::cout << buffer << std::endl; + std::cout << argv[0] << std::endl; + } + + std::ofstream out("foam.log"); + std::streambuf *coutbuf = std::cout.rdbuf(); //save old buffer + std::cout.rdbuf(out.rdbuf()); //redirect std::cout to log.txt + + auto const parset = getParameters(argc, argv); + + using Assembler = MyAssembler<DefLeafGridView, dims>; + using field_type = Matrix::field_type; + + // ---------------------- + // set up contact network + // ---------------------- + TwoBlocksFactory<Grid, Vector> twoBlocksFactory(parset); + using ContactNetwork = typename TwoBlocksFactory<Grid, Vector>::ContactNetwork; + twoBlocksFactory.build(); + + ContactNetwork& contactNetwork = twoBlocksFactory.contactNetwork(); + + /*ThreeBlocksFactory<Grid, Vector> threeBlocksFactory(parset); + using ContactNetwork = typename ThreeBlocksFactory<Grid, Vector>::ContactNetwork; + threeBlocksFactory.build(); + + ContactNetwork& contactNetwork = threeBlocksFactory.contactNetwork(); */ + + const size_t bodyCount = contactNetwork.nBodies(); + + for (size_t i=0; i<contactNetwork.nLevels(); i++) { + // printDofLocation(contactNetwork.body(i)->gridView()); + + //Vector def(contactNetwork.deformedGrids()[i]->size(dims)); + //def = 1; + //deformedGridComplex.setDeformation(def, i); + + const auto& level = *contactNetwork.level(i); + + for (size_t j=0; j<level.nBodies(); j++) { + writeToVTK(level.body(j)->gridView(), "../debug_print/bodies/", "body_" + std::to_string(j) + "_level_" + std::to_string(i)); + } + } + + for (size_t i=0; i<bodyCount; i++) { + writeToVTK(contactNetwork.body(i)->gridView(), "../debug_print/bodies/", "body_" + std::to_string(i) + "_leaf"); + } + + // ---------------------------- + // assemble contactNetwork + // ---------------------------- + contactNetwork.assemble(); + + //printMortarBasis<Vector>(contactNetwork.nBodyAssembler()); + + // ----------------- + // init input/output + // ----------------- + std::vector<size_t> nVertices(bodyCount); + for (size_t i=0; i<bodyCount; i++) { + nVertices[i] = contactNetwork.body(i)->nVertices(); + } + + using MyProgramState = ProgramState<Vector, ScalarVector>; + MyProgramState programState(nVertices); + auto const firstRestart = parset.get<size_t>("io.restarts.first"); + auto const restartSpacing = parset.get<size_t>("io.restarts.spacing"); + auto const writeRestarts = parset.get<bool>("io.restarts.write"); + auto const writeData = parset.get<bool>("io.data.write"); + bool const handleRestarts = writeRestarts or firstRestart > 0; + + + auto dataFile = + writeData ? std::make_unique<HDF5::File>("output.h5") : nullptr; + + auto restartFile = handleRestarts + ? std::make_unique<HDF5::File>( + "restarts.h5", + writeRestarts ? HDF5::Access::READWRITE + : HDF5::Access::READONLY) + : nullptr; + + + auto restartIO = handleRestarts + ? std::make_unique<RestartIO<MyProgramState>>( + *restartFile, nVertices) + : nullptr; + + if (firstRestart > 0) // automatically adjusts the time and timestep + restartIO->read(firstRestart, programState); + else + programState.setupInitialConditions(parset, contactNetwork); + + + //DUNE_THROW(Dune::Exception, "Just need to stop here!"); + + auto& nBodyAssembler = contactNetwork.nBodyAssembler(); + for (size_t i=0; i<bodyCount; i++) { + contactNetwork.body(i)->setDeformation(programState.u[i]); + } + nBodyAssembler.assembleTransferOperator(); + nBodyAssembler.assembleObstacle(); + + // ------------------------ + // assemble global friction + // ------------------------ + contactNetwork.assembleFriction(parset.get<Config::FrictionModel>("boundary.friction.frictionModel"), programState.weightedNormalStress); + + auto& globalFriction = contactNetwork.globalFriction(); + globalFriction.updateAlpha(programState.alpha); + + using MyVertexBasis = typename Assembler::VertexBasis; + using MyCellBasis = typename Assembler::CellBasis; + std::vector<Vector> vertexCoordinates(bodyCount); + std::vector<const MyVertexBasis* > vertexBases(bodyCount); + std::vector<const MyCellBasis* > cellBases(bodyCount); + + auto& wPatches = twoBlocksFactory.weakPatches(); + std::vector<std::vector<const ConvexPolyhedron<LocalVector>*>> weakPatches(bodyCount); + + + for (size_t i=0; i<bodyCount; i++) { + const auto& body = contactNetwork.body(i); + vertexBases[i] = &(body->assembler()->vertexBasis); + cellBases[i] = &(body->assembler()->cellBasis); + + weakPatches[i].resize(1); + weakPatches[i][0] = wPatches[i].get(); + + auto& vertexCoords = vertexCoordinates[i]; + vertexCoords.resize(nVertices[i]); + + Dune::MultipleCodimMultipleGeomTypeMapper< + DefLeafGridView, Dune::MCMGVertexLayout> const vertexMapper(body->gridView(), Dune::mcmgVertexLayout()); + for (auto &&v : vertices(body->gridView())) + vertexCoords[vertexMapper.index(v)] = geoToPoint(v.geometry()); + } + + typename ContactNetwork::BoundaryPatches frictionBoundaries; + contactNetwork.boundaryPatches("friction", frictionBoundaries); + + auto dataWriter = + writeData ? std::make_unique< + HDF5LevelWriter<MyProgramState, MyVertexBasis, DefLeafGridView>>( + *dataFile, vertexCoordinates, vertexBases, + frictionBoundaries, weakPatches) + : nullptr; + + const MyVTKWriter<MyVertexBasis, MyCellBasis> vtkWriter(cellBases, vertexBases, "/storage/mi/podlesny/software/dune/dune-tectonic/body"); + + IterationRegister iterationCount; + + auto const report = [&](bool initial = false) { + if (writeData) { + dataWriter->reportSolution(programState, globalFriction); + if (!initial) + dataWriter->reportIterations(programState, iterationCount); + dataFile->flush(); + } + + if (writeRestarts and !initial and + programState.timeStep % restartSpacing == 0) { + restartIO->write(programState); + restartFile->flush(); + } + + if (parset.get<bool>("io.printProgress")) + std::cout << "timeStep = " << std::setw(6) << programState.timeStep + << ", time = " << std::setw(12) << programState.relativeTime + << ", tau = " << std::setw(12) << programState.relativeTau + << std::endl; + + if (parset.get<bool>("io.vtk.write")) { + std::vector<ScalarVector> stress(bodyCount); + + for (size_t i=0; i<bodyCount; i++) { + const auto& body = contactNetwork.body(i); + body->assembler()->assembleVonMisesStress(body->data()->getYoungModulus(), + body->data()->getPoissonRatio(), + programState.u[i], stress[i]); + + } + + vtkWriter.write(programState.timeStep, programState.u, programState.v, + programState.alpha, stress); + } + }; + report(true); + + // ------------------- + // Set up TNNMG solver + // ------------------- + + BitVector totalDirichletNodes; + contactNetwork.totalNodes("dirichlet", totalDirichletNodes); + + /*for (size_t i=0; i<totalDirichletNodes.size(); i++) { + bool val = false; + for (size_t d=0; d<dims; d++) { + val = val || totalDirichletNodes[i][d]; + } + + totalDirichletNodes[i] = val; + for (size_t d=0; d<dims; d++) { + totalDirichletNodes[i][d] = val; + } + }*/ + + //print(totalDirichletNodes, "totalDirichletNodes:"); + + //using Functional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, field_type>; + using Functional = Functional<Matrix&, Vector&, GlobalFriction<Matrix, Vector>&, Vector&, Vector&, field_type>; + using NonlinearFactory = SolverFactory<Functional, BitVector>; + + using BoundaryFunctions = typename ContactNetwork::BoundaryFunctions; + using BoundaryNodes = typename ContactNetwork::BoundaryNodes; + using Updaters = Updaters<RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>, + StateUpdater<ScalarVector, Vector>>; + + BoundaryFunctions velocityDirichletFunctions; + contactNetwork.boundaryFunctions("dirichlet", velocityDirichletFunctions); + + BoundaryNodes dirichletNodes; + contactNetwork.boundaryNodes("dirichlet", dirichletNodes); + + /*for (size_t i=0; i<dirichletNodes.size(); i++) { + for (size_t j=0; j<dirichletNodes[i].size(); j++) { + print(*dirichletNodes[i][j], "dirichletNodes_body_" + std::to_string(i) + "_boundary_" + std::to_string(j)); + } + }*/ + + std::vector<const Dune::BitSetVector<1>*> frictionNodes; + contactNetwork.frictionNodes(frictionNodes); + + /*for (size_t i=0; i<frictionNodes.size(); i++) { + print(*frictionNodes[i], "frictionNodes_body_" + std::to_string(i)); + }*/ + + Updaters current( + initRateUpdater( + parset.get<Config::scheme>("timeSteps.scheme"), + velocityDirichletFunctions, + dirichletNodes, + contactNetwork.matrices(), + programState.u, + programState.v, + programState.a), + initStateUpdater<ScalarVector, Vector>( + parset.get<Config::stateModel>("boundary.friction.stateModel"), + programState.alpha, + nBodyAssembler.getContactCouplings(), + contactNetwork.couplings()) + ); + + + auto const refinementTolerance = parset.get<double>("timeSteps.refinementTolerance"); + + const auto& stateEnergyNorms = contactNetwork.stateEnergyNorms(); + + auto const mustRefine = [&](Updaters &coarseUpdater, + Updaters &fineUpdater) { + + //return false; + //std::cout << "Step 1" << std::endl; + + std::vector<ScalarVector> coarseAlpha; + coarseAlpha.resize(bodyCount); + coarseUpdater.state_->extractAlpha(coarseAlpha); + + //print(coarseAlpha, "coarseAlpha:"); + + std::vector<ScalarVector> fineAlpha; + fineAlpha.resize(bodyCount); + fineUpdater.state_->extractAlpha(fineAlpha); + + //print(fineAlpha, "fineAlpha:"); + + //std::cout << "Step 3" << std::endl; + + ScalarVector::field_type energyNorm = 0; + for (size_t i=0; i<stateEnergyNorms.size(); i++) { + //std::cout << "for " << i << std::endl; + + //std::cout << not stateEnergyNorms[i] << std::endl; + + if (coarseAlpha[i].size()==0 || fineAlpha[i].size()==0) + continue; + + energyNorm += stateEnergyNorms[i]->diff(fineAlpha[i], coarseAlpha[i]); + } + std::cout << "energy norm: " << energyNorm << " tol: " << refinementTolerance << std::endl; + std::cout << "must refine: " << (energyNorm > refinementTolerance) << std::endl; + return energyNorm > refinementTolerance; + }; + + + std::signal(SIGXCPU, handleSignal); + std::signal(SIGINT, handleSignal); + std::signal(SIGTERM, handleSignal); + +/* + // set patch preconditioner for linear correction in TNNMG method + using PatchSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>; + using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, PatchSolver, Matrix, Vector>; + + const auto& preconditionerParset = parset.sub("solver.tnnmg.linear.preconditioner"); + + auto gsStep = Dune::Solvers::BlockGSStepFactory<Matrix, Vector>::create(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0)); + PatchSolver patchSolver(gsStep, + preconditionerParset.get<size_t>("maximumIterations"), + preconditionerParset.get<double>("tolerance"), + nullptr, + preconditionerParset.get<Solver::VerbosityMode>("verbosity"), + false); // absolute error + + Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), true); + Preconditioner preconditioner(contactNetwork, activeLevels, preconditionerParset.get<Preconditioner::Mode>("mode")); + preconditioner.setPatchSolver(patchSolver); + preconditioner.setPatchDepth(preconditionerParset.get<size_t>("patchDepth")); +*/ + // set adaptive time stepper + typename ContactNetwork::ExternalForces externalForces; + contactNetwork.externalForces(externalForces); + + AdaptiveTimeStepper<NonlinearFactory, std::decay_t<decltype(contactNetwork)>, Updaters, std::decay_t<decltype(stateEnergyNorms)>> + adaptiveTimeStepper(parset, contactNetwork, totalDirichletNodes, globalFriction, frictionNodes, current, + programState.relativeTime, programState.relativeTau, + externalForces, stateEnergyNorms, mustRefine); + + size_t timeSteps = parset.get<size_t>("timeSteps.timeSteps"); + + while (!adaptiveTimeStepper.reachedEnd()) { + programState.timeStep++; + + //preconditioner.build(); + iterationCount = adaptiveTimeStepper.advance(); + + programState.relativeTime = adaptiveTimeStepper.relativeTime_; + programState.relativeTau = adaptiveTimeStepper.relativeTau_; + current.rate_->extractDisplacement(programState.u); + current.rate_->extractVelocity(programState.v); + current.rate_->extractAcceleration(programState.a); + current.state_->extractAlpha(programState.alpha); + globalFriction.updateAlpha(programState.alpha); + + /*print(programState.u, "current u:"); + print(programState.v, "current v:"); + print(programState.a, "current a:"); + print(programState.alpha, "current alpha:");*/ + + contactNetwork.setDeformation(programState.u); + + report(); + + if (programState.timeStep==timeSteps) { + std::cout << "limit of timeSteps reached!" << std::endl; + break; // TODO remove after debugging + } + + if (terminationRequested) { + std::cerr << "Terminating prematurely" << std::endl; + break; + } + + + } + + + std::cout.rdbuf(coutbuf); //reset to standard output again + + } catch (Dune::Exception &e) { + Dune::derr << "Dune reported error: " << e << std::endl; + } catch (std::exception &e) { + std::cerr << "Standard exception: " << e.what() << std::endl; + } +} diff --git a/src/foam/foam.cfg b/src/foam/foam.cfg new file mode 100644 index 00000000..7c801610 --- /dev/null +++ b/src/foam/foam.cfg @@ -0,0 +1,107 @@ +# -*- mode:conf -*- +gravity = 9.81 # [m/s^2] + +[body0] +length = 0.4 # [m] +height = 0.04 # [m] +depth = 0.04 # [m] +bulkModulus = 2190 # [Pa] +poissonRatio = 0.11 # [1] +[body0.elastic] +density = 750 # [kg/m^3] +shearViscosity = 0 # [Pas] +bulkViscosity = 0 # [Pas] +[body0.viscoelastic] +density = 750 # [kg/m^3] +shearViscosity = 0 # [Pas] +bulkViscosity = 0 # [Pas] + +[body1] +length = 0.04 # [m] +height = 0.04 # [m] +depth = 0.04 # [m] +bulkModulus = 2190 # [Pa] +poissonRatio = 0.11 # [1] +[body1.elastic] +density = 750 # [kg/m^3] +shearViscosity = 0 # [Pas] +bulkViscosity = 0 # [Pas] +[body1.viscoelastic] +density = 750 # [kg/m^3] +shearViscosity = 0 # [Pas] +bulkViscosity = 0 # [Pas] + +[boundary.friction] +C = 10 # [Pa] +mu0 = 0.7 # [ ] +V0 = 5e-5 # [m/s] +L = 2.25e-5 # [m] +initialAlpha = 0 # [ ] +stateModel = AgeingLaw +frictionModel = Truncated #Regularised +[boundary.friction.weakening] +a = 0.025 # [ ] +b = 0.005 # [ ] +[boundary.friction.strengthening] +a = 0.025 # [ ] +b = 0.005 # [ ] + +[boundary.neumann] +sigmaN = 0.0 # [Pa] + +[io] +data.write = false +printProgress = true +restarts.first = 0 +restarts.spacing= 20 +restarts.write = false #true +vtk.write = true + +[problem] +finalTime = 1000 # [s] #1000 +bodyCount = 2 + +[initialTime] +timeStep = 0 +relativeTime = 0.0 +relativeTau = 5e-4 # 1e-6 + +[timeSteps] +scheme = newmark +timeSteps = 100000 + +[u0.solver] +maximumIterations = 100 +verbosity = full + +[a0.solver] +maximumIterations = 100 +verbosity = full + +[v.solver] +maximumIterations = 100 +verbosity = quiet + +[v.fpi] +maximumIterations = 10000 +lambda = 0.5 + +[solver.tnnmg.preconditioner] +mode = additive +patchDepth = 1 +maximumIterations = 2 +verbosity = quiet +[solver.tnnmg.preconditioner.patchsolver] +maximumIterations = 100 +verbosity = quiet +[solver.tnnmg.preconditioner.basesolver] +maximumIterations = 10000 +verbosity = quiet + +[solver.tnnmg.main] +pre = 1 +multi = 5 # number of multigrid steps +post = 0 + + + diff --git a/src/multi-body-problem-data/geometry.tex b/src/multi-body-problem-data/geometry.tex deleted file mode 100644 index 32d63b6e..00000000 --- a/src/multi-body-problem-data/geometry.tex +++ /dev/null @@ -1,68 +0,0 @@ -\documentclass[tikz]{minimal} - -\usepackage{tikz} -\usetikzlibrary{calc} -\usetikzlibrary{decorations.pathreplacing} - -\usepackage{siunitx} - -\begin{document} -\pgfmathsetmacro{\rightleg}{0.27} -\pgfmathsetmacro{\leftleg}{1.00} -\pgfmathsetmacro{\leftangle}{atan(\rightleg/\leftleg)} -\begin{tikzpicture}[scale=12, rotate=\leftangle] - \pgfmathsetmacro{\mysin}{sin(\leftangle)} - \pgfmathsetmacro{\mycos}{cos(\leftangle)} - \pgfmathsetmacro{\viscoheight}{0.06} - \pgfmathsetmacro{\Zx}{0.35} - \pgfmathsetmacro{\weaklen}{0.20} - - \coordinate (A) at (0,0); - \node at (A) [left] {A}; - \coordinate (B) at (\leftleg,-\rightleg); - \node at (B) [right] {B}; - \coordinate (C) at (\leftleg,0); - \node at (C) [right] {C}; - - \draw (A) -- (B) -- (C) -- node [above=.5cm, sloped] {$\overline{AC}=\SI{100}{cm}$} (A); - - \coordinate (Z) at (\Zx,0); - \node at (Z) [above] {Z}; - \coordinate (Y) at ($(\Zx,-\Zx/\leftleg * \rightleg)$); - \node at (Y) [below] {Y}; - \coordinate (X) at ($(Y) + (-\weaklen*\mycos,\weaklen*\mysin)$); - \node at (X) [below] {X}; - \path let \p1 = (X) in coordinate (U) at ($(\x1, 0)$); - \node at (U) [above] {U}; - - \path (A) -- node [above=.25cm, sloped] {$\overline{AZ} = \SI{35}{cm}$} (Z); - - \draw[color=red, thick] (X) -- node [below=.25cm] {$\overline{XY}=\SI{20}{cm}$} (Y); - \draw[dashed] (Y) -- (Z); - \draw[dashed] (U) -- (X); - - \coordinate (K) at ($(B) + (-\leftleg * \viscoheight / \rightleg,\viscoheight)$); - \node at (K) [below] {K}; - \coordinate (M) at ($(B) + (0, \viscoheight)$); - \node at (M) [right] {M}; - \path (C) -- node [right=.5cm] {$\overline{CM} = \SI{21}{cm}$} (M); - - \path[fill=blue] (K) -- (B) -- node [right=.75cm] {$\overline{BM}=\SI{6}{cm}$} (M) -- cycle; - - \coordinate (G) at ($(A) ! 0.5 ! (X)$); - \node at (G) [below] {G}; - \coordinate (H) at ($(X) ! 0.5 ! (Y)$); - \node at (H) [below] {H}; - \coordinate (J) at ($(Y) ! 0.5 ! (B)$); - \node at (J) [below] {J}; - - \coordinate (I) at ($(Y) + (G)$); - \node at (I) [below] {I}; - - \node[align=left] at (0.5,-0.225) { - $Z$: coast line\\ - $\overline{XY}$: velocity weakening zone\\ - $BKM$: visco-elastic domain}; -\end{tikzpicture} - -\end{document} diff --git a/src/multi-body-problem/CMakeLists.txt b/src/multi-body-problem/CMakeLists.txt new file mode 100644 index 00000000..15a48074 --- /dev/null +++ b/src/multi-body-problem/CMakeLists.txt @@ -0,0 +1,46 @@ +add_custom_target(tectonic_src_multi-body-problem SOURCES + multi-body-problem.cfg + multi-body-problem-2D.cfg + multi-body-problem-3D.cfg +) + +set(MSW_SOURCE_FILES + ../../dune/tectonic/assemblers.cc + ../../dune/tectonic/data-structures/body/body.cc + ../../dune/tectonic/data-structures/network/levelcontactnetwork.cc + ../../dune/tectonic/data-structures/network/contactnetwork.cc + ../../dune/tectonic/data-structures/enumparser.cc + #../../dune/tectonic/factories/cantorfactory.cc + ../../dune/tectonic/factories/threeblocksfactory.cc + ../../dune/tectonic/factories/stackedblocksfactory.cc + ../../dune/tectonic/io/vtk.cc + ../../dune/tectonic/io/hdf5/frictionalboundary-writer.cc + ../../dune/tectonic/io/hdf5/iteration-writer.cc + #../../dune/tectonic/io/hdf5/patchinfo-writer.cc + ../../dune/tectonic/io/hdf5/restart-io.cc + ../../dune/tectonic/io/hdf5/surface-writer.cc + ../../dune/tectonic/io/hdf5/time-writer.cc + ../../dune/tectonic/problem-data/grid/cuboidgeometry.cc + ../../dune/tectonic/problem-data/grid/mygrids.cc + ../../dune/tectonic/problem-data/grid/simplexmanager.cc + ../../dune/tectonic/spatial-solving/solverfactory.cc + ../../dune/tectonic/spatial-solving/fixedpointiterator.cc + ../../dune/tectonic/time-stepping/coupledtimestepper.cc + ../../dune/tectonic/time-stepping/adaptivetimestepper.cc + ../../dune/tectonic/time-stepping/rate.cc + ../../dune/tectonic/time-stepping/rate/rateupdater.cc + ../../dune/tectonic/time-stepping/state.cc + multi-body-problem.cc +) + +foreach(_dim 2 3) + set(_msw_target multi-body-problem-${_dim}D) + + add_executable(${_msw_target} ${MSW_SOURCE_FILES}) + + add_dune_ug_flags(${_msw_target}) + add_dune_hdf5_flags(${_msw_target}) + + set_property(TARGET ${_msw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}") + #set_property(TARGET ${_msw_target} APPEND PROPERTY COMPILE_DEFINITIONS "NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY=1") +endforeach() diff --git a/src/multi-body-problem-2D.cfg b/src/multi-body-problem/multi-body-problem-2D.cfg similarity index 64% rename from src/multi-body-problem-2D.cfg rename to src/multi-body-problem/multi-body-problem-2D.cfg index 4f122195..641078a7 100644 --- a/src/multi-body-problem-2D.cfg +++ b/src/multi-body-problem/multi-body-problem-2D.cfg @@ -1,6 +1,6 @@ # -*- mode:conf -*- [boundary.friction] -smallestDiameter = 0.5 # 2e-3 [m] +smallestDiameter = 0.05 # 2e-3 [m] [timeSteps] refinementTolerance = 1e-5 # 1e-5 @@ -17,8 +17,8 @@ tolerance = 1e-8 [v.fpi] tolerance = 1e-5 -[solver.tnnmg.linear] -tolerance = 1e-8 #1e-10 +[solver.tnnmg.preconditioner.basesolver] +tolerance = 1e-10 -[solver.tnnmg.linear.preconditioner] +[solver.tnnmg.preconditioner.patchsolver] tolerance = 1e-10 diff --git a/src/multi-body-problem-3D.cfg b/src/multi-body-problem/multi-body-problem-3D.cfg similarity index 100% rename from src/multi-body-problem-3D.cfg rename to src/multi-body-problem/multi-body-problem-3D.cfg diff --git a/src/multi-body-problem.cc b/src/multi-body-problem/multi-body-problem.cc similarity index 81% rename from src/multi-body-problem.cc rename to src/multi-body-problem/multi-body-problem.cc index 4582a652..715acca3 100644 --- a/src/multi-body-problem.cc +++ b/src/multi-body-problem/multi-body-problem.cc @@ -29,6 +29,7 @@ #include <dune/istl/bvector.hh> #include <dune/fufem/boundarypatch.hh> +#include <dune/fufem/geometry/convexpolyhedron.hh> #include <dune/fufem/formatstring.hh> #include <dune/fufem/hdf5/file.hh> @@ -40,44 +41,43 @@ #include <dune/contact/common/couplingpair.hh> #include <dune/contact/projections/normalprojection.hh> -#include <dune/tectonic/geocoordinate.hh> -#include <dune/tectonic/globalfriction.hh> -#include "assemblers.hh" -#include "gridselector.hh" -#include "explicitgrid.hh" -#include "explicitvectors.hh" +#include <dune/tectonic/assemblers.hh> +#include <dune/tectonic/gridselector.hh> +#include <dune/tectonic/explicitgrid.hh> +#include <dune/tectonic/explicitvectors.hh> -#include "data-structures/enumparser.hh" -#include "data-structures/enums.hh" -#include "data-structures/contactnetwork.hh" -#include "data-structures/matrices.hh" -#include "data-structures/program_state.hh" +#include <dune/tectonic/data-structures/enumparser.hh> +#include <dune/tectonic/data-structures/enums.hh> +#include <dune/tectonic/data-structures/network/contactnetwork.hh> +#include <dune/tectonic/data-structures/matrices.hh> +#include <dune/tectonic/data-structures/program_state.hh> +#include <dune/tectonic/data-structures/friction/globalfriction.hh> -#include "factories/stackedblocksfactory.hh" -#include "factories/threeblocksfactory.hh" +#include <dune/tectonic/factories/stackedblocksfactory.hh> +#include <dune/tectonic/factories/threeblocksfactory.hh> -//#include "io/hdf5-levelwriter.hh" -#include "io/hdf5/restart-io.hh" -#include "io/vtk.hh" +#include <dune/tectonic/io/hdf5-levelwriter.hh> +#include <dune/tectonic/io/hdf5/restart-io.hh> +#include <dune/tectonic/io/vtk.hh> -#include "multi-body-problem-data/bc.hh" -#include "multi-body-problem-data/mybody.hh" -#include "multi-body-problem-data/grid/mygrids.hh" +#include <dune/tectonic/problem-data/bc.hh> +#include <dune/tectonic/problem-data/mybody.hh> +#include <dune/tectonic/problem-data/grid/mygrids.hh> -#include "spatial-solving/tnnmg/functional.hh" -//#include "spatial-solving/preconditioners/multilevelpatchpreconditioner.hh" -#include "spatial-solving/tnnmg/localbisectionsolver.hh" -#include "spatial-solving/contact/nbodyassembler.hh" -#include "spatial-solving/solverfactory.hh" +#include <dune/tectonic/spatial-solving/tnnmg/functional.hh> +//#include <dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh> +#include <dune/tectonic/spatial-solving/tnnmg/localbisectionsolver.hh> +#include <dune/tectonic/spatial-solving/solverfactory.hh> -#include "time-stepping/adaptivetimestepper.hh" -#include "time-stepping/rate.hh" -#include "time-stepping/state.hh" -#include "time-stepping/updaters.hh" +#include <dune/tectonic/time-stepping/adaptivetimestepper.hh> +#include <dune/tectonic/time-stepping/rate.hh> +#include <dune/tectonic/time-stepping/state.hh> +#include <dune/tectonic/time-stepping/updaters.hh> -#include "utils/debugutils.hh" -#include "utils/diameter.hh" +#include <dune/tectonic/utils/debugutils.hh> +#include <dune/tectonic/utils/diameter.hh> +#include <dune/tectonic/utils/geocoordinate.hh> // for getcwd #include <unistd.h> @@ -89,9 +89,9 @@ size_t const dims = MY_DIM; Dune::ParameterTree getParameters(int argc, char *argv[]) { Dune::ParameterTree parset; - Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem.cfg", parset); + Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem/multi-body-problem.cfg", parset); Dune::ParameterTreeParser::readINITree( - Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem-%dD.cfg", dims), parset); + Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem/multi-body-problem-%dD.cfg", dims), parset); Dune::ParameterTreeParser::readOptions(argc, argv, parset); return parset; } @@ -146,12 +146,12 @@ int main(int argc, char *argv[]) { const auto& level = *contactNetwork.level(i); for (size_t j=0; j<level.nBodies(); j++) { - writeToVTK(level.body(j)->gridView(), "debug_print/bodies/", "body_" + std::to_string(j) + "_level_" + std::to_string(i)); + writeToVTK(level.body(j)->gridView(), "../debug_print/bodies/", "body_" + std::to_string(j) + "_level_" + std::to_string(i)); } } for (size_t i=0; i<bodyCount; i++) { - writeToVTK(contactNetwork.body(i)->gridView(), "debug_print/bodies/", "body_" + std::to_string(i) + "_leaf"); + writeToVTK(contactNetwork.body(i)->gridView(), "../debug_print/bodies/", "body_" + std::to_string(i) + "_leaf"); } // ---------------------------- @@ -223,11 +223,18 @@ int main(int argc, char *argv[]) { std::vector<const MyVertexBasis* > vertexBases(bodyCount); std::vector<const MyCellBasis* > cellBases(bodyCount); + auto& wPatches = stackedBlocksFactory.weakPatches(); + std::vector<std::vector<const ConvexPolyhedron<LocalVector>*>> weakPatches(bodyCount); + + for (size_t i=0; i<bodyCount; i++) { const auto& body = contactNetwork.body(i); vertexBases[i] = &(body->assembler()->vertexBasis); cellBases[i] = &(body->assembler()->cellBasis); + weakPatches[i].resize(1); + weakPatches[i][0] = wPatches[i].get(); + auto& vertexCoords = vertexCoordinates[i]; vertexCoords.resize(nVertices[i]); @@ -237,24 +244,23 @@ int main(int argc, char *argv[]) { vertexCoords[vertexMapper.index(v)] = geoToPoint(v.geometry()); } - //typename contactNetwork::BoundaryPatches frictionBoundaries; - //contactNetwork.boundaryPatches("friction", frictionBoundaries); + typename ContactNetwork::BoundaryPatches frictionBoundaries; + contactNetwork.boundaryPatches("friction", frictionBoundaries); - /* auto dataWriter = writeData ? std::make_unique< - HDF5Writer<MyProgramState, MyVertexBasis, DefLeafGridView>>( + HDF5LevelWriter<MyProgramState, MyVertexBasis, DefLeafGridView>>( *dataFile, vertexCoordinates, vertexBases, - frictionBoundaries) //, weakPatches) - : nullptr;*/ + frictionBoundaries, weakPatches) + : nullptr; const MyVTKWriter<MyVertexBasis, MyCellBasis> vtkWriter(cellBases, vertexBases, "/storage/mi/podlesny/software/dune/dune-tectonic/body"); IterationRegister iterationCount; auto const report = [&](bool initial = false) { - /*if (writeData) { - dataWriter->reportSolution(programState, contactNetwork.globalFriction()); + if (writeData) { + dataWriter->reportSolution(programState, globalFriction); if (!initial) dataWriter->reportIterations(programState, iterationCount); dataFile->flush(); @@ -264,7 +270,7 @@ int main(int argc, char *argv[]) { programState.timeStep % restartSpacing == 0) { restartIO->write(programState); restartFile->flush(); - }*/ + } if (parset.get<bool>("io.printProgress")) std::cout << "timeStep = " << std::setw(6) << programState.timeStep @@ -308,7 +314,7 @@ int main(int argc, char *argv[]) { } }*/ - print(totalDirichletNodes, "totalDirichletNodes:"); + //print(totalDirichletNodes, "totalDirichletNodes:"); //using Functional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, field_type>; using Functional = Functional<Matrix&, Vector&, GlobalFriction<Matrix, Vector>&, Vector&, Vector&, field_type>; @@ -334,9 +340,9 @@ int main(int argc, char *argv[]) { std::vector<const Dune::BitSetVector<1>*> frictionNodes; contactNetwork.frictionNodes(frictionNodes); - for (size_t i=0; i<frictionNodes.size(); i++) { + /*for (size_t i=0; i<frictionNodes.size(); i++) { print(*frictionNodes[i], "frictionNodes_body_" + std::to_string(i)); - } + }*/ Updaters current( initRateUpdater( @@ -363,27 +369,27 @@ int main(int argc, char *argv[]) { Updaters &fineUpdater) { //return false; - std::cout << "Step 1" << std::endl; + //std::cout << "Step 1" << std::endl; std::vector<ScalarVector> coarseAlpha; coarseAlpha.resize(bodyCount); coarseUpdater.state_->extractAlpha(coarseAlpha); - print(coarseAlpha, "coarseAlpha:"); + //print(coarseAlpha, "coarseAlpha:"); std::vector<ScalarVector> fineAlpha; fineAlpha.resize(bodyCount); fineUpdater.state_->extractAlpha(fineAlpha); - print(fineAlpha, "fineAlpha:"); + //print(fineAlpha, "fineAlpha:"); - std::cout << "Step 3" << std::endl; + //std::cout << "Step 3" << std::endl; ScalarVector::field_type energyNorm = 0; for (size_t i=0; i<stateEnergyNorms.size(); i++) { - std::cout << "for " << i << std::endl; + //std::cout << "for " << i << std::endl; - std::cout << not stateEnergyNorms[i] << std::endl; + //std::cout << not stateEnergyNorms[i] << std::endl; if (coarseAlpha[i].size()==0 || fineAlpha[i].size()==0) continue; @@ -429,6 +435,8 @@ int main(int argc, char *argv[]) { programState.relativeTime, programState.relativeTau, externalForces, stateEnergyNorms, mustRefine); + size_t timeSteps = parset.get<size_t>("timeSteps.timeSteps"); + while (!adaptiveTimeStepper.reachedEnd()) { programState.timeStep++; @@ -441,17 +449,18 @@ int main(int argc, char *argv[]) { current.rate_->extractVelocity(programState.v); current.rate_->extractAcceleration(programState.a); current.state_->extractAlpha(programState.alpha); + globalFriction.updateAlpha(programState.alpha); - print(programState.u, "current u:"); + /*print(programState.u, "current u:"); print(programState.v, "current v:"); print(programState.a, "current a:"); - print(programState.alpha, "current alpha:"); + print(programState.alpha, "current alpha:");*/ contactNetwork.setDeformation(programState.u); report(); - if (programState.timeStep==50) { + if (programState.timeStep==timeSteps) { std::cout << "limit of timeSteps reached!" << std::endl; break; // TODO remove after debugging } @@ -460,6 +469,8 @@ int main(int argc, char *argv[]) { std::cerr << "Terminating prematurely" << std::endl; break; } + + } diff --git a/src/multi-body-problem.cfg b/src/multi-body-problem/multi-body-problem.cfg similarity index 80% rename from src/multi-body-problem.cfg rename to src/multi-body-problem/multi-body-problem.cfg index eaade420..4be02c1c 100644 --- a/src/multi-body-problem.cfg +++ b/src/multi-body-problem/multi-body-problem.cfg @@ -2,7 +2,7 @@ gravity = 9.81 # [m/s^2] [io] -data.write = false #true +data.write = false printProgress = true restarts.first = 0 restarts.spacing= 20 @@ -10,7 +10,7 @@ restarts.write = false #true vtk.write = true [problem] -finalTime = 100 # [s] #1000 +finalTime = 10000 # [s] #1000 bodyCount = 2 [body] @@ -43,11 +43,11 @@ b = 0.005 # [ ] [initialTime] timeStep = 0 relativeTime = 0.0 -relativeTau = 1e-4 # 1e-6 +relativeTau = 5e-4 # 1e-6 [timeSteps] scheme = newmark -timeSteps = 1 +timeSteps = 100000 [u0.solver] maximumIterations = 100 @@ -59,20 +59,21 @@ verbosity = full [v.solver] maximumIterations = 100 -verbosity = full +verbosity = quiet [v.fpi] maximumIterations = 10000 lambda = 0.5 -[solver.tnnmg.linear] -maximumIterations = 100 -pre = 3 -cycle = 1 # 1 = V, 2 = W, etc. -post = 3 -[solver.tnnmg.linear.preconditioner] +[solver.tnnmg.preconditioner] mode = additive -patchDepth = 0 +patchDepth = 1 +maximumIterations = 2 +verbosity = quiet +[solver.tnnmg.preconditioner.patchsolver] +maximumIterations = 100 +verbosity = quiet +[solver.tnnmg.preconditioner.basesolver] maximumIterations = 10000 verbosity = quiet diff --git a/src/one-body-problem-3D.cfg b/src/one-body-problem-3D.cfg deleted file mode 100644 index 3ff0794d..00000000 --- a/src/one-body-problem-3D.cfg +++ /dev/null @@ -1,24 +0,0 @@ -# -*- mode:conf -*- -[boundary.friction] -smallestDiameter= 2e-2 # [m] - -[boundary.friction.weakening] -patchType = Trapezoidal - -[timeSteps] -refinementTolerance = 1e-5 - -[u0.solver] -tolerance = 1e-6 - -[a0.solver] -tolerance = 1e-6 - -[v.solver] -tolerance = 1e-6 - -[v.fpi] -tolerance = 1e-5 - -[solver.tnnmg.linear] -tolerance = 1e-10 diff --git a/src/one-body-problem-data/bc.hh b/src/one-body-problem-data/bc.hh deleted file mode 100644 index 7c29cf08..00000000 --- a/src/one-body-problem-data/bc.hh +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SRC_ONE_BODY_PROBLEM_DATA_BC_HH -#define SRC_ONE_BODY_PROBLEM_DATA_BC_HH - -class VelocityDirichletCondition - : public Dune::VirtualFunction<double, double> { - void evaluate(double const &relativeTime, double &y) const { - // Assumed to vanish at time zero - double const finalVelocity = -5e-5; - y = (relativeTime <= 0.1) - ? finalVelocity * (1.0 - std::cos(relativeTime * M_PI / 0.1)) / 2.0 - : finalVelocity; - } -}; - -class NeumannCondition : public Dune::VirtualFunction<double, double> { - void evaluate(double const &relativeTime, double &y) const { y = 0.0; } -}; -#endif diff --git a/src/one-body-problem-data/geometry.tex b/src/one-body-problem-data/geometry.tex deleted file mode 100644 index 32d63b6e..00000000 --- a/src/one-body-problem-data/geometry.tex +++ /dev/null @@ -1,68 +0,0 @@ -\documentclass[tikz]{minimal} - -\usepackage{tikz} -\usetikzlibrary{calc} -\usetikzlibrary{decorations.pathreplacing} - -\usepackage{siunitx} - -\begin{document} -\pgfmathsetmacro{\rightleg}{0.27} -\pgfmathsetmacro{\leftleg}{1.00} -\pgfmathsetmacro{\leftangle}{atan(\rightleg/\leftleg)} -\begin{tikzpicture}[scale=12, rotate=\leftangle] - \pgfmathsetmacro{\mysin}{sin(\leftangle)} - \pgfmathsetmacro{\mycos}{cos(\leftangle)} - \pgfmathsetmacro{\viscoheight}{0.06} - \pgfmathsetmacro{\Zx}{0.35} - \pgfmathsetmacro{\weaklen}{0.20} - - \coordinate (A) at (0,0); - \node at (A) [left] {A}; - \coordinate (B) at (\leftleg,-\rightleg); - \node at (B) [right] {B}; - \coordinate (C) at (\leftleg,0); - \node at (C) [right] {C}; - - \draw (A) -- (B) -- (C) -- node [above=.5cm, sloped] {$\overline{AC}=\SI{100}{cm}$} (A); - - \coordinate (Z) at (\Zx,0); - \node at (Z) [above] {Z}; - \coordinate (Y) at ($(\Zx,-\Zx/\leftleg * \rightleg)$); - \node at (Y) [below] {Y}; - \coordinate (X) at ($(Y) + (-\weaklen*\mycos,\weaklen*\mysin)$); - \node at (X) [below] {X}; - \path let \p1 = (X) in coordinate (U) at ($(\x1, 0)$); - \node at (U) [above] {U}; - - \path (A) -- node [above=.25cm, sloped] {$\overline{AZ} = \SI{35}{cm}$} (Z); - - \draw[color=red, thick] (X) -- node [below=.25cm] {$\overline{XY}=\SI{20}{cm}$} (Y); - \draw[dashed] (Y) -- (Z); - \draw[dashed] (U) -- (X); - - \coordinate (K) at ($(B) + (-\leftleg * \viscoheight / \rightleg,\viscoheight)$); - \node at (K) [below] {K}; - \coordinate (M) at ($(B) + (0, \viscoheight)$); - \node at (M) [right] {M}; - \path (C) -- node [right=.5cm] {$\overline{CM} = \SI{21}{cm}$} (M); - - \path[fill=blue] (K) -- (B) -- node [right=.75cm] {$\overline{BM}=\SI{6}{cm}$} (M) -- cycle; - - \coordinate (G) at ($(A) ! 0.5 ! (X)$); - \node at (G) [below] {G}; - \coordinate (H) at ($(X) ! 0.5 ! (Y)$); - \node at (H) [below] {H}; - \coordinate (J) at ($(Y) ! 0.5 ! (B)$); - \node at (J) [below] {J}; - - \coordinate (I) at ($(Y) + (G)$); - \node at (I) [below] {I}; - - \node[align=left] at (0.5,-0.225) { - $Z$: coast line\\ - $\overline{XY}$: velocity weakening zone\\ - $BKM$: visco-elastic domain}; -\end{tikzpicture} - -\end{document} diff --git a/src/one-body-problem-data/midpoint.hh b/src/one-body-problem-data/midpoint.hh deleted file mode 100644 index 407b55f9..00000000 --- a/src/one-body-problem-data/midpoint.hh +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SRC_MIDPOINT_HH -#define SRC_MIDPOINT_HH - -#include <dune/solvers/common/arithmetic.hh> - -template <class Vector> Vector midPoint(Vector const &x, Vector const &y) { - Vector ret(0); - Arithmetic::addProduct(ret, 0.5, x); - Arithmetic::addProduct(ret, 0.5, y); - return ret; -} -#endif diff --git a/src/one-body-problem-data/mybody.hh b/src/one-body-problem-data/mybody.hh deleted file mode 100644 index 6e98d289..00000000 --- a/src/one-body-problem-data/mybody.hh +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef SRC_ONE_BODY_PROBLEM_DATA_MYBODY_HH -#define SRC_ONE_BODY_PROBLEM_DATA_MYBODY_HH - -#include <dune/common/fvector.hh> - -#include <dune/fufem/functions/constantfunction.hh> - -#include <dune/tectonic/body.hh> -#include <dune/tectonic/gravity.hh> - -#include "mygeometry.hh" -#include "segmented-function.hh" - -template <int dimension> class MyBody : public Body<dimension> { - using typename Body<dimension>::ScalarFunction; - using typename Body<dimension>::VectorField; - -public: - MyBody(Dune::ParameterTree const &parset) - : poissonRatio_(parset.get<double>("body.poissonRatio")), - youngModulus_(3.0 * parset.get<double>("body.bulkModulus") * - (1.0 - 2.0 * poissonRatio_)), - shearViscosityField_( - parset.get<double>("body.elastic.shearViscosity"), - parset.get<double>("body.viscoelastic.shearViscosity")), - bulkViscosityField_( - parset.get<double>("body.elastic.bulkViscosity"), - parset.get<double>("body.viscoelastic.bulkViscosity")), - densityField_(parset.get<double>("body.elastic.density"), - parset.get<double>("body.viscoelastic.density")), - gravityField_(densityField_, MyGeometry::zenith, - parset.get<double>("gravity")) {} - - double getPoissonRatio() const override { return poissonRatio_; } - double getYoungModulus() const override { return youngModulus_; } - ScalarFunction const &getShearViscosityField() const override { - return shearViscosityField_; - } - ScalarFunction const &getBulkViscosityField() const override { - return bulkViscosityField_; - } - ScalarFunction const &getDensityField() const override { - return densityField_; - } - VectorField const &getGravityField() const override { return gravityField_; } - -private: - double const poissonRatio_; - double const youngModulus_; - SegmentedFunction const shearViscosityField_; - SegmentedFunction const bulkViscosityField_; - SegmentedFunction const densityField_; - Gravity<dimension> const gravityField_; -}; -#endif diff --git a/src/one-body-problem-data/mygeometry.cc b/src/one-body-problem-data/mygeometry.cc deleted file mode 100644 index fef8452a..00000000 --- a/src/one-body-problem-data/mygeometry.cc +++ /dev/null @@ -1,158 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <fstream> - -#ifdef HAVE_CAIROMM -#include <cairomm/context.h> -#include <cairomm/fontface.h> -#include <cairomm/surface.h> -#endif - -#include "mygeometry.hh" - -void MyGeometry::write() { - std::fstream writer("geometry", std::fstream::out); - writer << "A = " << A << std::endl; - writer << "B = " << B << std::endl; - writer << "C = " << C << std::endl; - writer << "Y = " << Y << std::endl; - writer << "X = " << X << std::endl; - writer << "Z = " << Z << std::endl; - writer << "U = " << U << std::endl; - writer << "K = " << K << std::endl; - writer << "M = " << M << std::endl; - writer << "G = " << G << std::endl; - writer << "H = " << H << std::endl; - writer << "J = " << J << std::endl; - writer << "I = " << I << std::endl; - writer << "zenith = " << zenith << std::endl; -} - -void MyGeometry::render() { -#ifdef HAVE_CAIROMM - std::string const filename = "geometry.png"; - double const width = 600; - double const height = 400; - double const widthScale = 400; - double const heightScale = 400; - - auto surface = - Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height); - auto cr = Cairo::Context::create(surface); - - auto const setRGBColor = [&](int colour) { - cr->set_source_rgb(((colour & 0xFF0000) >> 16) / 255.0, - ((colour & 0x00FF00) >> 8) / 255.0, - ((colour & 0x0000FF) >> 0) / 255.0); - }; - auto const moveTo = [&](LocalVector2D const &v) { cr->move_to(v[0], -v[1]); }; - auto const lineTo = [&](LocalVector2D const &v) { cr->line_to(v[0], -v[1]); }; - - cr->scale(widthScale, heightScale); - cr->translate(0.1, 0.1); - cr->set_line_width(0.0025); - - // triangle - { - moveTo(reference::A); - lineTo(reference::B); - lineTo(reference::C); - cr->close_path(); - cr->stroke(); - } - - // dashed lines - { - cr->save(); - std::vector<double> dashPattern = { 0.005 }; - cr->set_dash(dashPattern, 0); - moveTo(reference::Z); - lineTo(reference::Y); - moveTo(reference::U); - lineTo(reference::X); - cr->stroke(); - cr->restore(); - } - - // fill viscoelastic region - { - cr->save(); - setRGBColor(0x0097E0); - moveTo(reference::B); - lineTo(reference::K); - lineTo(reference::M); - cr->fill(); - cr->restore(); - } - - // mark weakening region - { - cr->save(); - setRGBColor(0x7AD3FF); - cr->set_line_width(0.005); - moveTo(reference::X); - lineTo(reference::Y); - cr->stroke(); - cr->restore(); - } - - // mark points - { - auto const drawCircle = [&](LocalVector2D const &v) { - cr->arc(v[0], -v[1], 0.0075, -M_PI, M_PI); // x,y,radius,angle1,angle2 - cr->fill(); - }; - - cr->save(); - setRGBColor(0x002F47); - drawCircle(reference::A); - drawCircle(reference::B); - drawCircle(reference::C); - drawCircle(reference::Y); - drawCircle(reference::X); - drawCircle(reference::Z); - drawCircle(reference::U); - drawCircle(reference::K); - drawCircle(reference::M); - drawCircle(reference::G); - drawCircle(reference::H); - drawCircle(reference::J); - drawCircle(reference::I); - cr->restore(); - } - - // labels - { - auto const label = [&](LocalVector2D const &v, std::string l) { - moveTo(v); - cr->rel_move_to(0.005, -0.02); - cr->show_text(l); - }; - auto font = Cairo::ToyFontFace::create( - "monospace", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL); - - cr->save(); - cr->set_font_face(font); - cr->set_font_size(0.03); - - label(reference::A, "A"); - label(reference::B, "B"); - label(reference::C, "C"); - label(reference::K, "K"); - label(reference::M, "M"); - label(reference::U, "U"); - label(reference::X, "X"); - label(reference::Y, "Y"); - label(reference::Z, "Z"); - label(reference::G, "G"); - label(reference::H, "H"); - label(reference::J, "J"); - label(reference::I, "I"); - cr->restore(); - } - - surface->write_to_png(filename); -#endif -} diff --git a/src/one-body-problem-data/mygeometry.hh b/src/one-body-problem-data/mygeometry.hh deleted file mode 100644 index dbfa722a..00000000 --- a/src/one-body-problem-data/mygeometry.hh +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef SRC_MYGEOMETRY_HH -#define SRC_MYGEOMETRY_HH - -#include <dune/common/fvector.hh> - -#include "midpoint.hh" - -namespace MyGeometry { -namespace { - using LocalVector2D = Dune::FieldVector<double, 2>; - using LocalMatrix2D = Dune::FieldMatrix<double, 2, 2>; - - using LocalVector = Dune::FieldVector<double, MY_DIM>; -} - -namespace reference { - double const s = 1.0; // scaling factor - - double const rightLeg = 0.27 * s; - double const leftLeg = 1.00 * s; - double const leftAngle = atan(rightLeg / leftLeg); - double const viscoHeight = 0.06 * s; // Height of the viscous bottom layer - double const weakLen = 0.20 * s; // Length of the weak zone - - double const zDistance = 0.35; - - LocalVector2D const A = {0, 0}; - LocalVector2D const B = {leftLeg, -rightLeg}; - LocalVector2D const C = {leftLeg, 0}; - - LocalVector2D const Z = {zDistance * s, 0}; - LocalVector2D const Y = {zDistance * s, -zDistance *s / leftLeg *rightLeg}; - LocalVector2D const X = {Y[0] - weakLen * std::cos(leftAngle), - Y[1] + weakLen *std::sin(leftAngle)}; - - LocalVector2D const U = {X[0], 0}; - - LocalVector2D const K = {B[0] - leftLeg * viscoHeight / rightLeg, - B[1] + viscoHeight}; - LocalVector2D const M = {B[0], B[1] + viscoHeight}; - - LocalVector2D const G = midPoint(A, X); - LocalVector2D const H = midPoint(X, Y); - LocalVector2D const J = midPoint(Y, B); - - LocalVector2D const I = {Y[0] + G[0], Y[1] + G[1]}; - - LocalVector2D const zenith = {0, 1}; - - LocalMatrix2D const rotation = {{std::cos(leftAngle), -std::sin(leftAngle)}, - {std::sin(leftAngle), std::cos(leftAngle)}}; -} - -namespace { - LocalVector rotate(LocalVector2D const &x) { - LocalVector2D ret2D; - reference::rotation.mv(x, ret2D); - LocalVector ret(0); - ret[0] = ret2D[0]; - ret[1] = ret2D[1]; - return ret; - } -} - -double const lengthScale = reference::s; - -double const depth = 0.60 * lengthScale; - -LocalVector const A = rotate(reference::A); -LocalVector const B = rotate(reference::B); -LocalVector const C = rotate(reference::C); -LocalVector const G = rotate(reference::G); -LocalVector const H = rotate(reference::H); -LocalVector const I = rotate(reference::I); -LocalVector const J = rotate(reference::J); -LocalVector const K = rotate(reference::K); -LocalVector const M = rotate(reference::M); -LocalVector const U = rotate(reference::U); -LocalVector const X = rotate(reference::X); -LocalVector const Y = rotate(reference::Y); -LocalVector const Z = rotate(reference::Z); - -LocalVector const zenith = rotate(reference::zenith); - -void write(); - -void render(); -} -#endif diff --git a/src/one-body-problem-data/myglobalfrictiondata.hh b/src/one-body-problem-data/myglobalfrictiondata.hh deleted file mode 100644 index d92e7223..00000000 --- a/src/one-body-problem-data/myglobalfrictiondata.hh +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef SRC_ONE_BODY_PROBLEM_DATA_MYGLOBALFRICTIONDATA_HH -#define SRC_ONE_BODY_PROBLEM_DATA_MYGLOBALFRICTIONDATA_HH - -#include <dune/common/function.hh> - -#include <dune/tectonic/globalfrictiondata.hh> - -#include "patchfunction.hh" - -template <class LocalVector> -class MyGlobalFrictionData : public GlobalFrictionData<LocalVector::dimension> { -private: - using typename GlobalFrictionData<LocalVector::dimension>::VirtualFunction; - -public: - MyGlobalFrictionData(Dune::ParameterTree const &parset, - ConvexPolyhedron<LocalVector> const &segment) - : C_(parset.get<double>("C")), - L_(parset.get<double>("L")), - V0_(parset.get<double>("V0")), - a_(parset.get<double>("strengthening.a"), - parset.get<double>("weakening.a"), segment), - b_(parset.get<double>("strengthening.b"), - parset.get<double>("weakening.b"), segment), - mu0_(parset.get<double>("mu0")) {} - - double const &C() const override { return C_; } - double const &L() const override { return L_; } - double const &V0() const override { return V0_; } - VirtualFunction const &a() const override { return a_; } - VirtualFunction const &b() const override { return b_; } - double const &mu0() const override { return mu0_; } - -private: - double const C_; - double const L_; - double const V0_; - PatchFunction const a_; - PatchFunction const b_; - double const mu0_; -}; -#endif diff --git a/src/one-body-problem-data/mygrid.cc b/src/one-body-problem-data/mygrid.cc deleted file mode 100644 index 7188f73a..00000000 --- a/src/one-body-problem-data/mygrid.cc +++ /dev/null @@ -1,227 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <dune/fufem/geometry/polyhedrondistance.hh> - -#include "mygrid.hh" -#include "midpoint.hh" -#include "../utils/diameter.hh" - -#if MY_DIM == 3 -SimplexManager::SimplexManager(unsigned int shift) : shift_(shift) {} -#endif - -// back-to-front, front-to-back, front-to-back -void SimplexManager::addFromVerticesFBB(unsigned int U, unsigned int V, - unsigned int W) { -#if MY_DIM == 3 - unsigned int const U2 = U + shift_; - unsigned int const V2 = V + shift_; - unsigned int const W2 = W + shift_; - - simplices_.push_back({ U, V, W, U2 }); - simplices_.push_back({ V, V2, W2, U2 }); - simplices_.push_back({ W, W2, U2, V }); -#else - simplices_.push_back({ U, V, W }); -#endif -} - -// back-to-front, back-to-front, front-to-back -void SimplexManager::addFromVerticesFFB(unsigned int U, unsigned int V, - unsigned int W) { -#if MY_DIM == 3 - unsigned int const U2 = U + shift_; - unsigned int const V2 = V + shift_; - unsigned int const W2 = W + shift_; - - simplices_.push_back({ U, V, W, U2 }); - simplices_.push_back({ V, V2, W, U2 }); - simplices_.push_back({ V2, W, U2, W2 }); -#else - simplices_.push_back({ U, V, W }); -#endif -} - -auto SimplexManager::getSimplices() -> SimplexList const & { - return simplices_; -} - -template <class Grid> GridConstructor<Grid>::GridConstructor() { - auto const &A = MyGeometry::A; - auto const &B = MyGeometry::B; - auto const &C = MyGeometry::C; - - unsigned int const vc = 3; - -#if MY_DIM == 3 - Dune::FieldMatrix<double, 2 * vc, MY_DIM> vertices; -#else - Dune::FieldMatrix<double, vc, MY_DIM> vertices; -#endif - for (size_t i = 0; i < 2; ++i) { -#if MY_DIM == 3 - size_t numXYplanes = 2; -#else - size_t numXYplanes = 1; -#endif - size_t k = 0; - for (size_t j = 1; j <= numXYplanes; ++j) { - vertices[k++][i] = A[i]; - vertices[k++][i] = B[i]; - vertices[k++][i] = C[i]; - assert(k == j * vc); - } - } - -#if MY_DIM == 3 - for (size_t k = 0; k < vc; ++k) { - vertices[k][2] = -MyGeometry::depth / 2.0; - vertices[k + vc][2] = MyGeometry::depth / 2.0; - } -#endif - - for (size_t i = 0; i < vertices.N(); ++i) - gridFactory.insertVertex(vertices[i]); - - Dune::GeometryType cell; -#if MY_DIM == 3 - cell.makeTetrahedron(); -#else - cell.makeTriangle(); -#endif - -#if MY_DIM == 3 - SimplexManager sm(vc); -#else - SimplexManager sm; -#endif - sm.addFromVerticesFFB(1, 2, 0); - auto const &simplices = sm.getSimplices(); - - // sanity-check choices of simplices - for (size_t i = 0; i < simplices.size(); ++i) { - Dune::FieldMatrix<double, MY_DIM, MY_DIM> check; - for (size_t j = 0; j < MY_DIM; ++j) - check[j] = vertices[simplices[i][j + 1]] - vertices[simplices[i][j]]; - assert(check.determinant() > 0); - gridFactory.insertElement(cell, simplices[i]); - } -} - -template <class Grid> std::shared_ptr<Grid> GridConstructor<Grid>::getGrid() { - return std::shared_ptr<Grid>(gridFactory.createGrid()); -} - -template <class Grid> -template <class GridView> -MyFaces<GridView> GridConstructor<Grid>::constructFaces( - GridView const &gridView) { - return MyFaces<GridView>(gridView); -} - -template <class GridView> -template <class Vector> -bool MyFaces<GridView>::xyCollinear(Vector const &a, Vector const &b, - Vector const &c) { - return isClose2((b[0] - a[0]) * (c[1] - a[1]), (b[1] - a[1]) * (c[0] - a[0])); -} - -template <class GridView> -template <class Vector> -bool MyFaces<GridView>::xyBoxed(Vector const &v1, Vector const &v2, - Vector const &x) { - auto const minmax0 = std::minmax(v1[0], v2[0]); - auto const minmax1 = std::minmax(v1[1], v2[1]); - - if (minmax0.first - 1e-14 * MyGeometry::lengthScale > x[0] or - x[0] > minmax0.second + 1e-14 * MyGeometry::lengthScale) - return false; - if (minmax1.first - 1e-14 * MyGeometry::lengthScale > x[1] or - x[1] > minmax1.second + 1e-14 * MyGeometry::lengthScale) - return false; - - return true; -} - -template <class GridView> -template <class Vector> -bool MyFaces<GridView>::xyBetween(Vector const &v1, Vector const &v2, - Vector const &x) { - return xyCollinear(v1, v2, x) && xyBoxed(v1, v2, x); -} - -template <class GridView> -MyFaces<GridView>::MyFaces(GridView const &gridView) - : -#if MY_DIM == 3 - lower(gridView), - right(gridView), - upper(gridView), - front(gridView), - back(gridView) -#else - lower(gridView), - right(gridView), - upper(gridView) -#endif -{ - assert(isClose(MyGeometry::A[1], 0)); - assert(isClose(MyGeometry::B[1], 0)); - lower.insertFacesByProperty([&](typename GridView::Intersection const &in) { - return isClose(0, in.geometry().center()[1]); - }); -#if MY_DIM == 3 - front.insertFacesByProperty([&](typename GridView::Intersection const &in) { - return isClose(MyGeometry::depth / 2.0, in.geometry().center()[2]); - }); - - back.insertFacesByProperty([&](typename GridView::Intersection const &in) { - return isClose(-MyGeometry::depth / 2.0, in.geometry().center()[2]); - }); -#endif - - upper.insertFacesByProperty([&](typename GridView::Intersection const &in) { - return xyBetween(MyGeometry::A, MyGeometry::C, in.geometry().center()); - }); - - right.insertFacesByProperty([&](typename GridView::Intersection const &in) { - return xyBetween(MyGeometry::B, MyGeometry::C, in.geometry().center()); - }); -} - -double computeAdmissibleDiameter(double distance, double smallestDiameter) { - return (distance / 0.0125 / MyGeometry::lengthScale + 1.0) * smallestDiameter; -} - -template <class Grid, class LocalVector> -void refine(Grid &grid, ConvexPolyhedron<LocalVector> const &weakPatch, - double smallestDiameter) { - bool needRefine = true; - while (true) { - needRefine = false; - for (auto &&e : elements(grid.leafGridView())) { - auto const geometry = e.geometry(); - - auto const weakeningRegionDistance = - distance(weakPatch, geometry, 1e-6 * MyGeometry::lengthScale); - auto const admissibleDiameter = - computeAdmissibleDiameter(weakeningRegionDistance, smallestDiameter); - - if (diameter(geometry) <= admissibleDiameter) - continue; - - needRefine = true; - grid.mark(1, e); - } - if (!needRefine) - break; - - grid.preAdapt(); - grid.adapt(); - grid.postAdapt(); - } -} - -#include "mygrid_tmpl.cc" diff --git a/src/one-body-problem-data/mygrid.hh b/src/one-body-problem-data/mygrid.hh deleted file mode 100644 index 3508048d..00000000 --- a/src/one-body-problem-data/mygrid.hh +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef SRC_ONE_BODY_PROBLEM_DATA_MYGRID_HH -#define SRC_ONE_BODY_PROBLEM_DATA_MYGRID_HH - -#include <dune/common/fmatrix.hh> -#include <dune/grid/common/gridfactory.hh> - -#include <dune/fufem/boundarypatch.hh> -#include <dune/fufem/geometry/convexpolyhedron.hh> - -#include "mygeometry.hh" - -template <class GridView> struct MyFaces { - BoundaryPatch<GridView> lower; - BoundaryPatch<GridView> right; - BoundaryPatch<GridView> upper; - -#if MY_DIM == 3 - BoundaryPatch<GridView> front; - BoundaryPatch<GridView> back; -#endif - - MyFaces(GridView const &gridView); - -private: - bool isClose(double a, double b) { - return std::abs(a - b) < 1e-14 * MyGeometry::lengthScale; - }; - - bool isClose2(double a, double b) { - return std::abs(a - b) < - 1e-14 * MyGeometry::lengthScale * MyGeometry::lengthScale; - }; - - template <class Vector> - bool xyBoxed(Vector const &v1, Vector const &v2, Vector const &x); - - template <class Vector> - bool xyCollinear(Vector const &a, Vector const &b, Vector const &c); - - template <class Vector> - bool xyBetween(Vector const &v1, Vector const &v2, Vector const &x); -}; - -class SimplexManager { -public: - using SimplexList = std::vector<std::vector<unsigned int>>; - -#if MY_DIM == 3 - SimplexManager(unsigned int shift); -#endif - - void addFromVerticesFBB(unsigned int U, unsigned int V, unsigned int W); - void addFromVerticesFFB(unsigned int U, unsigned int V, unsigned int W); - - SimplexList const &getSimplices(); - -private: - SimplexList simplices_; - -#if MY_DIM == 3 - unsigned int const shift_; -#endif -}; - -template <class Grid> class GridConstructor { -public: - GridConstructor(); - - std::shared_ptr<Grid> getGrid(); - - template <class GridView> - MyFaces<GridView> constructFaces(GridView const &gridView); - -private: - Dune::GridFactory<Grid> gridFactory; -}; - -double computeAdmissibleDiameter(double distance, double smallestDiameter); - -template <class Grid, class LocalVector> -void refine(Grid &grid, ConvexPolyhedron<LocalVector> const &weakPatch, - double smallestDiameter); - -#endif diff --git a/src/one-body-problem-data/mygrid_tmpl.cc b/src/one-body-problem-data/mygrid_tmpl.cc deleted file mode 100644 index acedf87e..00000000 --- a/src/one-body-problem-data/mygrid_tmpl.cc +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef MY_DIM -#error MY_DIM unset -#endif - -#include "../explicitgrid.hh" -#include "../explicitvectors.hh" - -template class GridConstructor<Grid>; - -template struct MyFaces<GridView>; - -template MyFaces<GridView> GridConstructor<Grid>::constructFaces( - GridView const &gridView); - -template void refine<Grid, LocalVector>( - Grid &grid, ConvexPolyhedron<LocalVector> const &weakPatch, - double smallestDiameter); diff --git a/src/one-body-problem-data/patchfunction.hh b/src/one-body-problem-data/patchfunction.hh deleted file mode 100644 index 72cdc867..00000000 --- a/src/one-body-problem-data/patchfunction.hh +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SRC_ONE_BODY_PROBLEM_DATA_PATCHFUNCTION_HH -#define SRC_ONE_BODY_PROBLEM_DATA_PATCHFUNCTION_HH - -#include <dune/common/function.hh> -#include <dune/common/fvector.hh> -#include <dune/common/parametertree.hh> - -#include <dune/fufem/geometry/polyhedrondistance.hh> - -class PatchFunction - : public Dune::VirtualFunction<Dune::FieldVector<double, MY_DIM>, - Dune::FieldVector<double, 1>> { -private: - using Polyhedron = ConvexPolyhedron<Dune::FieldVector<double, MY_DIM>>; - - double const v1_; - double const v2_; - Polyhedron const &segment_; - -public: - PatchFunction(double v1, double v2, Polyhedron const &segment) - : v1_(v1), v2_(v2), segment_(segment) {} - - void evaluate(Dune::FieldVector<double, MY_DIM> const &x, - Dune::FieldVector<double, 1> &y) const { - y = distance(x, segment_, 1e-6 * MyGeometry::lengthScale) <= 1e-5 ? v2_ - : v1_; - } -}; - -#endif diff --git a/src/one-body-problem-data/segmented-function.hh b/src/one-body-problem-data/segmented-function.hh deleted file mode 100644 index 652ba03b..00000000 --- a/src/one-body-problem-data/segmented-function.hh +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef SRC_ONE_BODY_PROBLEM_DATA_SEGMENTED_FUNCTION_HH -#define SRC_ONE_BODY_PROBLEM_DATA_SEGMENTED_FUNCTION_HH - -#include <dune/common/function.hh> -#include <dune/common/fvector.hh> -#include <dune/common/parametertree.hh> - -#include "mygeometry.hh" - -class SegmentedFunction - : public Dune::VirtualFunction<Dune::FieldVector<double, MY_DIM>, - Dune::FieldVector<double, 1>> { -private: - bool liesBelow(Dune::FieldVector<double, MY_DIM> const &x, - Dune::FieldVector<double, MY_DIM> const &y, - Dune::FieldVector<double, MY_DIM> const &z) const { - return x[1] + (z[0] - x[0]) * (y[1] - x[1]) / (y[0] - x[0]) >= z[1]; - }; - bool insideRegion2(Dune::FieldVector<double, MY_DIM> const &z) const { - return liesBelow(MyGeometry::K, MyGeometry::M, z); - }; - - double const _v1; - double const _v2; - -public: - SegmentedFunction(double v1, double v2) : _v1(v1), _v2(v2) {} - - void evaluate(Dune::FieldVector<double, MY_DIM> const &x, - Dune::FieldVector<double, 1> &y) const { - y = insideRegion2(x) ? _v2 : _v1; - } -}; -#endif diff --git a/src/one-body-problem-data/weakpatch.hh b/src/one-body-problem-data/weakpatch.hh deleted file mode 100644 index 59a65306..00000000 --- a/src/one-body-problem-data/weakpatch.hh +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef SRC_ONE_BODY_PROBLEM_DATA_WEAKPATCH_HH -#define SRC_ONE_BODY_PROBLEM_DATA_WEAKPATCH_HH - -template <class LocalVector> -ConvexPolyhedron<LocalVector> getWeakPatch(Dune::ParameterTree const &parset) { - ConvexPolyhedron<LocalVector> weakPatch; -#if MY_DIM == 3 - weakPatch.vertices.resize(4); - weakPatch.vertices[0] = weakPatch.vertices[2] = MyGeometry::X; - weakPatch.vertices[1] = weakPatch.vertices[3] = MyGeometry::Y; - for (size_t k = 0; k < 2; ++k) { - weakPatch.vertices[k][2] = -MyGeometry::depth / 2.0; - weakPatch.vertices[k + 2][2] = MyGeometry::depth / 2.0; - } - switch (parset.get<Config::PatchType>("patchType")) { - case Config::Rectangular: - break; - case Config::Trapezoidal: - weakPatch.vertices[1][0] += 0.05 * MyGeometry::lengthScale; - weakPatch.vertices[3][0] -= 0.05 * MyGeometry::lengthScale; - break; - default: - assert(false); - } -#else - weakPatch.vertices.resize(2); - weakPatch.vertices[0] = MyGeometry::X; - weakPatch.vertices[1] = MyGeometry::Y; -#endif - return weakPatch; -}; -#endif diff --git a/src/one-body-problem.cc b/src/one-body-problem.cc deleted file mode 100644 index b95f4cd1..00000000 --- a/src/one-body-problem.cc +++ /dev/null @@ -1,361 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_IPOPT -#undef HAVE_IPOPT -#endif - -#include <atomic> -#include <cmath> -#include <csignal> -#include <exception> -#include <fstream> -#include <iostream> -#include <iomanip> - -#include <dune/common/bitsetvector.hh> -#include <dune/common/exceptions.hh> -#include <dune/common/fmatrix.hh> -#include <dune/common/function.hh> -#include <dune/common/fvector.hh> -#include <dune/common/parallel/mpihelper.hh> -#include <dune/common/parametertree.hh> -#include <dune/common/parametertreeparser.hh> - -#include <dune/grid/common/mcmgmapper.hh> -#include <dune/istl/bcrsmatrix.hh> -#include <dune/istl/bvector.hh> - -#include <dune/fufem/boundarypatch.hh> -#include <dune/fufem/formatstring.hh> - -#include <dune/solvers/norms/energynorm.hh> - - -/* -#include <dune/solvers/solvers/loopsolver.hh> -#include <dune/solvers/solvers/solver.hh> -#include <dune/tnnmg/problem-classes/convexproblem.hh> -*/ - - -#include <dune/tectonic/geocoordinate.hh> -#include <dune/tectonic/myblockproblem.hh> -#include <dune/tectonic/globalfriction.hh> -#include <dune/fufem/hdf5/file.hh> - -#include "assemblers.hh" -#include "boundarycondition.hh" -#include "gridselector.hh" - -#include "data-structures/enumparser.hh" -#include "data-structures/enums.hh" -#include "data-structures/matrices.hh" -#include "data-structures/program_state.hh" - -#include "io/hdf5-writer.hh" -#include "io/hdf5/restart-io.hh" -#include "io/vtk.hh" - -#include "one-body-problem-data/bc.hh" -#include "one-body-problem-data/mybody.hh" -#include "one-body-problem-data/mygeometry.hh" -#include "one-body-problem-data/myglobalfrictiondata.hh" -#include "one-body-problem-data/mygrid.hh" -#include "one-body-problem-data/weakpatch.hh" - -#include "spatial-solving/solverfactory.hh" - -#include "time-stepping/adaptivetimestepper.hh" -#include "time-stepping/rate.hh" -#include "time-stepping/state.hh" -#include "time-stepping/updaters.hh" - -#include "utils/diameter.hh" - -// for getcwd -#include <unistd.h> - -#define USE_OLD_TNNMG - -size_t const dims = MY_DIM; - -Dune::ParameterTree getParameters(int argc, char *argv[]) { - Dune::ParameterTree parset; - Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/one-body-problem.cfg", parset); - Dune::ParameterTreeParser::readINITree( - Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/one-body-problem-%dD.cfg", dims), parset); - Dune::ParameterTreeParser::readOptions(argc, argv, parset); - return parset; -} - -static std::atomic<bool> terminationRequested(false); -void handleSignal(int signum) { terminationRequested = true; } - -int main(int argc, char *argv[]) { - try { - Dune::MPIHelper::instance(argc, argv); - - char buffer[256]; - char *val = getcwd(buffer, sizeof(buffer)); - if (val) { - std::cout << buffer << std::endl; - std::cout << argv[0] << std::endl; - } - - auto const parset = getParameters(argc, argv); - - MyGeometry::render(); - MyGeometry::write(); - - using GridView = Grid::LeafGridView; - using MyAssembler = MyAssembler<GridView, dims>; - using Matrix = MyAssembler::Matrix; - using Vector = MyAssembler::Vector; - using LocalVector = Vector::block_type; - using ScalarMatrix = MyAssembler::ScalarMatrix; - using ScalarVector = MyAssembler::ScalarVector; - - auto const weakPatch = - getWeakPatch<LocalVector>(parset.sub("boundary.friction.weakening")); - - // {{{ Set up grid - GridConstructor<Grid> gridConstructor; - auto grid = gridConstructor.getGrid(); - - refine(*grid, weakPatch, - parset.get<double>("boundary.friction.smallestDiameter")); - - double minDiameter = std::numeric_limits<double>::infinity(); - double maxDiameter = 0.0; - for (auto &&e : elements(grid->leafGridView())) { - auto const geometry = e.geometry(); - auto const diam = diameter(geometry); - minDiameter = std::min(minDiameter, diam); - maxDiameter = std::max(maxDiameter, diam); - } - std::cout << "min diameter: " << minDiameter << std::endl; - std::cout << "max diameter: " << maxDiameter << std::endl; - - auto const leafView = grid->leafGridView(); - auto const leafVertexCount = leafView.size(dims); - - std::cout << "Number of DOFs: " << leafVertexCount << std::endl; - - auto myFaces = gridConstructor.constructFaces(leafView); - - BoundaryPatch<GridView> const neumannBoundary(leafView); - BoundaryPatch<GridView> const &frictionalBoundary = myFaces.lower; - BoundaryPatch<GridView> const &surface = myFaces.upper; - - // Dirichlet Boundary - Dune::BitSetVector<dims> noNodes(leafVertexCount); - Dune::BitSetVector<dims> dirichletNodes(leafVertexCount); - for (size_t i = 0; i < leafVertexCount; ++i) { - if (myFaces.right.containsVertex(i)) - dirichletNodes[i][0] = true; - - if (myFaces.lower.containsVertex(i)) - dirichletNodes[i][1] = true; - -#if MY_DIM == 3 - if (myFaces.front.containsVertex(i) || myFaces.back.containsVertex(i)) - dirichletNodes[i][2] = true; -#endif - } - - - // Set up functions for time-dependent boundary conditions - using Function = Dune::VirtualFunction<double, double>; - Function const &velocityDirichletFunction = VelocityDirichletCondition(); - Function const &neumannFunction = NeumannCondition(); - - MyAssembler const myAssembler(leafView); - - MyBody<dims> const body(parset); - - Matrices<Matrix> matrices; - myAssembler.assembleElasticity(body.getYoungModulus(), - body.getPoissonRatio(), matrices.elasticity); - myAssembler.assembleViscosity(body.getShearViscosityField(), - body.getBulkViscosityField(), - matrices.damping); - myAssembler.assembleMass(body.getDensityField(), matrices.mass); - - ScalarMatrix relativeFrictionalBoundaryMass; - myAssembler.assembleFrictionalBoundaryMass(frictionalBoundary, - relativeFrictionalBoundaryMass); - relativeFrictionalBoundaryMass /= frictionalBoundary.area(); - EnergyNorm<ScalarMatrix, ScalarVector> const stateEnergyNorm( - relativeFrictionalBoundaryMass); - - // Assemble forces - Vector gravityFunctional; - myAssembler.assembleBodyForce(body.getGravityField(), gravityFunctional); - - // Problem formulation: right-hand side - std::function<void(double, Vector &)> computeExternalForces = - [&](double _relativeTime, Vector &_ell) { - myAssembler.assembleNeumann(neumannBoundary, _ell, neumannFunction, - _relativeTime); - _ell += gravityFunctional; - }; - - using MyProgramState = ProgramState<Vector, ScalarVector>; - MyProgramState programState(leafVertexCount); - auto const firstRestart = parset.get<size_t>("io.restarts.first"); - auto const restartSpacing = parset.get<size_t>("io.restarts.spacing"); - auto const writeRestarts = parset.get<bool>("io.restarts.write"); - auto const writeData = parset.get<bool>("io.data.write"); - bool const handleRestarts = writeRestarts or firstRestart > 0; - - /* - auto dataFile = - writeData ? std::make_unique<HDF5::File>("output.h5") : nullptr; - - auto restartFile = handleRestarts - ? std::make_unique<HDF5::File>( - "restarts.h5", - writeRestarts ? HDF5::Access::READWRITE - : HDF5::Access::READONLY) - : nullptr; - auto restartIO = handleRestarts - ? std::make_unique<RestartIO<MyProgramState>>( - *restartFile, leafVertexCount) - : nullptr; - - if (firstRestart > 0) // automatically adjusts the time and timestep - restartIO->read(firstRestart, programState); - else - programState.setupInitialConditions(parset, computeExternalForces, - matrices, myAssembler, dirichletNodes, - noNodes, frictionalBoundary, body); - - MyGlobalFrictionData<LocalVector> frictionInfo( - parset.sub("boundary.friction"), weakPatch); - auto myGlobalFriction = myAssembler.assembleFrictionNonlinearity( - parset.get<Config::FrictionModel>("boundary.friction.frictionModel"), - frictionalBoundary, frictionInfo, programState.weightedNormalStress); - myGlobalFriction->updateAlpha(programState.alpha); - - Vector vertexCoordinates(leafVertexCount); - { - Dune::MultipleCodimMultipleGeomTypeMapper< - GridView, Dune::MCMGVertexLayout> const vertexMapper(leafView, Dune::mcmgVertexLayout()); - for (auto &&v : vertices(leafView)) - vertexCoordinates[vertexMapper.index(v)] = geoToPoint(v.geometry()); - } - - using MyVertexBasis = typename MyAssembler::VertexBasis; - auto dataWriter = - writeData ? std::make_unique< - HDF5Writer<MyProgramState, MyVertexBasis, GridView>>( - *dataFile, vertexCoordinates, myAssembler.vertexBasis, - surface, frictionalBoundary, weakPatch) - : nullptr; - MyVTKWriter<MyVertexBasis, typename MyAssembler::CellBasis> const vtkWriter( - myAssembler.cellBasis, myAssembler.vertexBasis, "obs"); - - - IterationRegister iterationCount; - auto const report = [&](bool initial = false) { - if (writeData) { - dataWriter->reportSolution(programState, *myGlobalFriction); - if (!initial) - dataWriter->reportIterations(programState, iterationCount); - dataFile->flush(); - } - - if (writeRestarts and !initial and - programState.timeStep % restartSpacing == 0) { - restartIO->write(programState); - restartFile->flush(); - } - - if (parset.get<bool>("io.printProgress")) - std::cout << "timeStep = " << std::setw(6) << programState.timeStep - << ", time = " << std::setw(12) << programState.relativeTime - << ", tau = " << std::setw(12) << programState.relativeTau - << std::endl; - - if (parset.get<bool>("io.vtk.write")) { - ScalarVector stress; - myAssembler.assembleVonMisesStress(body.getYoungModulus(), - body.getPoissonRatio(), - programState.u, stress); - vtkWriter.write(programState.timeStep, programState.u, programState.v, - programState.alpha, stress); - } - }; - report(true); - - - // Set up TNNMG solver - using NonlinearFactory = SolverFactory< - dims, - MyBlockProblem<ConvexProblem<GlobalFriction<Matrix, Vector>, Matrix>>, - Grid>; - NonlinearFactory factory(parset.sub("solver.tnnmg"), *grid, dirichletNodes); - - using MyUpdater = Updaters<RateUpdater<Vector, Matrix, Function, dims>, - StateUpdater<ScalarVector, Vector>>; - MyUpdater current( - initRateUpdater(parset.get<Config::scheme>("timeSteps.scheme"), - velocityDirichletFunction, dirichletNodes, matrices, - programState.u, programState.v, programState.a), - initStateUpdater<ScalarVector, Vector>( - parset.get<Config::stateModel>("boundary.friction.stateModel"), - programState.alpha, *frictionalBoundary.getVertices(), - parset.get<double>("boundary.friction.L"), - parset.get<double>("boundary.friction.V0"))); - - auto const refinementTolerance = - parset.get<double>("timeSteps.refinementTolerance"); - auto const mustRefine = [&](MyUpdater &coarseUpdater, - MyUpdater &fineUpdater) { - ScalarVector coarseAlpha; - coarseUpdater.state_->extractAlpha(coarseAlpha); - - ScalarVector fineAlpha; - fineUpdater.state_->extractAlpha(fineAlpha); - - return stateEnergyNorm.diff(fineAlpha, coarseAlpha) > refinementTolerance; - }; - - std::signal(SIGXCPU, handleSignal); - std::signal(SIGINT, handleSignal); - std::signal(SIGTERM, handleSignal); - - AdaptiveTimeStepper<NonlinearFactory, MyUpdater, - EnergyNorm<ScalarMatrix, ScalarVector>> - adaptiveTimeStepper(factory, parset, myGlobalFriction, current, - programState.relativeTime, programState.relativeTau, - computeExternalForces, stateEnergyNorm, mustRefine); - while (!adaptiveTimeStepper.reachedEnd()) { - programState.timeStep++; - - iterationCount = adaptiveTimeStepper.advance(); - - programState.relativeTime = adaptiveTimeStepper.relativeTime_; - programState.relativeTau = adaptiveTimeStepper.relativeTau_; - current.rate_->extractDisplacement(programState.u); - current.rate_->extractVelocity(programState.v); - current.rate_->extractAcceleration(programState.a); - current.state_->extractAlpha(programState.alpha); - - report(); - - if (terminationRequested) { - std::cerr << "Terminating prematurely" << std::endl; - break; - } - } - - */ - } catch (Dune::Exception &e) { - Dune::derr << "Dune reported error: " << e << std::endl; - } catch (std::exception &e) { - std::cerr << "Standard exception: " << e.what() << std::endl; - } -} diff --git a/src/one-body-problem.cfg b/src/one-body-problem.cfg deleted file mode 100644 index 7336759c..00000000 --- a/src/one-body-problem.cfg +++ /dev/null @@ -1,70 +0,0 @@ -# -*- mode:conf -*- -gravity = 9.81 # [m/s^2] - -[io] -data.write = true -printProgress = false -restarts.first = 0 -restarts.spacing= 20 -restarts.write = true -vtk.write = false - -[problem] -finalTime = 1000 # [s] - -[body] -bulkModulus = 0.5e5 # [Pa] -poissonRatio = 0.3 # [1] -[body.elastic] -density = 900 # [kg/m^3] -shearViscosity = 1e3 # [Pas] -bulkViscosity = 1e3 # [Pas] -[body.viscoelastic] -density = 1000 # [kg/m^3] -shearViscosity = 1e4 # [Pas] -bulkViscosity = 1e4 # [Pas] - -[boundary.friction] -C = 10 # [Pa] -mu0 = 0.7 # [ ] -V0 = 5e-5 # [m/s] -L = 2.25e-5 # [m] -initialAlpha = 0 # [ ] -stateModel = AgeingLaw -frictionModel = Regularised -[boundary.friction.weakening] -a = 0.002 # [ ] -b = 0.017 # [ ] -[boundary.friction.strengthening] -a = 0.020 # [ ] -b = 0.005 # [ ] - -[timeSteps] -scheme = newmark - -[u0.solver] -maximumIterations = 100000 -verbosity = quiet - -[a0.solver] -maximumIterations = 100000 -verbosity = quiet - -[v.solver] -maximumIterations = 100000 -verbosity = quiet - -[v.fpi] -maximumIterations = 10000 -lambda = 0.5 - -[solver.tnnmg.linear] -maximumIterations = 100000 -pre = 3 -cycle = 1 # 1 = V, 2 = W, etc. -post = 3 - -[solver.tnnmg.main] -pre = 1 -multi = 5 # number of multigrid steps -post = 0 diff --git a/src/spatial-solving/CMakeLists.txt b/src/spatial-solving/CMakeLists.txt deleted file mode 100644 index e683042b..00000000 --- a/src/spatial-solving/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory("tnnmg") -add_subdirectory("preconditioners") diff --git a/src/spatial-solving/fixedpointiterator_tmpl.cc b/src/spatial-solving/fixedpointiterator_tmpl.cc deleted file mode 100644 index 5f4b30cf..00000000 --- a/src/spatial-solving/fixedpointiterator_tmpl.cc +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MY_DIM -#error MY_DIM unset -#endif - -#include "../explicitgrid.hh" -#include "../explicitvectors.hh" - -#include <dune/solvers/norms/energynorm.hh> - -#include "../spatial-solving/solverfactory_tmpl.cc" -#include "../data-structures/contactnetwork_tmpl.cc" - -#include "../time-stepping/rate/rateupdater.hh" -#include "../time-stepping/state/stateupdater.hh" -#include "../time-stepping/updaters.hh" - -using BoundaryNodes = typename MyContactNetwork::BoundaryNodes; -using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions; - -using MyStateUpdater = StateUpdater<ScalarVector, Vector>; -using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>; -using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>; - -using ErrorNorms = typename MyContactNetwork::StateEnergyNorms; - - -template class FixedPointIterator<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>; diff --git a/src/spatial-solving/preconditioners/CMakeLists.txt b/src/spatial-solving/preconditioners/CMakeLists.txt deleted file mode 100644 index 00e132a9..00000000 --- a/src/spatial-solving/preconditioners/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_custom_target(dune-tectonic_spatial-solving_preconditioners_src SOURCES - hierarchicleveliterator.hh - levelpatchpreconditioner.hh - localproblem.hh - multilevelpatchpreconditioner.hh - nbodycontacttransfer.hh - supportpatchfactory.hh -) diff --git a/src/spatial-solving/preconditioners/localproblem.hh b/src/spatial-solving/preconditioners/localproblem.hh deleted file mode 100644 index 8d202afc..00000000 --- a/src/spatial-solving/preconditioners/localproblem.hh +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef OSC_LOCAL_PROBLEM_HH -#define OSC_LOCAL_PROBLEM_HH - -#include <math.h> -#include <dune/common/fmatrix.hh> -#include <dune/common/function.hh> -#include <dune/common/timer.hh> - -#include <dune/istl/matrixindexset.hh> -//#include <dune/istl/superlu.hh> -#include <dune/istl/umfpack.hh> - -#include <dune/fufem/assemblers/localoperatorassembler.hh> - -#include "../../utils/debugutils.hh" - -template <class MatrixType, class DomainType, class RangeType = DomainType> -class LocalProblem { - -private: - typedef typename MatrixType::block_type block_type; - typedef typename MatrixType::field_type ctype; - - const static size_t dim = DomainType::block_type::dimension; - - using BitVector = Dune::BitSetVector<dim>; - - MatrixType localMat; - const RangeType& rhs_; - const BitVector& ignoreNodes_; - - /* size_t flatIndex(const size_t blockIdx, const size_t localBlockIdx) { - return blockIdx*dim + localBlockIdx; - } - - bool isAllIgnored(const size_t blockIdx) { - bool res = true; - size_t flatIdx = blockIdx*dim; - - for (size_t d=0; d<dim; d++) { - res = res && (globalToLocal_[flatIdx+d] == -1); - } - - return res; - }*/ - template <class LocalMat, class LocalBitVector> - void computeLocalMat(LocalMat& localMat, const LocalMat& refMat, const LocalBitVector& localIgnore, bool isDiagonal=false) { - if (isDiagonal) { - for (size_t i=0; i<refMat.N(); i++) { - bool isIgnored = localIgnore[i]; - for (size_t j=0; j<refMat.M(); j++) { - if (isIgnored || refMat[i][j]==0) - localMat[i][j] = (double) (i==j); - else - localMat[i][j] = refMat[i][j]; - } - } - } else { - for (size_t i=0; i<refMat.N(); i++) { - bool isIgnored = localIgnore[i]; - for (size_t j=0; j<refMat.M(); j++) { - if (isIgnored) - localMat[i][j] = 0; - else - localMat[i][j] = refMat[i][j]; - } - } - } - } - -public: - LocalProblem(const MatrixType& mat, - const RangeType& rhs, - const BitVector& ignoreNodes) : - rhs_(rhs), - ignoreNodes_(ignoreNodes) - { - - // construct globalToLocal map - /* std::vector<int, int> localToGlobal; - std::vector<int, int> globalToLocal(ignoreNodes.size()*dim, -1); - int localIdx = 0; - for (size_t i=0; i<ignoreNodes.size(); ++i) { - const auto& ignoreNode = ignoreNodes[i]; - for (size_t d=0; d<dim; d++) { - if (not toBool(ignoreNode[d])) { - size_t flatIdx = flatIndex(i, d); - localToGlobal[localIdx] = flatIdx; - globalToLocal[flatIdx] = localIdx; - localIdx++; - } - } - }*/ - - // build local stiffness matrix - localMat = mat; - - for(size_t rowIdx = 0; rowIdx<localMat.N(); rowIdx++) { - const auto& row = mat[rowIdx]; - - auto colIt = row.begin(); - const auto& colEndIt = row.end(); - for(; colIt!=colEndIt; ++colIt) { - const auto colIdx = colIt.index(); - computeLocalMat(localMat[rowIdx][colIdx], row[colIdx], ignoreNodes_[rowIdx], rowIdx==colIdx); - } - } - } - - MatrixType& getMat() { - return localMat; - } - - void getLocalRhs(const DomainType& iterate, RangeType& newRhs) { - newRhs = rhs_; - - for (size_t i=0; i<newRhs.size(); i++) { - for (size_t d=0; d<dim; d++) { - if (ignoreNodes_[i][d]) { - newRhs[i][d] = iterate[i][d]; - } - } - } - } - - /* void solve(DomainType& x){ - #if HAVE_SUPERLU - RangeType localRhsCopy(localRhs); - Dune::InverseOperatorResult res; - - x.resize(localMat.M()); - - Dune::UMFPack<MatrixType> directSolver(localMat); - directSolver.apply(x, localRhsCopy, res); - #else - #error No SuperLU! - #endif - }*/ -}; - -#endif diff --git a/src/spatial-solving/solverfactory.cc b/src/spatial-solving/solverfactory.cc deleted file mode 100644 index 017f981d..00000000 --- a/src/spatial-solving/solverfactory.cc +++ /dev/null @@ -1,50 +0,0 @@ -//#ifdef HAVE_CONFIG_H -//#include "config.h" -//#endif - -#include <dune/solvers/common/wrapownshare.hh> -#include <dune/solvers/iterationsteps/blockgssteps.hh> -#include <dune/solvers/solvers/umfpacksolver.hh> - -//#include "solverfactory.hh" - -#include "../utils/debugutils.hh" - -template <class Functional, class BitVector, class ContactNetwork> -template <class LinearSolver> -SolverFactory<Functional, BitVector, ContactNetwork>::SolverFactory( - const Dune::ParameterTree& parset, - Functional& J, - LinearSolver&& linearSolver, - const BitVector& ignoreNodes, - const ContactNetwork& contactNetwork) : - J_(Dune::Solvers::wrap_own_share<const Functional>(std::forward<Functional>(J))) { - - //auto localSolver = Dune::TNNMG::gaussSeidelLocalSolver(LocalSolver()); - //nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, localSolver); - - nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, LocalSolver()); - - auto linearSolver_ptr = Dune::Solvers::wrap_own_share<std::decay_t<LinearSolver>>(std::forward<LinearSolver>(linearSolver)); - - //tnnmgStep_ = std::make_shared<Step>(*J_, dummyIterate_, nonlinearSmoother_, linearSolver_ptr, DefectProjection(), Dune::TNNMG::ScalarObstacleSolver()); - - tnnmgStep_ = std::make_shared<Step>(*J_, dummyIterate_, nonlinearSmoother_, linearSolver_ptr, DefectProjection(), LineSearchSolver(), contactNetwork); - tnnmgStep_->setPreSmoothingSteps(parset.get<int>("main.pre")); - tnnmgStep_->setIgnore(ignoreNodes); -} - -template <class Functional, class BitVector, class ContactNetwork> -void SolverFactory<Functional, BitVector, ContactNetwork>::setProblem(Vector& x) { - nonlinearSmoother_->setProblem(x); - tnnmgStep_->setProblem(x); -} - - -template <class Functional, class BitVector, class ContactNetwork> -auto SolverFactory<Functional, BitVector, ContactNetwork>::step() --> std::shared_ptr<Step> { - return tnnmgStep_; -} - -//#include "solverfactory_tmpl.cc" diff --git a/src/spatial-solving/solverfactory_tmpl.cc b/src/spatial-solving/solverfactory_tmpl.cc deleted file mode 100644 index 996e7360..00000000 --- a/src/spatial-solving/solverfactory_tmpl.cc +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MY_DIM -#error MY_DIM unset -#endif - -#include "../explicitgrid.hh" -#include "../explicitvectors.hh" - -#include <dune/solvers/solvers/loopsolver.hh> - -#include "../../dune/tectonic/globalfriction.hh" -#include "tnnmg/functional.hh" -#include "tnnmg/zerononlinearity.hh" - -#include "../data-structures/contactnetwork.hh" - -#include "solverfactory.hh" - -using MyGlobalFriction = GlobalFriction<Matrix, Vector>; - -using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>; -using MyZeroFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, double>; - -using MyLinearSolver = Dune::Solvers::LoopSolver<Vector>; - -using MyContactNetwork = ContactNetwork<Grid, Vector>; - -using MySolverFactory = SolverFactory<MyFunctional, BitVector>; -template class SolverFactory<MyFunctional, BitVector>; -template<> template<> SolverFactory<MyFunctional, BitVector>::SolverFactory(const Dune::ParameterTree&, MyFunctional&, MyLinearSolver&&, const BitVector&, const MyContactNetwork&); - -using MyZeroSolverFactory = SolverFactory<MyZeroFunctional, BitVector>; -template class SolverFactory<MyZeroFunctional, BitVector>; -/*template<> SolverFactory<MyZeroFunctional, BitVector>::SolverFactory(Dune::ParameterTree const &, - MyZeroFunctional&, - MyLinearSolver&&, - const BitVector&);*/ diff --git a/src/spatial-solving/tnnmg/CMakeLists.txt b/src/spatial-solving/tnnmg/CMakeLists.txt deleted file mode 100644 index d32080a3..00000000 --- a/src/spatial-solving/tnnmg/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_custom_target(dune-tectonic_spatial-solving_tnnmg_src SOURCES - functional.hh - linearization.hh - linearcorrection.hh - linesearchsolver.hh - localbisectionsolver.hh - zerononlinearity.hh -) diff --git a/src/tests/contactmerge.cc b/src/tests/contactmerge.cc deleted file mode 100644 index 5bf8d918..00000000 --- a/src/tests/contactmerge.cc +++ /dev/null @@ -1,40 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <dune/common/parallel/mpihelper.hh> -#include <dune/grid/yaspgrid.hh> -#include <dune/grid-glue/adapter/gridgluevtkwriter.hh> -#include <dune/grid-glue/extractors/codim1extractor.hh> -#include <dune/grid-glue/gridglue.hh> -#include <dune/grid-glue/merging/contactmerge.hh> - -const unsigned dim = 3; -using Coordinates = Dune::EquidistantOffsetCoordinates<double, dim>; -using Grid = Dune::YaspGrid<dim, Coordinates>; -using Element = Grid::Codim<0>::Entity; -using Extractor = Dune::GridGlue::Codim1Extractor<Grid::LeafGridView>; -using GridGlue = Dune::GridGlue::GridGlue<Extractor, Extractor>; -using ContactMerge = Dune::GridGlue::ContactMerge<dim, Grid::ctype>; - -int main(int argc, char** argv) -{ - Dune::MPIHelper::instance(argc, argv); - - Grid grid0{{0., 0., 0.}, {1., 1., 1.}, {10, 10, 10}}; - Grid grid1{{.12, 0.23, 1.05}, {1.12, 1.23, 2.05}, {10, 10, 10}}; - - auto truePredicate = [](const Element&, unsigned int) { return true; }; - - auto extractor0 = std::make_shared<Extractor>(grid0.leafGridView(), truePredicate); - auto extractor1 = std::make_shared<Extractor>(grid1.leafGridView(), truePredicate); - - auto merger = std::make_shared<ContactMerge>(); - - GridGlue glue(extractor0, extractor1, merger); - glue.build(); - - Dune::GridGlue::GridGlueVtkWriter::write(glue, "contactmerge"); - - return 0; -} diff --git a/src/time-stepping/adaptivetimestepper.cc b/src/time-stepping/adaptivetimestepper.cc deleted file mode 100644 index 96aa6ecc..00000000 --- a/src/time-stepping/adaptivetimestepper.cc +++ /dev/null @@ -1,137 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "adaptivetimestepper.hh" - -void IterationRegister::registerCount(FixedPointIterationCounter count) { - totalCount += count; -} - -void IterationRegister::registerFinalCount(FixedPointIterationCounter count) { - finalCount = count; -} - -void IterationRegister::reset() { - totalCount = FixedPointIterationCounter(); - finalCount = FixedPointIterationCounter(); -} - -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> -AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::AdaptiveTimeStepper( - Dune::ParameterTree const &parset, - const ContactNetwork& contactNetwork, - const IgnoreVector& ignoreNodes, - GlobalFriction& globalFriction, - const std::vector<const BitVector*>& bodywiseNonmortarBoundaries, - Updaters ¤t, - double relativeTime, - double relativeTau, - ExternalForces& externalForces, - const ErrorNorms& errorNorms, - std::function<bool(Updaters &, Updaters &)> mustRefine) - : relativeTime_(relativeTime), - relativeTau_(relativeTau), - finalTime_(parset.get<double>("problem.finalTime")), - parset_(parset), - contactNetwork_(contactNetwork), - ignoreNodes_(ignoreNodes), - globalFriction_(globalFriction), - bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries), - current_(current), - R1_(), - externalForces_(externalForces), - mustRefine_(mustRefine), - errorNorms_(errorNorms) {} - -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> -bool AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::reachedEnd() { - return relativeTime_ >= 1.0; -} - -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> -IterationRegister AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::advance() { - /* - | C | We check here if making the step R1 of size tau is a - | R1 | R2 | good idea. To check if we can coarsen, we compare - |F1|F2| | the result of (R1+R2) with C, i.e. two steps of size - tau with one of size 2*tau. To check if we need to - refine, we compare the result of (F1+F2) with R1, i.e. two steps - of size tau/2 with one of size tau. The method makes multiple - coarsening/refining attempts, with coarsening coming first. */ - - std::cout << "AdaptiveTimeStepper::advance()" << std::endl; - - if (R1_.updaters == Updaters()) - R1_ = step(current_, relativeTime_, relativeTau_); - - std::cout << "AdaptiveTimeStepper Step 1" << std::endl; - - bool didCoarsen = false; - iterationRegister_.reset(); - UpdatersWithCount R2; /* - UpdatersWithCount C; - while (relativeTime_ + relativeTau_ <= 1.0) { - R2 = step(R1_.updaters, relativeTime_ + relativeTau_, relativeTau_); - std::cout << "AdaptiveTimeStepper R2 computed!" << std::endl << std::endl; - C = step(current_, relativeTime_, 2 * relativeTau_); - std::cout << "AdaptiveTimeStepper C computed!" << std::endl << std::endl; - if (mustRefine_(R2.updaters, C.updaters)) - break; - - didCoarsen = true; - relativeTau_ *= 2; - R1_ = C; - } - - std::cout << "AdaptiveTimeStepper Step 1" << std::endl; - UpdatersWithCount F1; - UpdatersWithCount F2; - if (!didCoarsen) { - while (true) { - F1 = step(current_, relativeTime_, relativeTau_ / 2.0); - std::cout << "AdaptiveTimeStepper F1 computed!" << std::endl << std::endl; - F2 = step(F1.updaters, relativeTime_ + relativeTau_ / 2.0, - relativeTau_ / 2.0); - std::cout << "AdaptiveTimeStepper F2 computed!" << std::endl << std::endl; - if (!mustRefine_(F2.updaters, R1_.updaters)) { - std::cout << "Sufficiently refined!" << std::endl; - break; - } - - relativeTau_ /= 2.0; - R1_ = F1; - R2 = F2; - } - } - */ - std::cout << "AdaptiveTimeStepper::advance() ..."; - - iterationRegister_.registerFinalCount(R1_.count); - relativeTime_ += relativeTau_; - current_ = R1_.updaters; - - //UpdatersWithCount emptyR1; - //R1_ = emptyR1; - R1_ = R2; - - std::cout << " done" << std::endl; - - return iterationRegister_; -} - -template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms> -typename AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::UpdatersWithCount -AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step( - Updaters const &oldUpdaters, double rTime, double rTau) { - UpdatersWithCount newUpdatersAndCount = {oldUpdaters.clone(), {}}; - newUpdatersAndCount.count = - MyCoupledTimeStepper(finalTime_, parset_, contactNetwork_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_, - newUpdatersAndCount.updaters, errorNorms_, - externalForces_) - .step(rTime, rTau); - iterationRegister_.registerCount(newUpdatersAndCount.count); - return newUpdatersAndCount; -} - -#include "adaptivetimestepper_tmpl.cc" diff --git a/src/time-stepping/adaptivetimestepper_tmpl.cc b/src/time-stepping/adaptivetimestepper_tmpl.cc deleted file mode 100644 index fcb100f4..00000000 --- a/src/time-stepping/adaptivetimestepper_tmpl.cc +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MY_DIM -#error MY_DIM unset -#endif - -#include "../explicitgrid.hh" -#include "../explicitvectors.hh" - -#include <dune/solvers/norms/energynorm.hh> - -#include "../spatial-solving/solverfactory_tmpl.cc" -#include "../data-structures/contactnetwork_tmpl.cc" - -#include "rate/rateupdater.hh" -#include "state/stateupdater.hh" -#include "updaters.hh" - -using BoundaryNodes = typename MyContactNetwork::BoundaryNodes; -using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions; - -using MyStateUpdater = StateUpdater<ScalarVector, Vector>; -using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>; -using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>; - -using ErrorNorms = typename MyContactNetwork::StateEnergyNorms; - -using MyAdaptiveTimeStepper = AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>; -template class AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>; diff --git a/src/time-stepping/coupledtimestepper_tmpl.cc b/src/time-stepping/coupledtimestepper_tmpl.cc deleted file mode 100644 index 3df79591..00000000 --- a/src/time-stepping/coupledtimestepper_tmpl.cc +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MY_DIM -#error MY_DIM unset -#endif - -#include "../explicitgrid.hh" -#include "../explicitvectors.hh" - -#include <dune/solvers/norms/energynorm.hh> - -#include "../spatial-solving/solverfactory_tmpl.cc" -#include "../data-structures/contactnetwork_tmpl.cc" - -#include "rate/rateupdater.hh" -#include "state/stateupdater.hh" -#include "updaters.hh" - -using BoundaryNodes = typename MyContactNetwork::BoundaryNodes; -using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions; - -using MyStateUpdater = StateUpdater<ScalarVector, Vector>; -using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>; -using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>; - -using ErrorNorms = typename MyContactNetwork::StateEnergyNorms; - - -template class CoupledTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>; diff --git a/todo.txt b/todo.txt deleted file mode 100644 index 1a337f71..00000000 --- a/todo.txt +++ /dev/null @@ -1,29 +0,0 @@ ------------- --- ToDo -- ------------- - - -1. LevelContactNetwork - - -1. build n-body system - Data structure: LevelContactNetwork - Factories: StackedBlocksFactory - - - extend to multilevel LevelContactNetwork - - write new multilevel Cantor network factory - -2. initialize/set up program state - Data structure: ProgramState - - - test setupInitialConditions() - -3. assemble RSD friction - -4. set up TNNMG solver - - rate updater - - state updater - -5. adaptive time stepper - - -- GitLab