diff --git a/.vscode/settings.json b/.vscode/settings.json index cb180ef037..74acf4f946 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,9 @@ }, "files.associations": { "*.icc": "cpp", - "iosfwd": "cpp" + "iosfwd": "cpp", + "*.tcc": "cpp", + "fstream": "cpp" }, "python.formatting.autopep8Args": [ "-max-line-length", diff --git a/configure.ac b/configure.ac index 3a8d2a0df4..bac1e411d1 100644 --- a/configure.ac +++ b/configure.ac @@ -199,6 +199,7 @@ AC_CONFIG_FILES([Makefile libsrc/pylith/feassemble/Makefile libsrc/pylith/fekernels/Makefile libsrc/pylith/faults/Makefile + libsrc/pylith/sources/Makefile libsrc/pylith/friction/Makefile libsrc/pylith/materials/Makefile libsrc/pylith/meshio/Makefile @@ -211,6 +212,7 @@ AC_CONFIG_FILES([Makefile modulesrc/include/Makefile modulesrc/bc/Makefile modulesrc/faults/Makefile + modulesrc/sources/Makefile modulesrc/feassemble/Makefile modulesrc/friction/Makefile modulesrc/materials/Makefile @@ -236,6 +238,7 @@ AC_CONFIG_FILES([Makefile tests/libtests/problems/data/Makefile tests/libtests/meshio/data/Makefile tests/libtests/scales/Makefile + tests/libtests/sources/Makefile tests/libtests/topology/Makefile tests/libtests/topology/data/Makefile tests/libtests/testing/Makefile @@ -250,6 +253,8 @@ AC_CONFIG_FILES([Makefile tests/mmstests/incompressibleelasticity/nofaults-2d/Makefile tests/mmstests/poroelasticity/Makefile tests/mmstests/poroelasticity/nofaults-2d/Makefile + tests/mmstests/sources/Makefile + tests/mmstests/sources/momenttensor-2d/Makefile tests/fullscale/Makefile tests/fullscale/cornercases/Makefile tests/fullscale/cornercases/nofaults-2d/Makefile diff --git a/docs/user/components/index.md b/docs/user/components/index.md index 1a55b970e3..4a61a02dea 100644 --- a/docs/user/components/index.md +++ b/docs/user/components/index.md @@ -14,6 +14,7 @@ faults/index.md materials/index.md meshio/index.md problems/index.md +sources/index.md testing/index.md topology/index.md utils/index.md diff --git a/docs/user/components/sources/AuxSubfieldsMomentTensorForce.md b/docs/user/components/sources/AuxSubfieldsMomentTensorForce.md new file mode 100644 index 0000000000..a33e7a456e --- /dev/null +++ b/docs/user/components/sources/AuxSubfieldsMomentTensorForce.md @@ -0,0 +1,29 @@ +# AuxSubfieldsMomentTensorForce + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.AuxSubfieldsMomentTensorForce` +:Journal name: `auxsubfieldsmomenttensorforce` + +Container for moment tensor force auxiliary subfields. + +This component defines the discretization for the moment tensor and time delay auxiliary subfields. + +## Pyre Facilities + +* `moment_tensor`: Moment tensor subfield. + - **current value**: 'subfield', from {default} + - **configurable as**: subfield, moment_tensor +* `time_delay`: Time delay subfield. + - **current value**: 'subfield', from {default} + - **configurable as**: subfield, time_delay + +## Example + +Example of setting `AuxSubfieldsMomentTensorForce` Pyre properties and facilities in a parameter file. + +:::{code-block} cfg +[pylithapp.problem.sources.source] +auxiliary_subfields.moment_tensor.basis_order = 0 +auxiliary_subfields.time_delay.basis_order = 0 +::: + diff --git a/docs/user/components/sources/AuxSubfieldsSourceTime.md b/docs/user/components/sources/AuxSubfieldsSourceTime.md new file mode 100644 index 0000000000..d94c10b940 --- /dev/null +++ b/docs/user/components/sources/AuxSubfieldsSourceTime.md @@ -0,0 +1,25 @@ +# AuxSubfieldsSourceTime + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.AuxSubfieldsSourceTime` +:Journal name: `auxsubfieldssourcetime` + +Container for source time function auxiliary subfields. + +This component defines the discretization for the center frequency auxiliary subfield used by wavelet source time functions. + +## Pyre Facilities + +* `center_frequency`: Center frequency subfield. + - **current value**: 'subfield', from {default} + - **configurable as**: subfield, center_frequency + +## Example + +Example of setting `AuxSubfieldsSourceTime` Pyre properties and facilities in a parameter file. + +:::{code-block} cfg +[pylithapp.problem.sources.source] +source_time_function.auxiliary_subfields.center_frequency.basis_order = 0 +::: + diff --git a/docs/user/components/sources/GaussianWavelet.md b/docs/user/components/sources/GaussianWavelet.md new file mode 100644 index 0000000000..82fdc72eaa --- /dev/null +++ b/docs/user/components/sources/GaussianWavelet.md @@ -0,0 +1,41 @@ +# GaussianWavelet + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.GaussianWavelet` +:Journal name: `gaussianwavelet` + +Gaussian wavelet source time function. + +The Gaussian wavelet provides a smooth pulse. + +The wavelet is defined as: + +$S(t) = \frac{1}{2\pi^2 f_0^2} \exp\left(-\pi^2 f_0^2 (t-t_d)^2\right)$ + +where $f_0$ is the center frequency and $t_d$ is the time delay. + +Implements `SourceTimeFunctionMomentTensorForce`. + +## Pyre Facilities + +* `auxiliary_subfields`: Discretization information for source time function parameters. + - **current value**: 'auxiliary_subfields', from {file='...', line=..., function='__set__'} + - **configurable as**: auxiliary_subfields + +## Example + +Example of setting `GaussianWavelet` Pyre properties and facilities in a parameter file. + +:::{code-block} cfg +[pylithapp.problem.sources.source] +source_time_function = pylith.sources.GaussianWavelet + +# Center frequency specified in the auxiliary field database +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = Source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_delay, center_frequency] +db_auxiliary_field.data = [1.0e12*Pa*s, 1.0e12*Pa*s, 0.0*Pa*s, 1.0e12*Pa*s, 0.0*s, 5.0] + +source_time_function.auxiliary_subfields.center_frequency.basis_order = 0 +::: + diff --git a/docs/user/components/sources/MomentTensorForce.md b/docs/user/components/sources/MomentTensorForce.md new file mode 100644 index 0000000000..818b23622b --- /dev/null +++ b/docs/user/components/sources/MomentTensorForce.md @@ -0,0 +1,84 @@ +# MomentTensorForce + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.MomentTensorForce` +:Journal name: `momenttensorforce` + +Moment tensor point source. + +This component implements a point source using a moment tensor representation. +The moment tensor describes the equivalent body forces of a seismic source. +The temporal evolution of the source is controlled by a source time function. + +Implements `Source`. + +## Pyre Facilities + +* `auxiliary_subfields`: Discretization information for auxiliary subfields. + - **current value**: 'auxiliary_subfields', from {file='...', line=..., function='__set__'} + - **configurable as**: auxiliary_subfields +* `db_auxiliary_field`: Database for source parameters. + - **current value**: 'simpledb', from {default} + - **configurable as**: simpledb, db_auxiliary_field +* `derived_subfields`: Discretization of derived subfields. + - **current value**: 'emptybin', from {default} + - **configurable as**: emptybin, derived_subfields +* `observers`: Observers (e.g., output). + - **current value**: 'singlephysicsobserver', from {default} + - **configurable as**: singlephysicsobserver, observers +* `reader`: Reader for source points list. + - **current value**: 'pointslist', from {default} + - **configurable as**: pointslist, reader +* `source_time_function`: Source time function for moment tensor force. + - **current value**: 'timehistorywavelet', from {default} + - **configurable as**: timehistorywavelet, source_time_function + +## Pyre Properties + +* `description`=\: Descriptive label for source. + - **default value**: '' + - **current value**: '', from {default} + - **validator**: +* `field`=\: Solution subfield associated with source. + - **default value**: 'displacement' + - **current value**: 'displacement', from {default} +* `label`=\: Name of label for source. + - **default value**: 'source-id' + - **current value**: 'source-id', from {default} +* `label_value`=\: Value of label identifying source. + - **default value**: 1 + - **current value**: 1, from {default} + +## Example + +Example of setting `MomentTensorForce` Pyre properties and facilities in a parameter file. + +:::{code-block} cfg +[pylithapp.problem] +sources = [source] +sources.source = pylith.sources.MomentTensorForce + +[pylithapp.problem.sources.source] +description = Earthquake source +label_value = 2 + +# Specify source locations +reader.filename = source_sites.txt +reader.coordsys = spatialdata.geocoords.CSCart +reader.coordsys.space_dim = 2 + +# Use Ricker wavelet source time function +source_time_function = pylith.sources.RickerWavelet + +# Source parameters (moment tensor and time delay) +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = Source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_delay, center_frequency] +db_auxiliary_field.data = [1.0e12*Pa*s, 1.0e12*Pa*s, 0.0*Pa*s, 1.0e12*Pa*s, 0.0*s, 5.0] + +# Discretization of auxiliary subfields +auxiliary_subfields.moment_tensor.basis_order = 0 +auxiliary_subfields.time_delay.basis_order = 0 +source_time_function.auxiliary_subfields.center_frequency.basis_order = 0 +::: + diff --git a/docs/user/components/sources/RickerWavelet.md b/docs/user/components/sources/RickerWavelet.md new file mode 100644 index 0000000000..9443d5a040 --- /dev/null +++ b/docs/user/components/sources/RickerWavelet.md @@ -0,0 +1,42 @@ +# RickerWavelet + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.RickerWavelet` +:Journal name: `rickerwavelet` + +Ricker wavelet source time function. + +The Ricker wavelet (Mexican hat wavelet) is the negative normalized second derivative of a Gaussian. +It is commonly used as a source time function in seismic wave propagation studies. + +The wavelet is defined as: + +$S(t) = \left(1 - 2\pi^2 f_0^2 (t-t_d)^2\right) \exp\left(-\pi^2 f_0^2 (t-t_d)^2\right)$ + +where $f_0$ is the center frequency and $t_d$ is the time delay. + +Implements `SourceTimeFunctionMomentTensorForce`. + +## Pyre Facilities + +* `auxiliary_subfields`: Discretization information for source time function parameters. + - **current value**: 'auxiliary_subfields', from {file='...', line=..., function='__set__'} + - **configurable as**: auxiliary_subfields + +## Example + +Example of setting `RickerWavelet` Pyre properties and facilities in a parameter file. + +:::{code-block} cfg +[pylithapp.problem.sources.source] +source_time_function = pylith.sources.RickerWavelet + +# Center frequency specified in the auxiliary field database +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = Source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_delay, center_frequency] +db_auxiliary_field.data = [1.0e12*Pa*s, 1.0e12*Pa*s, 0.0*Pa*s, 1.0e12*Pa*s, 0.0*s, 5.0] + +source_time_function.auxiliary_subfields.center_frequency.basis_order = 0 +::: + diff --git a/docs/user/components/sources/Source.md b/docs/user/components/sources/Source.md new file mode 100644 index 0000000000..060a404c78 --- /dev/null +++ b/docs/user/components/sources/Source.md @@ -0,0 +1,45 @@ +# Source + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.Source` +:Journal name: `source` + +Abstract base class for point sources. + +This is the base class for all point source implementations in PyLith. +Point sources are used to specify internal forcing terms at discrete points within the domain. + +## Pyre Facilities + +* `auxiliary_subfields`: Discretization information for auxiliary subfields. + - **current value**: 'emptybin', from {default} + - **configurable as**: emptybin, auxiliary_subfields +* `db_auxiliary_field`: Database for source parameters. + - **current value**: 'simpledb', from {default} + - **configurable as**: simpledb, db_auxiliary_field +* `derived_subfields`: Discretization of derived subfields. + - **current value**: 'emptybin', from {default} + - **configurable as**: emptybin, derived_subfields +* `observers`: Observers (e.g., output). + - **current value**: 'singlephysicsobserver', from {default} + - **configurable as**: singlephysicsobserver, observers +* `reader`: Reader for source points list. + - **current value**: 'pointslist', from {default} + - **configurable as**: pointslist, reader + +## Pyre Properties + +* `description`=\: Descriptive label for source. + - **default value**: '' + - **current value**: '', from {default} + - **validator**: +* `field`=\: Solution subfield associated with source. + - **default value**: 'displacement' + - **current value**: 'displacement', from {default} +* `label`=\: Name of label for source. + - **default value**: 'source-id' + - **current value**: 'source-id', from {default} +* `label_value`=\: Value of label identifying source. + - **default value**: 1 + - **current value**: 1, from {default} + diff --git a/docs/user/components/sources/SourceTimeFunctionMomentTensorForce.md b/docs/user/components/sources/SourceTimeFunctionMomentTensorForce.md new file mode 100644 index 0000000000..46d8ed60dd --- /dev/null +++ b/docs/user/components/sources/SourceTimeFunctionMomentTensorForce.md @@ -0,0 +1,17 @@ +# SourceTimeFunctionMomentTensorForce + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.SourceTimeFunctionMomentTensorForce` +:Journal name: `sourcetimefunctionmomenttensorforce` + +Abstract base class for source time functions. + +This is the base class for source time functions used with moment tensor force sources. +Derived classes implement specific wavelet types. + +## Pyre Facilities + +* `auxiliary_subfields`: Discretization information for physical properties and state variables. + - **current value**: 'emptybin', from {default} + - **configurable as**: emptybin, auxiliary_subfields + diff --git a/docs/user/components/sources/SquareWavelet.md b/docs/user/components/sources/SquareWavelet.md new file mode 100644 index 0000000000..046e3d0eee --- /dev/null +++ b/docs/user/components/sources/SquareWavelet.md @@ -0,0 +1,41 @@ +# SquareWavelet + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.SquareWavelet` +:Journal name: `squarewavelet` + +Square wavelet (step function) source time function. + +The square wavelet is a Heaviside step function that activates the source at the time delay. + +The wavelet is defined as: + +$S(t) = \begin{cases} 0 & t < t_d \\ 1 & t \geq t_d \end{cases}$ + +where $t_d$ is the time delay. + +Implements `SourceTimeFunctionMomentTensorForce`. + +## Pyre Facilities + +* `auxiliary_subfields`: Discretization information for source time function parameters. + - **current value**: 'auxiliary_subfields', from {file='...', line=..., function='__set__'} + - **configurable as**: auxiliary_subfields + +## Example + +Example of setting `SquareWavelet` Pyre properties and facilities in a parameter file. + +:::{code-block} cfg +[pylithapp.problem.sources.source] +source_time_function = pylith.sources.SquareWavelet + +# Source parameters specified in the auxiliary field database +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = Source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_delay, center_frequency] +db_auxiliary_field.data = [1.0e12*Pa*s, 1.0e12*Pa*s, 0.0*Pa*s, 1.0e12*Pa*s, 0.5*s, 1.0] + +source_time_function.auxiliary_subfields.center_frequency.basis_order = 0 +::: + diff --git a/docs/user/components/sources/TimeHistoryWavelet.md b/docs/user/components/sources/TimeHistoryWavelet.md new file mode 100644 index 0000000000..44890fe64a --- /dev/null +++ b/docs/user/components/sources/TimeHistoryWavelet.md @@ -0,0 +1,48 @@ +# TimeHistoryWavelet + +% WARNING: Do not edit; this is a generated file! +:Full name: `pylith.sources.TimeHistoryWavelet` +:Journal name: `timehistorywavelet` + +User-specified time history source time function. + +This source time function allows specification of an arbitrary wavelet shape using a time history database. +The time history should contain normalized amplitudes (typically between 0 and 1) as a function of time. + +Implements `SourceTimeFunctionMomentTensorForce`. + +## Pyre Facilities + +* `auxiliary_subfields`: Discretization information for source time function parameters. + - **current value**: 'auxiliary_subfields', from {file='...', line=..., function='__set__'} + - **configurable as**: auxiliary_subfields +* `time_history`: Time history with normalized amplitude as a function of time. + - **current value**: 'nullcomponent', from {default} + - **configurable as**: nullcomponent, time_history + +## Pyre Properties + +* `use_time_history`=\: Use time history term in time-dependent expression. + - **default value**: True + - **current value**: True, from {default} + +## Example + +Example of setting `TimeHistoryWavelet` Pyre properties and facilities in a parameter file. + +:::{code-block} cfg +[pylithapp.problem.sources.source] +source_time_function = pylith.sources.TimeHistoryWavelet + +# Specify time history database +source_time_function.time_history = spatialdata.spatialdb.TimeHistory +source_time_function.time_history.description = Source time history +source_time_function.time_history.filename = wavelet.timedb + +# Source parameters specified in the auxiliary field database +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = Source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_history_start_time] +db_auxiliary_field.data = [1.0e12*Pa*s, 1.0e12*Pa*s, 0.0*Pa*s, 1.0e12*Pa*s, 0.0*s] +::: + diff --git a/docs/user/components/sources/index.md b/docs/user/components/sources/index.md new file mode 100644 index 0000000000..e57deaf671 --- /dev/null +++ b/docs/user/components/sources/index.md @@ -0,0 +1,19 @@ +# sources + +% WARNING: Do not edit; this is a generated file. + +:::{toctree} +--- +maxdepth: 1 +--- +Source.md +MomentTensorForce.md +SourceTimeFunctionMomentTensorForce.md +RickerWavelet.md +GaussianWavelet.md +SquareWavelet.md +TimeHistoryWavelet.md +AuxSubfieldsMomentTensorForce.md +AuxSubfieldsSourceTime.md +::: + diff --git a/docs/user/governingeqns/elasticity/infinitesimal-strain-dynamic.md b/docs/user/governingeqns/elasticity/infinitesimal-strain-dynamic.md index 419e81b5b9..f5caffd656 100644 --- a/docs/user/governingeqns/elasticity/infinitesimal-strain-dynamic.md +++ b/docs/user/governingeqns/elasticity/infinitesimal-strain-dynamic.md @@ -9,7 +9,7 @@ We introduce the velocity as a unknown, $\vec{v}=\frac{\partial u}{\partial t}$, % Displacement-velocity \frac{\partial \vec{u}}{\partial t} &= \vec{v} \text{ in } \Omega, \\ % Elasticity -\rho(\vec{x}) \frac{\partial\vec{v}}{\partial t} &= \vec{f}(\vec{x},t) + \boldsymbol{\nabla} \cdot \boldsymbol{\sigma}(\vec{u}) \text{ in } \Omega, \\ +\rho(\vec{x}) \frac{\partial\vec{v}}{\partial t} &= \vec{f}(\vec{x},t) + \boldsymbol{\nabla} \cdot \boldsymbol{\sigma}(\vec{u}) + \boldsymbol{\nabla} \cdot {\bf M} \text{ in } \Omega, \\ % Neumann \boldsymbol{\sigma} \cdot \vec{n} &= \vec{\tau}(\vec{x},t) \text{ on } \Gamma_\tau, \\ % Dirichlet diff --git a/docs/user/physics/index.md b/docs/user/physics/index.md index 8bbbaf27b0..839d69d6d6 100644 --- a/docs/user/physics/index.md +++ b/docs/user/physics/index.md @@ -5,4 +5,5 @@ materials/index.md bc/index.md faults/index.md +sources/index.md ::: diff --git a/docs/user/physics/sources/index.md b/docs/user/physics/sources/index.md new file mode 100644 index 0000000000..1390d526aa --- /dev/null +++ b/docs/user/physics/sources/index.md @@ -0,0 +1,44 @@ +(sec-user-physics-sources)= +# Point Sources + +Point sources provide a mechanism for specifying internal sources within the domain, such as moment tensor sources for earthquake simulations or other force sources. +These sources are implemented at discrete points rather than on surfaces like boundary conditions or faults. + +## Point Source Implementation + +Point sources in PyLith are implemented using a moment tensor force representation. +The source is specified at discrete points in the domain, and the moment tensor components define the force couples applied at each point. +The temporal behavior of the source is controlled by a source time function, which can be an analytical wavelet or a user-specified time history. + +## Specifying Point Sources + +There are three basic steps in specifying point sources: + +1. Create a file specifying the locations of the point sources. +2. Set the parameters for each source using `cfg` files or command line arguments. +3. Specify the spatial variation in source parameters (moment tensor, time delay) using a spatial database. +4. Select a source time function and specify its parameters. + +## Arrays of Source Components + +A dynamic array of source components associates a name (string) with each source. +The default source is `MomentTensorForce`. + +```{code-block} cfg +--- +caption: Array of sources in a `cfg` file. +--- +[pylithapp.problem] +# Array of point sources +sources = [source1, source2] + +# Default source is MomentTensorForce +# Both sources use the default type +``` + +## Source Implementations + +:::{toctree} +moment-tensor-force.md +::: + diff --git a/docs/user/physics/sources/moment-tensor-force.md b/docs/user/physics/sources/moment-tensor-force.md new file mode 100644 index 0000000000..1922926fcc --- /dev/null +++ b/docs/user/physics/sources/moment-tensor-force.md @@ -0,0 +1,180 @@ +(sec-user-physics-moment-tensor-force)= +# Moment Tensor Force (`MomentTensorForce`) + +The `MomentTensorForce` component implements point sources using a moment tensor representation. +This is commonly used in seismology to represent earthquake sources or other internal force sources. + +A moment tensor describes the equivalent body forces of a seismic source. +In 2D, the moment tensor has 4 independent components (symmetric $2 \times 2$ tensor), while in 3D it has 6 independent components (symmetric $3 \times 3$ tensor). + +The temporal evolution of the source is controlled by a source time function, which multiplies the moment tensor amplitude at each time step. +PyLith provides several built-in source time functions as well as support for user-defined time histories. + +## Source Parameters + +The source parameters include the moment tensor components and a time delay. +The time delay allows offsetting the source time function for each point source, enabling simulation of rupture propagation. + +```{table} Values in the auxiliary field spatial database for MomentTensorForce. +:name: tab:source:momenttensorforce:auxiliary +| Subfield | Components (2D) | Components (3D) | +|:-------------------|:---------------------------|:-------------------------------------| +| `moment_tensor` | xx, yy, xy, zz | xx, yy, zz, xy, yz, xz | +| `time_delay` | -- | -- | +``` + +## Source Points File + +The locations of point sources are specified in a text file. +The file contains the coordinates of each source point along with an optional name identifier. + +```{code-block} text +--- +caption: Example source points file format. +--- +# Comment lines start with # +# x y [z] name +0.0 0.0 source1 +1000.0 500.0 source2 +``` + +:::{seealso} +See [`MomentTensorForce` Component](../../components/sources/MomentTensorForce.md) for the Pyre properties and facilities and configuration examples. +::: + +## Source Time Functions + +The source time function controls the temporal evolution of the moment tensor force. +PyLith supports the following source time functions: + +:`RickerWavelet`: A Ricker wavelet (Mexican hat wavelet) commonly used in seismic modeling. +:`GaussianWavelet`: A Gaussian wavelet. +:`SquareWavelet`: A step function (Heaviside function). +:`TimeHistoryWavelet`: A user-specified time function from a time history database. + +### Ricker Wavelet (`RickerWavelet`) + +The Ricker wavelet, also known as the Mexican hat wavelet, is the negative normalized second derivative of a Gaussian function. +It is commonly used as a source time function in seismic wave propagation studies because it has a well-defined frequency content and compact time duration. + +The Ricker wavelet is defined as: +% +\begin{gather} + S(t) = \left(1 - 2\pi^2 f_0^2 (t-t_d)^2\right) \exp\left(-\pi^2 f_0^2 (t-t_d)^2\right) +\end{gather} +% +where $f_0$ is the center frequency and $t_d$ is the time delay. + +```{table} Values in the auxiliary field spatial database for RickerWavelet. +:name: tab:source:rickerwavelet:auxiliary +| Subfield | Description | +|:--------------------|:-----------------------------------------| +| `center_frequency` | Center frequency of the wavelet ($f_0$) | +``` + +:::{seealso} +See [`RickerWavelet` Component](../../components/sources/RickerWavelet.md) for the Pyre properties and facilities and configuration examples. +::: + +### Gaussian Wavelet (`GaussianWavelet`) + +The Gaussian wavelet provides a smooth pulse. +It is defined as: +% +\begin{gather} + S(t) = \frac{1}{2\pi^2 f_0^2} \exp\left(-\pi^2 f_0^2 (t-t_d)^2\right) +\end{gather} +% +where $f_0$ is the center frequency and $t_d$ is the time delay. + +:::{note} +The implementation uses the negative of the second derivative of a Gaussian. +::: + +```{table} Values in the auxiliary field spatial database for GaussianWavelet. +:name: tab:source:gaussianwavelet:auxiliary +| Subfield | Description | +|:--------------------|:-----------------------------------------| +| `center_frequency` | Center frequency of the wavelet ($f_0$) | +``` + +:::{seealso} +See [`GaussianWavelet` Component](../../components/sources/GaussianWavelet.md) for the Pyre properties and facilities and configuration examples. +::: + +### Square Wavelet (`SquareWavelet`) + +The square wavelet is a step function (Heaviside function) that activates the source at the time delay: +% +\begin{gather} + S(t) = \left\{ \begin{array}{cc} + 0 & t < t_d \\ + 1 & t \geq t_d + \end{array}\right. +\end{gather} +% +where $t_d$ is the time delay. + +```{table} Values in the auxiliary field spatial database for SquareWavelet. +:name: tab:source:squarewavelet:auxiliary +| Subfield | Description | +|:--------------------|:-----------------------------------------| +| `center_frequency` | Not used (placeholder for consistency) | +``` + +:::{seealso} +See [`SquareWavelet` Component](../../components/sources/SquareWavelet.md) for the Pyre properties and facilities and configuration examples. +::: + +### Time History Wavelet (`TimeHistoryWavelet`) + +The time history wavelet allows specification of an arbitrary source time function using a time history database. +The time history should contain normalized amplitudes (typically between 0 and 1) as a function of time. + +```{table} Values in the auxiliary field spatial database for TimeHistoryWavelet. +:name: tab:source:timehistorywavelet:auxiliary +| Subfield | Description | +|:---------------------------|:----------------------------------------------| +| `time_history_start_time` | Start time for the time history | +``` + +:::{seealso} +See [`TimeHistoryWavelet` Component](../../components/sources/TimeHistoryWavelet.md) for the Pyre properties and facilities and configuration examples. +::: + +## Example Configuration + +The following example shows how to configure a moment tensor point source with a Ricker wavelet: + +```{code-block} cfg +--- +caption: Example configuration for a moment tensor point source with Ricker wavelet. +--- +[pylithapp.problem] +sources = [source] +sources.source = pylith.sources.MomentTensorForce + +[pylithapp.problem.sources.source] +description = Earthquake source +label_value = 2 + +# Specify source locations +reader.filename = source_sites.txt +reader.coordsys = spatialdata.geocoords.CSCart +reader.coordsys.space_dim = 2 + +# Use Ricker wavelet source time function +source_time_function = pylith.sources.RickerWavelet + +# Source parameters (moment tensor and time delay) +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = Source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_delay, center_frequency] +db_auxiliary_field.data = [1.0e12*Pa*s, 1.0e12*Pa*s, 0.0*Pa*s, 1.0e12*Pa*s, 0.0*s, 5.0] + +# Discretization of auxiliary subfields +auxiliary_subfields.moment_tensor.basis_order = 0 +auxiliary_subfields.time_delay.basis_order = 0 +source_time_function.auxiliary_subfields.center_frequency.basis_order = 0 +``` + diff --git a/examples/point-source/impulse_gen.py b/examples/point-source/impulse_gen.py new file mode 100644 index 0000000000..f83eba0719 --- /dev/null +++ b/examples/point-source/impulse_gen.py @@ -0,0 +1,29 @@ +import numpy as np + +def generate_ramp_stf(duration=0.5, dt=0.01, max_amplitude=1.0): + time = np.arange(0, duration + dt, dt) + amplitude = max_amplitude - (max_amplitude / duration) * time + return time, amplitude + +# Parameters +duration = 0.10 +dt = 0.001 +max_amp = 1.0 +time, amplitude = generate_ramp_stf(duration, dt, max_amp) + +# Write in the same format as impulse.timedb +with open("ramp.timedb", "w") as f: + f.write("// -*- C++ -*- (tell Emacs to use C++ mode for syntax highlighting)\n") + f.write("//\n") + f.write("// Ramp source time function with linear increase to max amplitude.\n") + f.write("#TIME HISTORY ascii\n") + f.write("TimeHistory {\n") + f.write(f" num-points = {len(time)+1} // number of points in time history\n") + f.write(" time-units = second // units for time\n") + f.write("}\n") + for t, a in zip(time, amplitude): + f.write(f"{t:10.4f} {a:10.4f}\n") + t_final = 999.000 + a_final = 0.000 + f.write(f"{t_final:10.4f} {a_final:10.4f}\n") + diff --git a/examples/point-source/mesh_quad.exo b/examples/point-source/mesh_quad.exo new file mode 100644 index 0000000000..81680a2cec Binary files /dev/null and b/examples/point-source/mesh_quad.exo differ diff --git a/examples/point-source/mesh_quad.jou b/examples/point-source/mesh_quad.jou new file mode 100644 index 0000000000..ce8fc96b5c --- /dev/null +++ b/examples/point-source/mesh_quad.jou @@ -0,0 +1,30 @@ +# ---------------------------------------------------------------------- +# Generate geometry +# ---------------------------------------------------------------------- +playback 'geometry.jou' + +# ---------------------------------------------------------------------- +# Set discretization size +# ---------------------------------------------------------------------- +${dx=120.0*m} +surface all size {dx} + + +# ---------------------------------------------------------------------- +# Generate the mesh +# ---------------------------------------------------------------------- +surface all scheme submap +mesh surface all + +# ---------------------------------------------------------------------- +# Mark entities for boundary conditions, etc. +# ---------------------------------------------------------------------- +playback 'bc.jou' + +# ---------------------------------------------------------------------- +# Export exodus file +# ---------------------------------------------------------------------- +export mesh "mesh_quad.exo" dimension 2 overwrite + + + diff --git a/examples/point-source/pylithapp.cfg b/examples/point-source/pylithapp.cfg new file mode 100644 index 0000000000..16a1b792da --- /dev/null +++ b/examples/point-source/pylithapp.cfg @@ -0,0 +1,124 @@ +[pylithapp.metadata] +# This is not a self-contained simulation configuration file. This +# file only specifies the general parameters common to the simulations +# in this directory. +keywords = [example, 2D] +features = [ + Dynamic simulation, + Implicit-explicit formulation, + Quadrilateral cells, + Runge-Kutta time stepping, + pylith.meshio.MeshIOCubit, + pylith.problems.TimeDependent, + pylith.materials.Elasticity, + pylith.materials.IsotropicLinearElasticity, + spatialdata.spatialdb.UniformDB, + pylith.meshio.DataWriterHDF5, + spatialdata.units.NondimElasticDynamic + ] + +# ---------------------------------------------------------------------- +# journal +# ---------------------------------------------------------------------- +# Turn on some journals to show progress. +[pylithapp.journal] +#device = color-console + +[pylithapp.journal.info] +timedependent = 1 +solution = 1 +meshiocubit = 1 +pylithapp = 1 + +[pylithapp.journal.debug] +timedependent = 0 + + + +# ---------------------------------------------------------------------- +# problem +# ---------------------------------------------------------------------- +[pylithapp.problem] +# Use the nonlinear solver to verify residual and Jacobian are consistent. +solver = linear +formulation = dynamic + +# # Nondimensionalize problem using wave propagation parameters. +# normalizer = spatialdata.units.NondimElasticDynamic +# normalizer.mass_density = 2500.0*kg/m**3 +# normalizer.shear_wave_speed = 1.0*km/s +# normalizer.wave_period = 0.5*s + +defaults.quadrature_order = 1 + + +# Set the discretization for each of the solution subfields. +# +# For a quastistatic simulation with a fault, we have two solution fields: +# (1) displacement and (2) Lagrange multiplier. We use a predefined containter +# to create a solution field with these two subfields. +solution = pylith.problems.SolnDispVel + +solution.subfields.displacement.basis_order = 1 +solution.subfields.velocity.basis_order = 1 + +#solution_observers = [domain] +#solution_observers = [] +#solution_observers.domain.trigger.num_skip = 10 + + +start_time = 0.0*s +end_time = 0.025*s +initial_dt = 0.001*s + +# ---------------------------------------------------------------------- +# materials +# ---------------------------------------------------------------------- +[pylithapp.problem] +# Create an array of one material +materials = [elastic] + +# We use the default material (elasticity) and rheology +# (isotropic, linearly elastic). + +[pylithapp.problem.materials.elastic] +# id must match the values in the mesh material-ids. +description = Elastic material +label_value = 1 +observers = [] +#observers.observer.trigger.num_skip = 10 +# We will use uniform material properties, so we use the UniformDB +# spatial database. +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = Elastic properties +db_auxiliary_field.values = [density, vs, vp] +db_auxiliary_field.data = [1800*kg/m**3, 1.3*km/s, 3.0*km/s] + +# Set the discretization of the material auxiliary fields (properties). +# We have uniform material properties, so we can use a basis order of 0. +auxiliary_subfields.density.basis_order = 0 +bulk_rheology.auxiliary_subfields.bulk_modulus.basis_order = 0 +bulk_rheology.auxiliary_subfields.shear_modulus.basis_order = 0 + +# ---------------------------------------------------------------------- +# PETSc +# ---------------------------------------------------------------------- +[pylithapp.petsc] +ts_type = rk +ts_rk_type = 3bs +ts_adapt_dt_max = 0.1 + +ksp_rtol = 1.0e-8 +ksp_atol = 1.0e-12 +ksp_max_it = 30 +ksp_gmres_restart = 50 +ksp_error_if_not_converged = true + +snes_rtol = 1.0e-10 +snes_atol = 1.0e-10 +snes_error_if_not_converged = true + +# Monitors for debugging +ts_monitor = true + +# End of file diff --git a/examples/point-source/ramp.timedb b/examples/point-source/ramp.timedb new file mode 100644 index 0000000000..d78a94fa91 --- /dev/null +++ b/examples/point-source/ramp.timedb @@ -0,0 +1,110 @@ +// -*- C++ -*- (tell Emacs to use C++ mode for syntax highlighting) +// +// Ramp source time function with linear increase to max amplitude. +#TIME HISTORY ascii +TimeHistory { + num-points = 102 // number of points in time history + time-units = second // units for time +} + 0.0000 1.0000 + 0.0010 0.9900 + 0.0020 0.9800 + 0.0030 0.9700 + 0.0040 0.9600 + 0.0050 0.9500 + 0.0060 0.9400 + 0.0070 0.9300 + 0.0080 0.9200 + 0.0090 0.9100 + 0.0100 0.9000 + 0.0110 0.8900 + 0.0120 0.8800 + 0.0130 0.8700 + 0.0140 0.8600 + 0.0150 0.8500 + 0.0160 0.8400 + 0.0170 0.8300 + 0.0180 0.8200 + 0.0190 0.8100 + 0.0200 0.8000 + 0.0210 0.7900 + 0.0220 0.7800 + 0.0230 0.7700 + 0.0240 0.7600 + 0.0250 0.7500 + 0.0260 0.7400 + 0.0270 0.7300 + 0.0280 0.7200 + 0.0290 0.7100 + 0.0300 0.7000 + 0.0310 0.6900 + 0.0320 0.6800 + 0.0330 0.6700 + 0.0340 0.6600 + 0.0350 0.6500 + 0.0360 0.6400 + 0.0370 0.6300 + 0.0380 0.6200 + 0.0390 0.6100 + 0.0400 0.6000 + 0.0410 0.5900 + 0.0420 0.5800 + 0.0430 0.5700 + 0.0440 0.5600 + 0.0450 0.5500 + 0.0460 0.5400 + 0.0470 0.5300 + 0.0480 0.5200 + 0.0490 0.5100 + 0.0500 0.5000 + 0.0510 0.4900 + 0.0520 0.4800 + 0.0530 0.4700 + 0.0540 0.4600 + 0.0550 0.4500 + 0.0560 0.4400 + 0.0570 0.4300 + 0.0580 0.4200 + 0.0590 0.4100 + 0.0600 0.4000 + 0.0610 0.3900 + 0.0620 0.3800 + 0.0630 0.3700 + 0.0640 0.3600 + 0.0650 0.3500 + 0.0660 0.3400 + 0.0670 0.3300 + 0.0680 0.3200 + 0.0690 0.3100 + 0.0700 0.3000 + 0.0710 0.2900 + 0.0720 0.2800 + 0.0730 0.2700 + 0.0740 0.2600 + 0.0750 0.2500 + 0.0760 0.2400 + 0.0770 0.2300 + 0.0780 0.2200 + 0.0790 0.2100 + 0.0800 0.2000 + 0.0810 0.1900 + 0.0820 0.1800 + 0.0830 0.1700 + 0.0840 0.1600 + 0.0850 0.1500 + 0.0860 0.1400 + 0.0870 0.1300 + 0.0880 0.1200 + 0.0890 0.1100 + 0.0900 0.1000 + 0.0910 0.0900 + 0.0920 0.0800 + 0.0930 0.0700 + 0.0940 0.0600 + 0.0950 0.0500 + 0.0960 0.0400 + 0.0970 0.0300 + 0.0980 0.0200 + 0.0990 0.0100 + 0.1000 0.0000 + 999.0000 0.0000 diff --git a/examples/point-source/source_sites.txt b/examples/point-source/source_sites.txt new file mode 100644 index 0000000000..6c0b234328 --- /dev/null +++ b/examples/point-source/source_sites.txt @@ -0,0 +1,2 @@ +#Site X Y +s000 5000.00 5000.00 \ No newline at end of file diff --git a/examples/point-source/step01_ricker.cfg b/examples/point-source/step01_ricker.cfg new file mode 100644 index 0000000000..399d23fee7 --- /dev/null +++ b/examples/point-source/step01_ricker.cfg @@ -0,0 +1,126 @@ +[pylithapp.metadata] +# y +# ^ +# | +# --> x + +base = [pylithapp.cfg] +description = Ricker source test. +authors = [Robert Walker] +keywords = [Ricker source, time-dependent Dirichlet boundary condition] +arguments = [step01_ricker.cfg] +version = 1.0.0 +pylith_version = [>=3.0, <7.0] + +features = [ + pylith.problems.SolnDispVel, + pylith.bc.DirichletTimeDependent, + spatialdata.spatialdb.ZeroDB + ] + +[pylithapp] +# File with version information and parameters (including defaults). +# +# You can view this file using the pylith_parameters application or +# online at https://geodynamics.github.io/pylith_parameters/. +dump_parameters.filename = output/step01_ricker-parameters.json +problem.progress_monitor.filename = output/step01_ricker-progress.txt + +# Set the name of the problem that will be used to construct the +# output filenames. The default directory for output is 'output'. +problem.defaults.name = step01_ricker + +# ---------------------------------------------------------------------- +# problem +# ---------------------------------------------------------------------- +[pylithapp.problem] +# Use the nonlinear solver to verify residual and Jacobian are consistent. +solver = nonlinear +formulation = dynamic + +# Nondimensionalize problem using wave propagation parameters. +normalizer = spatialdata.units.NondimElasticDynamic +normalizer.mass_density = 2500.0*kg/m**3 +normalizer.shear_wave_speed = 1000.0*m/s +normalizer.wave_period = 1.0*s + +defaults.quadrature_order = 1 + + +# Set the discretization for each of the solution subfields. +# +solution = pylith.problems.SolnDispVel + +solution.subfields.displacement.basis_order = 1 +solution.subfields.velocity.basis_order = 1 + +solution_observers = [domain] + +start_time = 0.0*s +end_time = 1.0*s +initial_dt = 0.01*s +# ---------------------------------------------------------------------- +# sources +# ---------------------------------------------------------------------- + +[pylithapp.problem] +sources = [source] + +sources.source = pylith.sources.MomentTensorForce +[pylithapp.problem.sources] +source.source_time_function = pylith.sources.RickerWavelet + +[pylithapp.problem.sources.source] +description = Ricker Source +label_value = 2 +reader.filename = source_sites.txt +reader.coordsys = spatialdata.geocoords.CSCart +reader.coordsys.space_dim = 2 + +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_delay, center_frequency] +db_auxiliary_field.data = [100*Pa*s, 100*Pa*s, 0.0*Pa*s, 100.0*Pa*s, 0.0*s, 1] + +# Set the discretization of the material auxiliary fields (properties). +# We have uniform material properties, so we can use a basis order of 0. +auxiliary_subfields.moment_tensor.basis_order = 0 +auxiliary_subfields.time_delay.basis_order = 0 +source_time_function.auxiliary_subfields.center_frequency.basis_order = 0 + + + +# ---------------------------------------------------------------------- +# initial conditions +# ---------------------------------------------------------------------- +[pylithapp.problem] +ic = [domain] +ic.domain = pylith.problems.InitialConditionDomain + +[pylithapp.problem.ic.domain] +db = spatialdata.spatialdb.UniformDB +db.description = Initial conditions over domain +db.values = [displacement_x, displacement_y] +db.data = [0.0*m, 0.0*m] + +# ---------------------------------------------------------------------- +# boundary conditions +# ---------------------------------------------------------------------- +[pylithapp.problem] + + +# ---------------------------------------------------------------------- +# PETSc +# ---------------------------------------------------------------------- +[pylithapp.petsc] +ts_type = rk +ts_rk_type = 3bs +ts_adapt_dt_max = 0.001 +dm_partition_view = True + +# ---------------------------------------------------------------------- +# Mesh Generator +# ---------------------------------------------------------------------- +[pylithapp.mesh_generator] +refiner = pylith.topology.RefineUniform +# End of file diff --git a/examples/point-source/step01_time_history.cfg b/examples/point-source/step01_time_history.cfg new file mode 100644 index 0000000000..bc1b188d8f --- /dev/null +++ b/examples/point-source/step01_time_history.cfg @@ -0,0 +1,127 @@ +[pylithapp.metadata] +# y +# ^ +# | +# --> x + +base = [pylithapp.cfg] +description = Time History MT test. +authors = [Robert Walker] +keywords = [Time History Wavelet, time-dependent Dirichlet boundary condition] +arguments = [step01_time_history.cfg] +version = 1.0.0 +pylith_version = [>=3.0, <7.0] + +features = [ + pylith.problems.SolnDispVel, + pylith.bc.DirichletTimeDependent, + spatialdata.spatialdb.ZeroDB + ] + +[pylithapp] +# File with version information and parameters (including defaults). +# +# You can view this file using the pylith_parameters application or +# online at https://geodynamics.github.io/pylith_parameters/. +dump_parameters.filename = output/step01_ricker-parameters.json +problem.progress_monitor.filename = output/step01_ricker-progress.txt + +# Set the name of the problem that will be used to construct the +# output filenames. The default directory for output is 'output'. +problem.defaults.name = step01_time_history + +# ---------------------------------------------------------------------- +# problem +# ---------------------------------------------------------------------- +[pylithapp.problem] +# Use the nonlinear solver to verify residual and Jacobian are consistent. +solver = nonlinear +formulation = dynamic + +# Nondimensionalize problem using wave propagation parameters. +normalizer = spatialdata.units.NondimElasticDynamic +normalizer.mass_density = 2500.0*kg/m**3 +normalizer.shear_wave_speed = 1000.0*m/s +normalizer.wave_period = 1.0*s + +defaults.quadrature_order = 1 + + +# Set the discretization for each of the solution subfields. +# +solution = pylith.problems.SolnDispVel + +solution.subfields.displacement.basis_order = 1 +solution.subfields.velocity.basis_order = 1 + +solution_observers = [domain] + +start_time = 0.0*s +end_time = 0.1*s +initial_dt = 0.01*s +# ---------------------------------------------------------------------- +# sources +# ---------------------------------------------------------------------- + +[pylithapp.problem] +sources = [source] + +sources.source = pylith.sources.MomentTensorForce + +[pylithapp.problem.sources.source] +description = Time History Source +label_value = 2 +reader.filename = source_sites.txt +reader.coordsys = spatialdata.geocoords.CSCart +reader.coordsys.space_dim = 2 +source_time_function = pylith.sources.TimeHistoryWavelet + + +#useTimeHistory = True + +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_history_start_time] +db_auxiliary_field.data = [100*Pa*s, 100*Pa*s, 0.0*Pa*s, 100.0*Pa*s, 0.0*s] +source_time_function.time_history = spatialdata.spatialdb.TimeHistory +source_time_function.time_history.description = Ramp time history +source_time_function.time_history.filename = ramp.timedb + + +# Set the discretization of the material auxiliary fields (properties). +# We have uniform material properties, so we can use a basis order of 0. +auxiliary_subfields.moment_tensor.basis_order = 0 +#source_time_function.auxiliary_subfields.time_history_amplitude.basis_order = 0 +#source_time_function.auxiliary_subfields.time_history_start_time.basis_order = 0 + + + +# ---------------------------------------------------------------------- +# initial conditions +# ---------------------------------------------------------------------- +[pylithapp.problem] +ic = [domain] +ic.domain = pylith.problems.InitialConditionDomain + +[pylithapp.problem.ic.domain] +db = spatialdata.spatialdb.UniformDB +db.description = Initial conditions over domain +db.values = [displacement_x, displacement_y] +db.data = [0.0*m, 0.0*m] + +# ---------------------------------------------------------------------- +# boundary conditions +# ---------------------------------------------------------------------- +[pylithapp.problem] + + +# ---------------------------------------------------------------------- +# PETSc +# ---------------------------------------------------------------------- +[pylithapp.petsc] +ts_type = rk +ts_rk_type = 3bs +ts_adapt_dt_max = 0.001 + + +# End of file diff --git a/examples/point-source/step02_time_history.cfg b/examples/point-source/step02_time_history.cfg new file mode 100644 index 0000000000..22043befed --- /dev/null +++ b/examples/point-source/step02_time_history.cfg @@ -0,0 +1,133 @@ +[pylithapp.metadata] +# y +# ^ +# | +# --> x + +base = [pylithapp.cfg] +description = Time History MT test. +authors = [Robert Walker] +keywords = [Time History Wavelet, time-dependent Dirichlet boundary condition] +arguments = [step02_time_history.cfg] +version = 1.0.0 +pylith_version = [>=3.0, <7.0] + +features = [ + pylith.problems.SolnDispVel, + pylith.bc.DirichletTimeDependent, + spatialdata.spatialdb.ZeroDB + ] + +[pylithapp] +# File with version information and parameters (including defaults). +# +# You can view this file using the pylith_parameters application or +# online at https://geodynamics.github.io/pylith_parameters/. +dump_parameters.filename = output/step02_time_history-parameters.json +problem.progress_monitor.filename = output/step02_time_history-progress.txt + +# Set the name of the problem that will be used to construct the +# output filenames. The default directory for output is 'output'. +problem.defaults.name = step02_time_history + +# ---------------------------------------------------------------------- +# problem +# ---------------------------------------------------------------------- +[pylithapp.problem] +# Use the nonlinear solver to verify residual and Jacobian are consistent. +solver = nonlinear +formulation = dynamic + +# Nondimensionalize problem using wave propagation parameters. +normalizer = spatialdata.units.NondimElasticDynamic +normalizer.mass_density = 2500.0*kg/m**3 +normalizer.shear_wave_speed = 1000.0*m/s +normalizer.wave_period = 1.0*s + +defaults.quadrature_order = 1 + + +# Set the discretization for each of the solution subfields. +# +solution = pylith.problems.SolnDispVel + +solution.subfields.displacement.basis_order = 1 +solution.subfields.velocity.basis_order = 1 + +solution_observers = [domain] +#solution_observers.domain.trigger.num_skip = 10 + +start_time = 0.0*s +end_time = 1.0*s +initial_dt = 0.01*s +# ---------------------------------------------------------------------- +# sources +# ---------------------------------------------------------------------- + +[pylithapp.problem] +sources = [source] + +sources.source = pylith.sources.MomentTensorForce + +[pylithapp.problem.sources.source] +description = Time History Source +label_value = 2 +reader.filename = source_sites.txt +reader.coordsys = spatialdata.geocoords.CSCart +reader.coordsys.space_dim = 2 +source_time_function = pylith.sources.TimeHistoryWavelet +#observer.trigger.num_skip = 10 +observers = [] +#useTimeHistory = True + +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_history_start_time] +db_auxiliary_field.data = [100*Pa*s, 100*Pa*s, 0.0*Pa*s, 100.0*Pa*s, 0.0*s] +source_time_function.time_history = spatialdata.spatialdb.TimeHistory +source_time_function.time_history.description = ramp time history +source_time_function.time_history.filename = ramp.timedb + + +# Set the discretization of the material auxiliary fields (properties). +# We have uniform material properties, so we can use a basis order of 0. +auxiliary_subfields.moment_tensor.basis_order = 0 +#source_time_function.auxiliary_subfields.time_history_amplitude.basis_order = 0 +#source_time_function.auxiliary_subfields.time_history_start_time.basis_order = 0 + + + +# ---------------------------------------------------------------------- +# initial conditions +# ---------------------------------------------------------------------- +[pylithapp.problem] +ic = [domain] +ic.domain = pylith.problems.InitialConditionDomain + +[pylithapp.problem.ic.domain] +db = spatialdata.spatialdb.UniformDB +db.description = Initial conditions over domain +db.values = [displacement_x, displacement_y] +db.data = [0.0*m, 0.0*m] + +# ---------------------------------------------------------------------- +# boundary conditions +# ---------------------------------------------------------------------- +[pylithapp.problem] + + +# ---------------------------------------------------------------------- +# PETSc +# ---------------------------------------------------------------------- +[pylithapp.petsc] +ts_type = rk +ts_rk_type = 3bs +ts_adapt_dt_max = 0.001 + +# ---------------------------------------------------------------------- +# Mesh Generator +# ---------------------------------------------------------------------- +[pylithapp.mesh_generator] +refiner = pylith.topology.RefineUniform + +# End of file diff --git a/examples/point-source/step03_ricker.cfg b/examples/point-source/step03_ricker.cfg new file mode 100644 index 0000000000..8e81b8c2fd --- /dev/null +++ b/examples/point-source/step03_ricker.cfg @@ -0,0 +1,171 @@ +[pylithapp.metadata] +# y +# ^ +# | +# --> x + +base = [pylithapp.cfg] +description = Ricker source test. +authors = [Robert Walker] +keywords = [Ricker source, time-dependent Dirichlet boundary condition] +arguments = [step03_ricker.cfg] +version = 1.0.0 +pylith_version = [>=3.0, <7.0] + +features = [ + pylith.problems.SolnDispVel, + pylith.bc.DirichletTimeDependent, + spatialdata.spatialdb.ZeroDB + ] + +[pylithapp] +# File with version information and parameters (including defaults). +# +# You can view this file using the pylith_parameters application or +# online at https://geodynamics.github.io/pylith_parameters/. +dump_parameters.filename = output/step03_ricker-parameters.json +problem.progress_monitor.filename = output/step03_ricker-progress.txt + +# Set the name of the problem that will be used to construct the +# output filenames. The default directory for output is 'output'. +problem.defaults.name = step03_ricker + +# ---------------------------------------------------------------------- +# problem +# ---------------------------------------------------------------------- +[pylithapp.problem] +# Use the nonlinear solver to verify residual and Jacobian are consistent. +solver = nonlinear +formulation = dynamic + +# Nondimensionalize problem using wave propagation parameters. +normalizer = spatialdata.units.NondimElasticDynamic +normalizer.mass_density = 2500.0*kg/m**3 +normalizer.shear_wave_speed = 1000.0*m/s +normalizer.wave_period = 1.0*s + +defaults.quadrature_order = 1 + + +# Set the discretization for each of the solution subfields. +# +solution = pylith.problems.SolnDispVel + +solution.subfields.displacement.basis_order = 1 +solution.subfields.velocity.basis_order = 1 + +solution_observers = [domain] + +start_time = 0.0*s +end_time = 3.0*s +initial_dt = 0.01*s + +# ---------------------------------------------------------------------- +# mesh_generator +# ---------------------------------------------------------------------- +[pylithapp.mesh_generator] +# Set the reader to match the type of mesh file. +reader = pylith.meshio.MeshIOPetsc +#reader = pylith.meshio.MeshIOCubit +#reader.filename = mesh_quad.exo + +# Set the Cartesian coordinate system. +#reader.coordsys.space_dim = 2 + +#refiner = pylith.topology.RefineUniform +# ---------------------------------------------------------------------- +# materials +# ---------------------------------------------------------------------- +[pylithapp.problem] +# Create an array of one material +materials = [elastic] + +# We use the default material (elasticity) and rheology +# (isotropic, linearly elastic). + +[pylithapp.problem.materials.elastic] +# id must match the values in the mesh material-ids. +description = Elastic material +label_value = 1 +observers = [] +#observers.observer.trigger.num_skip = 10 +# We will use uniform material properties, so we use the UniformDB +# spatial database. +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = Elastic properties +db_auxiliary_field.values = [density, vs, vp] +db_auxiliary_field.data = [1800*kg/m**3, 1.3*km/s, 3.0*km/s] + +# Set the discretization of the material auxiliary fields (properties). +# We have uniform material properties, so we can use a basis order of 0. +auxiliary_subfields.density.basis_order = 0 +bulk_rheology.auxiliary_subfields.bulk_modulus.basis_order = 0 +bulk_rheology.auxiliary_subfields.shear_modulus.basis_order = 0 + +# ---------------------------------------------------------------------- +# sources +# ---------------------------------------------------------------------- + +[pylithapp.problem] +sources = [source] + +sources.source = pylith.sources.MomentTensorForce +[pylithapp.problem.sources] +source.source_time_function = pylith.sources.RickerWavelet + +[pylithapp.problem.sources.source] +description = Ricker Source +label_value = 2 +reader.filename = source_sites.txt +reader.coordsys = spatialdata.geocoords.CSCart +reader.coordsys.space_dim = 2 + +db_auxiliary_field = spatialdata.spatialdb.UniformDB +db_auxiliary_field.description = source properties +db_auxiliary_field.values = [moment_tensor_xx, moment_tensor_yy, moment_tensor_xy, moment_tensor_zz, time_delay, center_frequency] +#db_auxiliary_field.data = [0*newton*m, 0*newton*m, 1000.0*newton*m, 0.0*newton*m, -1.0*s, 0.5] +db_auxiliary_field.data = [1e14*newton*m, 1e14*newton*m, 0.0*newton*m, 1e14*newton*m, 0.0*s, 0.5] + + +# Set the discretization of the material auxiliary fields (properties). +# We have uniform material properties, so we can use a basis order of 0. +auxiliary_subfields.moment_tensor.basis_order = 0 +auxiliary_subfields.time_delay.basis_order = 0 +source_time_function.auxiliary_subfields.center_frequency.basis_order = 0 + + + +# ---------------------------------------------------------------------- +# initial conditions +# ---------------------------------------------------------------------- +[pylithapp.problem] +ic = [domain] +ic.domain = pylith.problems.InitialConditionDomain + +[pylithapp.problem.ic.domain] +db = spatialdata.spatialdb.UniformDB +db.description = Initial conditions over domain +db.values = [displacement_x, displacement_y] +db.data = [0.0*m, 0.0*m] + +# ---------------------------------------------------------------------- +# boundary conditions +# ---------------------------------------------------------------------- +[pylithapp.problem] + + +# ---------------------------------------------------------------------- +# PETSc +# ---------------------------------------------------------------------- +[pylithapp.petsc] +ts_type = rk +ts_rk_type = 3bs +ts_adapt_dt_max = 0.01 +dm_partition_view = True + +dm_plex_box_faces = 100,100 +dm_plex_box_lower = 0,0 +dm_plex_box_upper = 10000,10000 + + +# End of file diff --git a/libsrc/pylith/Makefile.am b/libsrc/pylith/Makefile.am index c575311c28..ae8439c8c6 100644 --- a/libsrc/pylith/Makefile.am +++ b/libsrc/pylith/Makefile.am @@ -15,6 +15,7 @@ SUBDIRS = \ topology \ feassemble \ problems \ + sources \ meshio \ materials \ bc \ @@ -128,6 +129,16 @@ libpylith_la_SOURCES = \ problems/ProgressMonitor.cc \ problems/ProgressMonitorTime.cc \ problems/ProgressMonitorStep.cc \ + sources/AuxiliaryFactoryMomentTensorForce.cc \ + sources/AuxiliaryFactorySourceTime.cc \ + sources/DerivedFactoryMomentTensorForce.cc \ + sources/GaussianWavelet.cc \ + sources/SquareWavelet.cc \ + sources/RickerWavelet.cc \ + sources/TimeHistoryWavelet.cc \ + sources/Source.cc \ + sources/SourceTimeFunctionMomentTensorForce.cc \ + sources/MomentTensorForce.cc \ topology/Mesh.cc \ topology/MeshOps.cc \ topology/FieldBase.cc \ diff --git a/libsrc/pylith/feassemble/DSLabelAccess.icc b/libsrc/pylith/feassemble/DSLabelAccess.icc index d7dd9d24d5..80e0b529a8 100644 --- a/libsrc/pylith/feassemble/DSLabelAccess.icc +++ b/libsrc/pylith/feassemble/DSLabelAccess.icc @@ -80,7 +80,7 @@ pylith::feassemble::DSLabelAccess::DSLabelAccess(const PetscDM dm, } else { err = ISDestroy(&_pointsIS);PYLITH_CHECK_ERROR(err); } // if/else - } // if + } PYLITH_METHOD_END; } diff --git a/libsrc/pylith/fekernels/GaussianWavelet.hh b/libsrc/pylith/fekernels/GaussianWavelet.hh new file mode 100644 index 0000000000..a2045010e2 --- /dev/null +++ b/libsrc/pylith/fekernels/GaussianWavelet.hh @@ -0,0 +1,196 @@ +/* -*- C++ -*- + * + * ---------------------------------------------------------------------- + * + * Brad T. Aagaard, U.S. Geological Survey + * Charles A. Williams, GNS Science + * Matthew G. Knepley, University of Chicago + * + * This code was developed as part of the Computational Infrastructure + * for Geodynamics (http:*geodynamics.org). + * + * Copyright (c) 2010-2015 University of California, Davis + * + * See COPYING for license information. + * + * ---------------------------------------------------------------------- + */ + +/** @file libsrc/fekernels/GaussianWavelet.hh + * + */ + +#if !defined(pylith_fekernels_gaussianwavelet_hh) +#define pylith_fekernels_gaussianwavelet_hh + +// Include directives --------------------------------------------------- +#include "fekernelsfwd.hh" // forward declarations + +#include "pylith/utils/types.hh" + +#include // USES assert() + +// ===================================================================================================================== +// Kernels for the Ricker Source Time Function in 2D. +// ===================================================================================================================== + +class pylith::fekernels::GaussianWaveletPlaneStrain { + // PUBLIC MEMBERS /////////////////////////////////////////////////////// +public: + + /** Kernel interface. + * + * @param[in] dim Spatial dimension. + * @param[in] numS Number of registered subfields in solution field. + * @param[in] numA Number of registered subfields in auxiliary field. + * @param[in] sOff Offset of registered subfields in solution field [numS]. + * @param[in] sOff_x Offset of registered subfields in gradient of the solution field [numS]. + * @param[in] s Solution field with all subfields. + * @param[in] s_t Time derivative of solution field. + * @param[in] s_x Gradient of solution field. + * @param[in] aOff Offset of registered subfields in auxiliary field [numA] + * @param[in] aOff_x Offset of registered subfields in gradient of auxiliary field [numA] + * @param[in] a Auxiliary field with all subfields. + * @param[in] a_t Time derivative of auxiliary field. + * @param[in] a_x Gradient of auxiliary field. + * @param[in] t Time for residual evaluation. + * @param[in] x Coordinates of point evaluation. + * @param[in] numConstants Number of registered constants. + * @param[in] constants Array of registered constants. + * @param[out] f0 [dim]. + */ + + /** g1 function for velocity equation + * + */ + static + void g1v(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar g1[]) { + assert(sOff); + assert(s); + assert(g1); + + PylithInt _dim = 2; + // Incoming re-packed solution field. + + // Incoming re-packed auxiliary field. + const PylithInt i_momentTensor = 0; + const PylithInt i_timeDelay = 1; + const PylithInt i_gaussianwaveletCenterFrequency = numA - 1; + + const PylithScalar* momentTensor = &a[aOff[i_momentTensor]]; + const PylithScalar timeDelay = a[aOff[i_timeDelay]]; + const PylithScalar f0 = a[aOff[i_gaussianwaveletCenterFrequency]]; + + // GaussianWavelet source time function (time domain) + + PylithScalar rt = t - timeDelay; + PylithScalar gaussianwavelet = PetscExpReal( (PETSC_PI*PETSC_PI * f0*f0) * rt*rt) / (2.0 * (PETSC_PI*PETSC_PI * f0*f0) ); + // PetscPrintf(PETSC_COMM_WORLD, "timeDelay %d\n", (double)timeDelay); + // PetscPrintf(PETSC_COMM_WORLD, "t %d\n", (double)t); + // PetscPrintf(PETSC_COMM_WORLD, "gaussianWavelet %d\n", (double)gaussianwavelet); + for (PylithInt i = 0; i < dim*dim; ++i) { + g1[i] -= momentTensor[i] * gaussianwavelet; + } // for + } // g1v +}; // GaussianWaveletPlaneStrain + +// ===================================================================================================================== +// Kernels for the Ricker Source Time Function in 3D. +// ===================================================================================================================== + +class pylith::fekernels::GaussianWavelet3D { + // PUBLIC MEMBERS /////////////////////////////////////////////////////// +public: + + /** Kernel interface. + * + * @param[in] dim Spatial dimension. + * @param[in] numS Number of registered subfields in solution field. + * @param[in] numA Number of registered subfields in auxiliary field. + * @param[in] sOff Offset of registered subfields in solution field [numS]. + * @param[in] sOff_x Offset of registered subfields in gradient of the solution field [numS]. + * @param[in] s Solution field with all subfields. + * @param[in] s_t Time derivative of solution field. + * @param[in] s_x Gradient of solution field. + * @param[in] aOff Offset of registered subfields in auxiliary field [numA] + * @param[in] aOff_x Offset of registered subfields in gradient of auxiliary field [numA] + * @param[in] a Auxiliary field with all subfields. + * @param[in] a_t Time derivative of auxiliary field. + * @param[in] a_x Gradient of auxiliary field. + * @param[in] t Time for residual evaluation. + * @param[in] x Coordinates of point evaluation. + * @param[in] numConstants Number of registered constants. + * @param[in] constants Array of registered constants. + * @param[out] f0 [dim]. + */ + + /** g1 function for velocity equation + * + */ + static + void g1v(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar g1[]) { + assert(sOff); + assert(s); + assert(g1); + + PylithInt _dim = 3; + + // Incoming re-packed solution field. + + // Incoming re-packed auxiliary field. + const PylithInt i_momentTensor = 0; + const PylithInt i_timeDelay = 1; + const PylithInt i_gaussianwaveletCenterFrequency = numA - 1; + + const PylithScalar* momentTensor = &a[aOff[i_momentTensor]]; + const PylithScalar timeDelay = a[aOff[i_timeDelay]]; + const PylithScalar f0 = a[aOff[i_gaussianwaveletCenterFrequency]]; + + // GaussianWavelet source time function (time domain) + + PylithScalar rt = t - timeDelay; + PylithScalar gaussianwavelet = PetscExpReal( (PETSC_PI*PETSC_PI * f0*f0) * rt*rt) / (2.0 * (PETSC_PI*PETSC_PI * f0*f0) ); + + for (PylithInt i = 0; i < dim*dim; ++i) { + g1[i] -= momentTensor[i] * gaussianwavelet; + } // for + } // g1v +}; // GaussianWaveletPlaneStrain + +#endif /* pylith_fekernels_gaussianwavelet_hh */ + +/* End of file */ diff --git a/libsrc/pylith/fekernels/Makefile.am b/libsrc/pylith/fekernels/Makefile.am index d654a4ed04..0bef115461 100644 --- a/libsrc/pylith/fekernels/Makefile.am +++ b/libsrc/pylith/fekernels/Makefile.am @@ -30,7 +30,11 @@ subpkginclude_HEADERS = \ TimeDependentFn.hh \ NeumannTimeDependent.hh \ AbsorbingDampers.hh \ - FaultCohesiveKin.hh + FaultCohesiveKin.hh \ + SquareWavelet.hh \ + RickerWavelet.hh \ + GaussianWavelet.hh \ + TimeHistoryWavelet.hh dist_noinst_HEADERS = diff --git a/libsrc/pylith/fekernels/Poroelasticity.hh b/libsrc/pylith/fekernels/Poroelasticity.hh index db3978cb54..1acd62a571 100644 --- a/libsrc/pylith/fekernels/Poroelasticity.hh +++ b/libsrc/pylith/fekernels/Poroelasticity.hh @@ -280,7 +280,7 @@ public: context->displacement_t = &s_t[sOff[i_displacement]]; context->displacement_x = &s_x[sOff_x[i_displacement]]; context->pressure = s[sOff[i_pressure]]; - context->pressure_t = s_t[sOff[i_pressure]]; + // context->pressure_t = s_t[sOff[i_pressure]]; context->pressure_x = &s_x[sOff_x[i_pressure]]; context->velocity = &s[sOff[i_velocity]]; context->velocity_t = &s_t[sOff[i_velocity]]; @@ -1126,6 +1126,39 @@ public: } // for } // Jf0vv_explicit + /** Jf0 function for displacement equation: Jf0uu = s_tshift. + * + * Solution fields: [disp(dim), vel(dim)] + */ + static inline + void Jf0uu_stshift(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithReal s_tshift, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar Jf0[]) { + const PylithInt _numS = 3; + assert(_numS == numS); + assert(s_tshift > 0); + + for (PylithInt i = 0; i < dim; ++i) { + Jf0[i*dim+i] += s_tshift; + } // for + } // Jf0uu_stshift + // --------------------------------------------------------------------------------------------------------------------- /* * Jf0pdotp function for poroelasticity equation, quasistatic. diff --git a/libsrc/pylith/fekernels/RickerWavelet.hh b/libsrc/pylith/fekernels/RickerWavelet.hh new file mode 100644 index 0000000000..7c31cd57d2 --- /dev/null +++ b/libsrc/pylith/fekernels/RickerWavelet.hh @@ -0,0 +1,205 @@ +/* -*- C++ -*- + * + * ---------------------------------------------------------------------- + * + * Brad T. Aagaard, U.S. Geological Survey + * Charles A. Williams, GNS Science + * Matthew G. Knepley, University of Chicago + * + * This code was developed as part of the Computational Infrastructure + * for Geodynamics (http:*geodynamics.org). + * + * Copyright (c) 2010-2015 University of California, Davis + * + * See COPYING for license information. + * + * ---------------------------------------------------------------------- + */ + +/** @file libsrc/fekernels/RickerWavelet.hh + * + */ + +#if !defined(pylith_fekernels_rickerwavelet_hh) +#define pylith_fekernels_rickerwavelet_hh + +// Include directives --------------------------------------------------- +#include "fekernelsfwd.hh" // forward declarations + +#include "pylith/utils/types.hh" + +#include // USES assert() + +// ===================================================================================================================== +// Kernels for the Ricker Source Time Function in 2D. +// ===================================================================================================================== + +class pylith::fekernels::RickerWaveletPlaneStrain { + // PUBLIC MEMBERS /////////////////////////////////////////////////////// +public: + + /** Kernel interface. + * + * @param[in] dim Spatial dimension. + * @param[in] numS Number of registered subfields in solution field. + * @param[in] numA Number of registered subfields in auxiliary field. + * @param[in] sOff Offset of registered subfields in solution field [numS]. + * @param[in] sOff_x Offset of registered subfields in gradient of the solution field [numS]. + * @param[in] s Solution field with all subfields. + * @param[in] s_t Time derivative of solution field. + * @param[in] s_x Gradient of solution field. + * @param[in] aOff Offset of registered subfields in auxiliary field [numA] + * @param[in] aOff_x Offset of registered subfields in gradient of auxiliary field [numA] + * @param[in] a Auxiliary field with all subfields. + * @param[in] a_t Time derivative of auxiliary field. + * @param[in] a_x Gradient of auxiliary field. + * @param[in] t Time for residual evaluation. + * @param[in] x Coordinates of point evaluation. + * @param[in] numConstants Number of registered constants. + * @param[in] constants Array of registered constants. + * @param[out] f0 [dim]. + */ + + /** g1 function for velocity equation + * + */ + static + void g1v(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar g1[]) { + assert(sOff); + assert(s); + assert(g1); + + PylithInt _dim = 2; + + // Incoming re-packed solution field. + + // Incoming re-packed auxiliary field. + const PylithInt i_momentTensor = 0; + const PylithInt i_timeDelay = 1; + const PylithInt i_rickerwaveletCenterFrequency = numA - 1; + + const PylithScalar* momentTensor = &a[aOff[i_momentTensor]]; + const PylithScalar timeDelay = a[aOff[i_timeDelay]]; + const PylithScalar rickerwaveletCenterFrequency = a[aOff[i_rickerwaveletCenterFrequency]]; + + // RickerWavelet source time function (time domain) + + PylithScalar rt = t - timeDelay; + PylithScalar rickerwavelet = (1.0 - 2.0*PETSC_PI*PETSC_PI*rickerwaveletCenterFrequency*rickerwaveletCenterFrequency*rt*rt) * + PetscExpReal(-PETSC_PI*PETSC_PI*rickerwaveletCenterFrequency*rickerwaveletCenterFrequency*rt*rt); + + // PetscPrintf(PETSC_COMM_WORLD, "timeDelay %f\n", (double)timeDelay); + // PetscPrintf(PETSC_COMM_WORLD, "t %f\n", (double)t); + // PetscPrintf(PETSC_COMM_WORLD, "Center Freq %f\n", (double)rickerwaveletCenterFrequency); + // PetscPrintf(PETSC_COMM_WORLD, "rickerWavelet %f\n", (double)rickerwavelet); + + for (PylithInt i = 0; i < dim*dim; ++i) { + g1[i] -= momentTensor[i] * rickerwavelet; + // PetscPrintf(PETSC_COMM_WORLD, "g1[%i]: %f - ricker\n", (int)i, (double)g1[i]); + } // for + } // g1v + +}; // RickerWaveletPlaneStrain + +// ===================================================================================================================== +// Kernels for the Ricker Source Time Function in 3D. +// ===================================================================================================================== + +class pylith::fekernels::RickerWavelet3D { + // PUBLIC MEMBERS /////////////////////////////////////////////////////// +public: + + /** Kernel interface. + * + * @param[in] dim Spatial dimension. + * @param[in] numS Number of registered subfields in solution field. + * @param[in] numA Number of registered subfields in auxiliary field. + * @param[in] sOff Offset of registered subfields in solution field [numS]. + * @param[in] sOff_x Offset of registered subfields in gradient of the solution field [numS]. + * @param[in] s Solution field with all subfields. + * @param[in] s_t Time derivative of solution field. + * @param[in] s_x Gradient of solution field. + * @param[in] aOff Offset of registered subfields in auxiliary field [numA] + * @param[in] aOff_x Offset of registered subfields in gradient of auxiliary field [numA] + * @param[in] a Auxiliary field with all subfields. + * @param[in] a_t Time derivative of auxiliary field. + * @param[in] a_x Gradient of auxiliary field. + * @param[in] t Time for residual evaluation. + * @param[in] x Coordinates of point evaluation. + * @param[in] numConstants Number of registered constants. + * @param[in] constants Array of registered constants. + * @param[out] f0 [dim]. + */ + + /** g1 function for velocity equation + * + */ + static inline + void g1v(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar g1[]) { + assert(sOff); + assert(s); + assert(g1); + + PylithInt _dim = 3; + + // Incoming re-packed solution field. + + // Incoming re-packed auxiliary field. + const PylithInt i_momentTensor = 0; + const PylithInt i_timeDelay = 1; + const PylithInt i_rickerwaveletCenterFrequency = numA - 1; + + const PylithScalar* momentTensor = &a[aOff[i_momentTensor]]; + const PylithScalar timeDelay = a[aOff[i_timeDelay]]; + const PylithScalar rickerwaveletCenterFrequency = a[aOff[i_rickerwaveletCenterFrequency]]; + + // RickerWavelet source time function (time domain) + + PylithScalar rt = t - timeDelay; + PylithScalar rickerwavelet = (1.0 - 2.0*PETSC_PI*PETSC_PI*rickerwaveletCenterFrequency*rickerwaveletCenterFrequency*rt*rt) * + PetscExpReal(-PETSC_PI*PETSC_PI*rickerwaveletCenterFrequency*rickerwaveletCenterFrequency*rt*rt); + + for (PylithInt i = 0; i < dim*dim; ++i) { + g1[i] -= momentTensor[i] * rickerwavelet; + } // for + } // g1v + +}; // RickerWaveletPlaneStrain + +#endif /* pylith_fekernels_rickerwavelet_hh */ + +/* End of file */ diff --git a/libsrc/pylith/fekernels/SquareWavelet.hh b/libsrc/pylith/fekernels/SquareWavelet.hh new file mode 100644 index 0000000000..5a1b81556e --- /dev/null +++ b/libsrc/pylith/fekernels/SquareWavelet.hh @@ -0,0 +1,201 @@ +/* -*- C++ -*- + * + * ---------------------------------------------------------------------- + * + * Brad T. Aagaard, U.S. Geological Survey + * Charles A. Williams, GNS Science + * Matthew G. Knepley, University of Chicago + * + * This code was developed as part of the Computational Infrastructure + * for Geodynamics (http:*geodynamics.org). + * + * Copyright (c) 2010-2015 University of California, Davis + * + * See COPYING for license information. + * + * ---------------------------------------------------------------------- + */ + +/** @file libsrc/fekernels/SquareWavelet.hh + * + */ + +#if !defined(pylith_fekernels_squarewavelet_hh) +#define pylith_fekernels_squarewavelet_hh + +// Include directives --------------------------------------------------- +#include "fekernelsfwd.hh" // forward declarations + +#include "pylith/utils/types.hh" + +#include // USES assert() + +// ===================================================================================================================== +// Kernels for the Square Source Time Function in 2D. +// ===================================================================================================================== + +class pylith::fekernels::SquareWaveletPlaneStrain { + // PUBLIC MEMBERS /////////////////////////////////////////////////////// +public: + + /** Kernel interface. + * + * @param[in] dim Spatial dimension. + * @param[in] numS Number of registered subfields in solution field. + * @param[in] numA Number of registered subfields in auxiliary field. + * @param[in] sOff Offset of registered subfields in solution field [numS]. + * @param[in] sOff_x Offset of registered subfields in gradient of the solution field [numS]. + * @param[in] s Solution field with all subfields. + * @param[in] s_t Time derivative of solution field. + * @param[in] s_x Gradient of solution field. + * @param[in] aOff Offset of registered subfields in auxiliary field [numA] + * @param[in] aOff_x Offset of registered subfields in gradient of auxiliary field [numA] + * @param[in] a Auxiliary field with all subfields. + * @param[in] a_t Time derivative of auxiliary field. + * @param[in] a_x Gradient of auxiliary field. + * @param[in] t Time for residual evaluation. + * @param[in] x Coordinates of point evaluation. + * @param[in] numConstants Number of registered constants. + * @param[in] constants Array of registered constants. + * @param[out] f0 [dim]. + */ + + /** g1 function for velocity equation + * + */ + static + void g1v(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar g1[]) { + assert(sOff); + assert(s); + assert(g1); + + PylithInt _dim = 2; + + // Incoming re-packed solution field. + + // Incoming re-packed auxiliary field. + const PylithInt i_momentTensor = 0; + const PylithInt i_timeDelay = 1; + const PylithInt i_squarewaveletCenterFrequency = numA - 1; + + const PylithScalar* momentTensor = &a[aOff[i_momentTensor]]; + const PylithScalar timeDelay = a[aOff[i_timeDelay]]; + const PylithScalar squarewaveletCenterFrequency = a[aOff[i_squarewaveletCenterFrequency]]; + + // SquareWavelet source time function (time domain) + + PylithScalar rt = t - timeDelay; + PylithScalar squarewavelet = (rt >= 0.0) ? 1.0 : 0.0; + + // PetscPrintf(PETSC_COMM_WORLD, "timeDelay %f\n", (double)timeDelay); + // PetscPrintf(PETSC_COMM_WORLD, "t %f\n", (double)t); + // PetscPrintf(PETSC_COMM_WORLD, "Center Freq %f\n", (double)squarewaveletCenterFrequency); + // PetscPrintf(PETSC_COMM_WORLD, "squareWavelet %f\n", (double)squarewavelet); + + for (PylithInt i = 0; i < dim*dim; ++i) { + g1[i] -= momentTensor[i] * squarewavelet; + // PetscPrintf(PETSC_COMM_WORLD, "g1[%i]: %f - square\n", (int)i, (double)g1[i]); + } // for + } // g1v +}; // SquareWaveletPlaneStrain + +// ===================================================================================================================== +// Kernels for the Square Source Time Function in 3D. +// ===================================================================================================================== + +class pylith::fekernels::SquareWavelet3D { + // PUBLIC MEMBERS /////////////////////////////////////////////////////// +public: + + /** Kernel interface. + * + * @param[in] dim Spatial dimension. + * @param[in] numS Number of registered subfields in solution field. + * @param[in] numA Number of registered subfields in auxiliary field. + * @param[in] sOff Offset of registered subfields in solution field [numS]. + * @param[in] sOff_x Offset of registered subfields in gradient of the solution field [numS]. + * @param[in] s Solution field with all subfields. + * @param[in] s_t Time derivative of solution field. + * @param[in] s_x Gradient of solution field. + * @param[in] aOff Offset of registered subfields in auxiliary field [numA] + * @param[in] aOff_x Offset of registered subfields in gradient of auxiliary field [numA] + * @param[in] a Auxiliary field with all subfields. + * @param[in] a_t Time derivative of auxiliary field. + * @param[in] a_x Gradient of auxiliary field. + * @param[in] t Time for residual evaluation. + * @param[in] x Coordinates of point evaluation. + * @param[in] numConstants Number of registered constants. + * @param[in] constants Array of registered constants. + * @param[out] f0 [dim]. + */ + + /** g1 function for velocity equation + * + */ + static + void g1v(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar g1[]) { + assert(sOff); + assert(s); + assert(g1); + + PylithInt _dim = 3; + + // Incoming re-packed solution field. + + // Incoming re-packed auxiliary field. + const PylithInt i_momentTensor = 0; + const PylithInt i_timeDelay = 1; + const PylithInt i_squarewaveletCenterFrequency = numA - 1; + + const PylithScalar* momentTensor = &a[aOff[i_momentTensor]]; + const PylithScalar timeDelay = a[aOff[i_timeDelay]]; + const PylithScalar squarewaveletCenterFrequency = a[aOff[i_squarewaveletCenterFrequency]]; + + // SquareWavelet source time function (time domain) + + PylithScalar rt = t - timeDelay; + PylithScalar squarewavelet = (rt >= 0.0) ? 1.0 : 0.0; + + for (PylithInt i = 0; i < dim*dim; ++i) { + g1[i] -= momentTensor[i] * squarewavelet; + } // for + } // g1v +}; // SquareWaveletPlaneStrain + +#endif /* pylith_fekernels_squarewavelet_hh */ + +/* End of file */ diff --git a/libsrc/pylith/fekernels/TimeHistoryWavelet.hh b/libsrc/pylith/fekernels/TimeHistoryWavelet.hh new file mode 100644 index 0000000000..a5cfa1cab1 --- /dev/null +++ b/libsrc/pylith/fekernels/TimeHistoryWavelet.hh @@ -0,0 +1,193 @@ +/* -*- C++ -*- + * + * ---------------------------------------------------------------------- + * + * Brad T. Aagaard, U.S. Geological Survey + * Charles A. Williams, GNS Science + * Matthew G. Knepley, University of Chicago + * + * This code was developed as part of the Computational Infrastructure + * for Geodynamics (http:*geodynamics.org). + * + * Copyright (c) 2010-2015 University of California, Davis + * + * See COPYING for license information. + * + * ---------------------------------------------------------------------- + */ + +/** @file libsrc/fekernels/TimeHistoryWavelet.hh + * + */ + +#if !defined(pylith_fekernels_timehistorywavelet_hh) +#define pylith_fekernels_timehistorywavelet_hh + +// Include directives --------------------------------------------------- +#include "fekernelsfwd.hh" // forward declarations + +#include "pylith/utils/types.hh" + +#include // USES assert() + +// ===================================================================================================================== +// Kernels for the TimeHistory Source Time Function in 2D. +// ===================================================================================================================== + +class pylith::fekernels::TimeHistoryWaveletPlaneStrain { + // PUBLIC MEMBERS /////////////////////////////////////////////////////// +public: + + /** Kernel interface. + * + * @param[in] dim Spatial dimension. + * @param[in] numS Number of registered subfields in solution field. + * @param[in] numA Number of registered subfields in auxiliary field. + * @param[in] sOff Offset of registered subfields in solution field [numS]. + * @param[in] sOff_x Offset of registered subfields in gradient of the solution field [numS]. + * @param[in] s Solution field with all subfields. + * @param[in] s_t Time derivative of solution field. + * @param[in] s_x Gradient of solution field. + * @param[in] aOff Offset of registered subfields in auxiliary field [numA] + * @param[in] aOff_x Offset of registered subfields in gradient of auxiliary field [numA] + * @param[in] a Auxiliary field with all subfields. + * @param[in] a_t Time derivative of auxiliary field. + * @param[in] a_x Gradient of auxiliary field. + * @param[in] t Time for residual evaluation. + * @param[in] x Coordinates of point evaluation. + * @param[in] numConstants Number of registered constants. + * @param[in] constants Array of registered constants. + * @param[out] f0 [dim]. + */ + + /** g1 function for velocity equation + * + */ + static + void g1v(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar g1[]) { + const PylithInt _numA = 3; + assert(_numA == numA); + assert(aOff); + assert(a); + + // const PylithInt i_amplitude = aOff[numA - 3]; + const PylithInt i_moment_tensor = aOff[0]; + const PylithInt i_start_time = aOff[numA - 2]; + const PylithInt i_value = aOff[numA - 1]; + + PylithInt _dim = 2; + + // PetscPrintf(PETSC_COMM_WORLD, "timeDelay %f\n", (double)timeDelay); + // PetscPrintf(PETSC_COMM_WORLD, "t %f\n", (double)t); + // PetscPrintf(PETSC_COMM_WORLD, "Center Freq %f\n", (double)timehistorywaveletCenterFrequency); + // PetscPrintf(PETSC_COMM_WORLD, "timehistoryWavelet %f\n", (double)timehistorywavelet); + + const PylithScalar* momentTensor = &a[aOff[i_moment_tensor]]; + + for (PylithInt i = 0; i < dim*dim; ++i) { + g1[i] -= momentTensor[i] * a[i_value]; + // PetscPrintf(PETSC_COMM_WORLD, "g1[%i]: %f - timehistory\n", (int)i, (double)g1[i]); + } // for + } // g1v + +}; // TimeHistoryWaveletPlaneStrain + +// ===================================================================================================================== +// Kernels for the TimeHistory Source Time Function in 3D. +// ===================================================================================================================== + +class pylith::fekernels::TimeHistoryWavelet3D { + // PUBLIC MEMBERS /////////////////////////////////////////////////////// +public: + + /** Kernel interface. + * + * @param[in] dim Spatial dimension. + * @param[in] numS Number of registered subfields in solution field. + * @param[in] numA Number of registered subfields in auxiliary field. + * @param[in] sOff Offset of registered subfields in solution field [numS]. + * @param[in] sOff_x Offset of registered subfields in gradient of the solution field [numS]. + * @param[in] s Solution field with all subfields. + * @param[in] s_t Time derivative of solution field. + * @param[in] s_x Gradient of solution field. + * @param[in] aOff Offset of registered subfields in auxiliary field [numA] + * @param[in] aOff_x Offset of registered subfields in gradient of auxiliary field [numA] + * @param[in] a Auxiliary field with all subfields. + * @param[in] a_t Time derivative of auxiliary field. + * @param[in] a_x Gradient of auxiliary field. + * @param[in] t Time for residual evaluation. + * @param[in] x Coordinates of point evaluation. + * @param[in] numConstants Number of registered constants. + * @param[in] constants Array of registered constants. + * @param[out] f0 [dim]. + */ + + /** g1 function for velocity equation + * + */ + static inline + void g1v(const PylithInt dim, + const PylithInt numS, + const PylithInt numA, + const PylithInt sOff[], + const PylithInt sOff_x[], + const PylithScalar s[], + const PylithScalar s_t[], + const PylithScalar s_x[], + const PylithInt aOff[], + const PylithInt aOff_x[], + const PylithScalar a[], + const PylithScalar a_t[], + const PylithScalar a_x[], + const PylithReal t, + const PylithScalar x[], + const PylithInt numConstants, + const PylithScalar constants[], + PylithScalar g1[]) { + const PylithInt _numA = 3; + assert(_numA == numA); + assert(aOff); + assert(a); + + // const PylithInt i_amplitude = aOff[numA - 3]; + const PylithInt i_moment_tensor = aOff[0]; + // const PylithInt i_start_time = aOff[numA - 2]; + const PylithInt i_value = aOff[numA - 1]; + + PylithInt _dim = 3; + + // PetscPrintf(PETSC_COMM_WORLD, "timeDelay %f\n", (double)timeDelay); + // PetscPrintf(PETSC_COMM_WORLD, "t %f\n", (double)t); + // PetscPrintf(PETSC_COMM_WORLD, "Center Freq %f\n", (double)timehistorywaveletCenterFrequency); + // PetscPrintf(PETSC_COMM_WORLD, "timehistoryWavelet %f\n", (double)timehistorywavelet); + + const PylithScalar* momentTensor = &a[aOff[i_moment_tensor]]; + + for (PylithInt i = 0; i < dim*dim; ++i) { + g1[i] -= momentTensor[i] * a[i_value]; + // PetscPrintf(PETSC_COMM_WORLD, "g1[%i]: %f - timehistory\n", (int)i, (double)g1[i]); + } // for + } // g1v + +}; // g1v + +#endif /* pylith_fekernels_timehistorywavelet_hh */ + +/* End of file */ diff --git a/libsrc/pylith/fekernels/fekernelsfwd.hh b/libsrc/pylith/fekernels/fekernelsfwd.hh index 174fef2b00..a9bb918e26 100644 --- a/libsrc/pylith/fekernels/fekernelsfwd.hh +++ b/libsrc/pylith/fekernels/fekernelsfwd.hh @@ -57,6 +57,22 @@ namespace pylith { class FaultCohesive; class FaultCohesiveKin; + class SquareWavelet; + class SquareWaveletPlaneStrain; + class SquareWavelet3D; + + class RickerWavelet; + class RickerWaveletPlaneStrain; + class RickerWavelet3D; + + class GaussianWavelet; + class GaussianWaveletPlaneStrain; + class GaussianWavelet3D; + + class TimeHistoryWavelet; + class TimeHistoryWaveletPlaneStrain; + class TimeHistoryWavelet3D; + class BoundaryDirections; } // fekernels } // pylith diff --git a/libsrc/pylith/materials/Poroelasticity.cc b/libsrc/pylith/materials/Poroelasticity.cc index 66510d1de3..6277a0357b 100644 --- a/libsrc/pylith/materials/Poroelasticity.cc +++ b/libsrc/pylith/materials/Poroelasticity.cc @@ -499,6 +499,7 @@ pylith::materials::Poroelasticity::_setKernelsResidual(pylith::feassemble::Integ kernels[3] = ResidualKernels("pressure", pylith::feassemble::Integrator::RHS, g0p, g1p); kernels[4] = ResidualKernels("velocity", pylith::feassemble::Integrator::LHS, f0v, f1v); kernels[5] = ResidualKernels("velocity", pylith::feassemble::Integrator::RHS, g0v, g1v); + break; } // DYNAMIC default: PYLITH_COMPONENT_LOGICERROR("Unknown formulation for equations (" << _formulation << ")."); @@ -703,6 +704,7 @@ pylith::materials::Poroelasticity::_setKernelsJacobian(pylith::feassemble::Integ PetscPointJacFn* Jf3vv = NULL; const EquationPart equationPart = pylith::feassemble::Integrator::LHS_LUMPED_INV; + kernels.resize(9); kernels[0] = JacobianKernels("displacement", "displacement", equationPart, Jf0uu, Jf1uu, Jf2uu, Jf3uu); kernels[1] = JacobianKernels("displacement", "pressure", equationPart, Jf0up, Jf1up, Jf2up, Jf3up); kernels[2] = JacobianKernels("displacement", "velocity", equationPart, Jf0uv, Jf1uv, Jf2uv, Jf3uv); diff --git a/libsrc/pylith/meshio/MeshBuilder.cc b/libsrc/pylith/meshio/MeshBuilder.cc index 35867aeded..1b13d8a558 100644 --- a/libsrc/pylith/meshio/MeshBuilder.cc +++ b/libsrc/pylith/meshio/MeshBuilder.cc @@ -667,33 +667,33 @@ pylith::meshio::_MeshBuilder::getGroupNames(string_vector* names, const PetscInt* labelValues = PETSC_NULLPTR; err = DMLabelGetNumValues(dmLabel, &numLabelValues);PYLITH_CHECK_ERROR(err); // assert(1 == numLabelValues); err = DMLabelGetValueIS(dmLabel, &labelValuesIS);PYLITH_CHECK_ERROR(err);assert(labelValuesIS); - err = ISGetIndices(labelValuesIS, &labelValues);PYLITH_CHECK_ERROR(err);assert(labelValues); - const PetscInt labelValue = labelValues[0]; - + err = ISGetIndices(labelValuesIS, &labelValues);PYLITH_CHECK_ERROR(err); + if (labelValues) { + const PetscInt labelValue = labelValues[0]; + pylith::topology::StratumIS pointIS(dmMesh, labelStr, labelValue); + const PetscInt* points = pointIS.points(); + const PetscInt numPoints = pointIS.size(); + bool hasOtherPoints = false; + bool foundPoint = false; + for (PetscInt iPoint = 0; iPoint < numPoints; ++iPoint) { + if ((points[iPoint] >= pStart) && (points[iPoint] < pEnd) ) { + foundPoint = true; + if (!exclusive) { + break; + } // if + } else { + hasOtherPoints = true; + if (exclusive) { + break; + } // if + } // if/else + } // for + if ((foundPoint && !exclusive) || (foundPoint && exclusive && !hasOtherPoints)) { + (*names)[numNames++] = labelName; + } // if + } err = ISRestoreIndices(labelValuesIS, &labelValues);PYLITH_CHECK_ERROR(err); err = ISDestroy(&labelValuesIS);PYLITH_CHECK_ERROR(err); - - pylith::topology::StratumIS pointIS(dmMesh, labelStr, labelValue); - const PetscInt* points = pointIS.points(); - const PetscInt numPoints = pointIS.size(); - bool hasOtherPoints = false; - bool foundPoint = false; - for (PetscInt iPoint = 0; iPoint < numPoints; ++iPoint) { - if ((points[iPoint] >= pStart) && (points[iPoint] < pEnd) ) { - foundPoint = true; - if (!exclusive) { - break; - } // if - } else { - hasOtherPoints = true; - if (exclusive) { - break; - } // if - } // if/else - } // for - if ((foundPoint && !exclusive) || (foundPoint && exclusive && !hasOtherPoints)) { - (*names)[numNames++] = labelName; - } // if } // if } // for names->resize(numNames); diff --git a/libsrc/pylith/meshio/MeshIOPetsc.cc b/libsrc/pylith/meshio/MeshIOPetsc.cc index e2e67c217a..923262c915 100644 --- a/libsrc/pylith/meshio/MeshIOPetsc.cc +++ b/libsrc/pylith/meshio/MeshIOPetsc.cc @@ -299,6 +299,13 @@ pylith::meshio::_MeshIOPetsc::fixMaterialLabel(PetscDM* dmMesh) { PetscDMLabel dmLabel = NULL; PetscInt pStart = -1, pEnd = -1; err = DMGetLabel(*dmMesh, labelName, &dmLabel);PYLITH_CHECK_ERROR(err); + if (!dmLabel) { + err = DMCreateLabel(*dmMesh, labelName);PYLITH_CHECK_ERROR(err); + err = DMGetLabel(*dmMesh, labelName, &dmLabel);PYLITH_CHECK_ERROR(err); + for (PetscInt point = cStart; point < cEnd; ++point) { + err = DMLabelSetValue(dmLabel, point, 1);PYLITH_CHECK_ERROR(err); + } + } err = DMLabelGetBounds(dmLabel, &pStart, &pEnd);PYLITH_CHECK_ERROR(err); if (pStart == cStart) { pStart = cEnd; } if (pEnd == cEnd) { pEnd = cStart; } diff --git a/libsrc/pylith/problems/Problem.cc b/libsrc/pylith/problems/Problem.cc index 7575d5ddf2..96204f5e38 100644 --- a/libsrc/pylith/problems/Problem.cc +++ b/libsrc/pylith/problems/Problem.cc @@ -20,6 +20,7 @@ #include "pylith/materials/Material.hh" // USES Material #include "pylith/faults/FaultCohesive.hh" // USES FaultCohesive #include "pylith/bc/BoundaryCondition.hh" // USES BoundaryCondition +#include "pylith/sources/Source.hh" // USES Source #include "pylith/feassemble/Integrator.hh" // USES Integrator #include "pylith/feassemble/IntegratorDomain.hh" // USES IntegratorDomain #include "pylith/feassemble/IntegratorInterface.hh" // USES IntegratorInterface @@ -347,6 +348,25 @@ pylith::problems::Problem::setBoundaryConditions(pylith::bc::BoundaryCondition* } // setBoundaryConditions +// ------------------------------------------------------------------------------------------------ +// Set sources. +void +pylith::problems::Problem::setSources(pylith::sources::Source* sources[], + const int numSources) { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("Problem::setSources("<setFormulation(_formulation); } // for + const size_t numSources = _sources.size(); + for (size_t i = 0; i < numSources; ++i) { + assert(_sources[i]); + _sources[i]->setScales(*_scales); + _sources[i]->setFormulation(_formulation); + } // for + _Problem::Events::logger.eventEnd(_Problem::Events::preinitialize); PYLITH_METHOD_END; } // preinitialize @@ -436,6 +463,13 @@ pylith::problems::Problem::verifyConfiguration(void) const { _bc[i]->verifyConfiguration(*solution); } // for + // Check to make sure sources are compatible with the solution. + const size_t numSources = _sources.size(); + for (size_t i = 0; i < numSources; ++i) { + assert(_sources[i]); + _sources[i]->verifyConfiguration(*solution); + } // for + _checkMaterialLabels(); assert(_observers); @@ -540,7 +574,7 @@ pylith::problems::Problem::_checkMaterialLabels(void) const { // ------------------------------------------------------------------------------------------------ -// Create array of integrators from materials, interfaces, and boundary conditions. +// Create array of integrators from materials, interfaces, sources, and boundary conditions. void pylith::problems::Problem::_createIntegrators(void) { PYLITH_METHOD_BEGIN; @@ -549,9 +583,10 @@ pylith::problems::Problem::_createIntegrators(void) { const size_t numMaterials = _materials.size(); const size_t numInterfaces = _interfaces.size(); + const size_t numSources = _sources.size(); const size_t numBC = _bc.size(); - const size_t maxSize = numMaterials + numInterfaces + numBC; + const size_t maxSize = numMaterials + numInterfaces + numSources + numBC; _integrators.resize(maxSize); size_t count = 0; @@ -573,6 +608,13 @@ pylith::problems::Problem::_createIntegrators(void) { if (integrator) { _integrators[count++] = integrator;} } // for + for (size_t i = 0; i < numSources; ++i) { + assert(_sources[i]); + pylith::feassemble::Integrator* integrator = _sources[i]->createIntegrator(*solution); + assert(count < maxSize); + if (integrator) { _integrators[count++] = integrator;} + } // for + // Check to make sure boundary conditions are compatible with the solution. for (size_t i = 0; i < numBC; ++i) { assert(_bc[i]); @@ -589,7 +631,7 @@ pylith::problems::Problem::_createIntegrators(void) { // ------------------------------------------------------------------------------------------------ -// Create array of constraints from materials, interfaces, and boundary conditions. +// Create array of constraints from materials, interfaces, sources, and boundary conditions. void pylith::problems::Problem::_createConstraints(void) { PYLITH_METHOD_BEGIN; @@ -598,6 +640,7 @@ pylith::problems::Problem::_createConstraints(void) { const size_t numMaterials = _materials.size(); const size_t numInterfaces = _interfaces.size(); + const size_t numSources = _sources.size(); const size_t numBC = _bc.size(); assert(_integrationData); @@ -620,6 +663,12 @@ pylith::problems::Problem::_createConstraints(void) { } // for + for (size_t i = 0; i < numSources; ++i) { + assert(_sources[i]); + std::vector constraints = _sources[i]->createConstraints(*solution); + _constraints.insert(_constraints.end(), constraints.begin(), constraints.end()); + } // for + for (size_t i = 0; i < numBC; ++i) { assert(_bc[i]); std::vector constraints = _bc[i]->createConstraints(*solution); diff --git a/libsrc/pylith/problems/Problem.hh b/libsrc/pylith/problems/Problem.hh index 32f6ee9158..8fb2bcfcf0 100644 --- a/libsrc/pylith/problems/Problem.hh +++ b/libsrc/pylith/problems/Problem.hh @@ -24,6 +24,7 @@ #include "pylith/materials/materialsfwd.hh" // HOLDSA Material #include "pylith/bc/bcfwd.hh" // HOLDSA BoundaryCondition #include "pylith/faults/faultsfwd.hh" // HOLDSA FaultCohesive +#include "pylith/sources/sourcesfwd.hh" // HOLDSA Source #include "pylith/testing/testingfwd.hh" // MMSTest ISA friend #include "spatialdata/spatialdb/spatialdbfwd.hh" // HASA GravityField @@ -142,6 +143,14 @@ public: void setMaterials(pylith::materials::Material* materials[], const int numMaterials); + /** Set sources. + * + * @param[in] sources Array of sources. + * @param[in] numSource Number of sources. + */ + void setSources(pylith::sources::Source* sources[], + const int numSources); + /** Set boundary conditions. * * @param[in] bc Array of boundary conditions. @@ -182,6 +191,7 @@ protected: spatialdata::spatialdb::GravityField* _gravityField; ///< Gravity field. std::vector _materials; ///< Array of materials. + std::vector _sources; ///< Array of sources. std::vector _bc; ///< Array of boundary conditions. std::vector _interfaces; ///< Array of interior interfaces. diff --git a/libsrc/pylith/sources/AuxiliaryFactoryMomentTensorForce.cc b/libsrc/pylith/sources/AuxiliaryFactoryMomentTensorForce.cc new file mode 100644 index 0000000000..120b576bc2 --- /dev/null +++ b/libsrc/pylith/sources/AuxiliaryFactoryMomentTensorForce.cc @@ -0,0 +1,264 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2015 University of California, Davis +// +// See COPYING for license information. +// +// ---------------------------------------------------------------------- +// + +#include + +#include "AuxiliaryFactoryMomentTensorForce.hh" // implementation of object methods + +#include "pylith/topology/Field.hh" // USES Field +#include "pylith/topology/FieldQuery.hh" // HOLDSA FieldQuery +#include "pylith/topology/VisitorMesh.hh" // USES VecVisitorMesh +#include "pylith/scales/Scales.hh" // USES Scales + +#include "spatialdata/spatialdb/TimeHistory.hh" // USES TimeHistory + +#include "pylith/utils/error.hh" // USES PYLITH_METHOD* +#include "pylith/utils/journals.hh" // USES PYLITH_JOURNAL* + +#include + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::AuxiliaryFactoryMomentTensorForce::AuxiliaryFactoryMomentTensorForce(void) { + GenericComponent::setName("auxiliaryfactorymomenttensorforce"); +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::AuxiliaryFactoryMomentTensorForce::~AuxiliaryFactoryMomentTensorForce(void) {} + + +// ---------------------------------------------------------------------------- +// Add isotropic permeability subfield to auxiliary fields. +void +pylith::sources::AuxiliaryFactoryMomentTensorForce::addMomentTensor(void) { // momentTensor + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addMomentTensor(void)"); + + const char* subfieldName = "moment_tensor"; + // For 2D: Mxx, Myy, Mxy, Myx (4 components) + // For 3D: Mxx, Myy, Mzz, Mxy, Myz, Mxz (6 components using symmetric Voigt notation) + const char* componentNames2D[4] = { + "moment_tensor_xx", + "moment_tensor_yy", + "moment_tensor_xy", + "moment_tensor_yx" + }; + const char* componentNames3D[6] = { + "moment_tensor_xx", + "moment_tensor_yy", + "moment_tensor_zz", + "moment_tensor_xy", + "moment_tensor_yz", + "moment_tensor_xz" + }; + const char** componentNames = (3 == _spaceDim) ? componentNames3D : componentNames2D; + const int tensorSize = (3 == _spaceDim) ? 6 : (2 == _spaceDim) ? 4 : 1; + const PylithReal pressureScale = _scales->getRigidityScale(); + + pylith::topology::Field::Description description; + description.label = subfieldName; + description.alias = subfieldName; + description.vectorFieldType = (3 == _spaceDim) ? pylith::topology::Field::TENSOR : pylith::topology::Field::OTHER; + description.numComponents = tensorSize; + description.componentNames.resize(tensorSize); + for (int i = 0; i < tensorSize; ++i) { + description.componentNames[i] = componentNames[i]; + } // for + description.scale = pressureScale; + description.validator = NULL; + + _field->subfieldAdd(description, getSubfieldDiscretization(subfieldName)); + this->setSubfieldQuery(subfieldName); + + PYLITH_METHOD_END; +} // addMomentTensor + + +// --------------------------------------------------------------------------------------------------------------------- +// Add time delay of source time function to auxiliary fields. +void +pylith::sources::AuxiliaryFactoryMomentTensorForce::addTimeDelay(void) { // timeDelay + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addTimeDelay(void)"); + + const char* subfieldName = "time_delay"; + + pylith::topology::Field::Description description; + const PylithReal timeScale = _scales->getTimeScale(); + description.label = subfieldName; + description.alias = subfieldName; + description.vectorFieldType = pylith::topology::Field::SCALAR; + description.numComponents = 1; + description.componentNames.resize(1); + description.componentNames[0] = subfieldName; + description.scale = timeScale; + // description.validator = pylith::topology::FieldQuery::validatorNonnegative; + description.validator = NULL; + + + _field->subfieldAdd(description, getSubfieldDiscretization(subfieldName)); + this->setSubfieldQuery(subfieldName); + + PYLITH_METHOD_END; +} // addTimeDelay + + +// --------------------------------------------------------------------------------------------------------------------- +// Add center frequency of source time function to auxiliary fields. +void +pylith::sources::AuxiliaryFactoryMomentTensorForce::addCenterFrequency(void) { // centerFrequency + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addCenterFrequency(void)"); + + const char* subfieldName = "center_frequency"; + const PylithReal timeScale = _scales->getTimeScale(); + + pylith::topology::Field::Description description; + description.label = subfieldName; + description.alias = subfieldName; + description.vectorFieldType = pylith::topology::Field::SCALAR; + description.numComponents = 1; + description.componentNames.resize(1); + description.componentNames[0] = subfieldName; + description.scale = 1.0 / timeScale; + description.validator = pylith::topology::FieldQuery::validatorNonnegative; + + _field->subfieldAdd(description, getSubfieldDiscretization(subfieldName)); + this->setSubfieldQuery(subfieldName); + + PYLITH_METHOD_END; +} // addCenterFrequency + + +// --------------------------------------------------------------------------------------------------------------------- +// Add time history start time field to auxiliary fields. +void +pylith::sources::AuxiliaryFactoryMomentTensorForce::addTimeHistoryStartTime(void) { + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addTimeHistoryStartTime(void)"); + + const char* subfieldName = "time_history_start_time"; + + assert(_defaultDescription); + assert(_scales); + pylith::topology::FieldBase::Description subfieldDescription(*_defaultDescription); + subfieldDescription.label = subfieldName; + subfieldDescription.alias = subfieldName; + subfieldDescription.vectorFieldType = pylith::topology::FieldBase::SCALAR; + subfieldDescription.numComponents = 1; + subfieldDescription.componentNames.resize(1); + subfieldDescription.componentNames[0] = subfieldName; + subfieldDescription.scale = _scales->getTimeScale(); + subfieldDescription.validator = NULL; + + _field->subfieldAdd(subfieldDescription, getSubfieldDiscretization(subfieldName)); + this->setSubfieldQuery(subfieldName); + + PYLITH_METHOD_END; +} // addTimeHistoryStartTime + + +// --------------------------------------------------------------------------------------------------------------------- +// Add time history value field to auxiliary fields. +void +pylith::sources::AuxiliaryFactoryMomentTensorForce::addTimeHistoryValue(void) { + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addTimeHistoryValue(void)"); + + const char* subfieldName = "time_history_value"; + + assert(_defaultDescription); + assert(_scales); + pylith::topology::FieldBase::Description subfieldDescription(*_defaultDescription); + subfieldDescription.label = subfieldName; + subfieldDescription.alias = subfieldName; + subfieldDescription.vectorFieldType = pylith::topology::FieldBase::SCALAR; + subfieldDescription.numComponents = 1; + subfieldDescription.componentNames.resize(1); + subfieldDescription.componentNames[0] = subfieldName; + subfieldDescription.validator = NULL; + + _field->subfieldAdd(subfieldDescription, getSubfieldDiscretization("time_history_amplitude")); + // No subfield query; populated by integrator or constraint at beginning of time step. + + PYLITH_METHOD_END; +} // addTimeHistoryValue + + +// --------------------------------------------------------------------------------------------------------------------- +void +pylith::sources::AuxiliaryFactoryMomentTensorForce::updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const PylithReal t, + const PylithReal timeScale, + spatialdata::spatialdb::TimeHistory* const dbTimeHistory) { + PYLITH_METHOD_BEGIN; + // pythia::journal::debug_t debug(_TimeDependentAuxiliaryFactory::genericComponent); + // debug << pythia::journal::at(__HERE__) + // << "TimeDependentAuxiliaryFactory::updateAuxiliaryField(auxiliaryField="<getLocalSection();assert(auxiliaryFieldSection); + PetscInt pStart = 0, pEnd = 0; + err = PetscSectionGetChart(auxiliaryFieldSection, &pStart, &pEnd);PYLITH_CHECK_ERROR(err); + pylith::topology::VecVisitorMesh auxiliaryFieldVisitor(*auxiliaryField); + PetscScalar* auxiliaryFieldArray = auxiliaryFieldVisitor.localArray();assert(auxiliaryFieldArray); + + // Compute offset of time history subfields in auxiliary field. + const PetscInt i_startTime = auxiliaryField->getSubfieldInfo("time_history_start_time").index; + const PetscInt i_value = auxiliaryField->getSubfieldInfo("time_history_value").index; + + // Loop over all points in section. + for (PetscInt p = pStart; p < pEnd; ++p) { + // Skip points without values in section. + if (!auxiliaryFieldVisitor.sectionDof(p)) {continue;} + + // Get starting time and compute relative time for point. + const PetscInt offStartTime = auxiliaryFieldVisitor.sectionSubfieldOffset(i_startTime, p); + const PylithScalar tStart = auxiliaryFieldArray[offStartTime]; + const PylithScalar tRel = t - tStart; + + // Query time history for value (normalized amplitude). + PylithScalar value = 0.0; + if (tRel >= 0.0) { + PylithScalar tDim = tRel * timeScale; + const int err = dbTimeHistory->query(&value, tDim); + if (err) { + std::ostringstream msg; + msg << "Error querying for time '" << tDim << "' in time history database '" << dbTimeHistory->getDescription() << "'."; + throw std::runtime_error(msg.str()); + } // if + } // if + + // Update value (normalized amplitude) in auxiliary field. + const PetscInt offValue = auxiliaryFieldVisitor.sectionSubfieldOffset(i_value, p); + auxiliaryFieldArray[offValue] = value; + } // for + + PYLITH_METHOD_END; +} // updateAuxiliaryField + + +// End of file diff --git a/libsrc/pylith/sources/AuxiliaryFactoryMomentTensorForce.hh b/libsrc/pylith/sources/AuxiliaryFactoryMomentTensorForce.hh new file mode 100644 index 0000000000..b69b5b1b24 --- /dev/null +++ b/libsrc/pylith/sources/AuxiliaryFactoryMomentTensorForce.hh @@ -0,0 +1,85 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2017 University of California, Davis +// +// See COPYING for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file libsrc/sources/AuxiliaryFactoryMomentTensorForce.hh + * + * @brief C++ helper class for setting up auxiliary subfields for the moment tensor force equation. + */ + +#if !defined(pylith_sources_auxiliaryfactorymomenttensorforce_hh) +#define pylith_sources_auxiliaryfactorymomenttensorforce_hh + +#include "sourcesfwd.hh" // forward declarations +#include "pylith/feassemble/AuxiliaryFactory.hh" // ISA AuxiliaryFactory + +#include "spatialdata/spatialdb/spatialdbfwd.hh" // USES GravityField + +class pylith::sources::AuxiliaryFactoryMomentTensorForce : public pylith::feassemble::AuxiliaryFactory { + friend class TestAuxiliaryFactoryMomentTensorForce; // unit testing + + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + AuxiliaryFactoryMomentTensorForce(void); + + /// Destructor. + virtual ~AuxiliaryFactoryMomentTensorForce(void); + + /// Add moment tensor subfield to auxiliary subfields. + void addMomentTensor(void); + + /// Add time delay subfield to auxiliary subfields. + void addTimeDelay(void); + + /// Add center frequency subfield to auxiliary subfields. + void addCenterFrequency(void); + + /// Add time history amplitude field to auxiliary fields. + void addTimeHistoryAmplitude(void); + + /// Add time history start time field to auxiliary fields. + void addTimeHistoryStartTime(void); + + /// Add time history value field to auxiliary fields. + void addTimeHistoryValue(void); + + /** Update auxiliary field for current time. + * + * @param[inout] auxiliaryField Auxiliary field to update. + * @param[in] t Current time. + * @param[in] timeScale Time scale for nondimensionalization. + * @param[in] dbTimeHistory Time history database. + */ + static + void updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const PylithReal t, + const PylithReal timeScale, + spatialdata::spatialdb::TimeHistory* const dbTimeHistory); + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + AuxiliaryFactoryMomentTensorForce(const AuxiliaryFactoryMomentTensorForce &); ///< Not implemented. + const AuxiliaryFactoryMomentTensorForce& operator=(const AuxiliaryFactoryMomentTensorForce&); ///< Not implemented + +}; // class AuxiliaryFactoryMomentTensorForce + +#endif // pylith_sources_auxiliaryfactorymomenttensorforce_hh + +// End of file diff --git a/libsrc/pylith/sources/AuxiliaryFactorySourceTime.cc b/libsrc/pylith/sources/AuxiliaryFactorySourceTime.cc new file mode 100644 index 0000000000..17111b3598 --- /dev/null +++ b/libsrc/pylith/sources/AuxiliaryFactorySourceTime.cc @@ -0,0 +1,184 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2015 University of California, Davis +// +// See COPYING for license information. +// +// ---------------------------------------------------------------------- +// + +#include + +#include "AuxiliaryFactorySourceTime.hh" // implementation of object methods + +#include "pylith/topology/Field.hh" // USES Field +#include "pylith/topology/FieldQuery.hh" // HOLDSA FieldQuery +#include "pylith/topology/VisitorMesh.hh" // USES VecVisitorMesh +#include "pylith/scales/Scales.hh" // USES Scales + +#include "spatialdata/spatialdb/TimeHistory.hh" // USES TimeHistory + +#include "pylith/utils/error.hh" // USES PYLITH_METHOD* +#include "pylith/utils/journals.hh" // USES PYLITH_JOURNAL* + +#include + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::AuxiliaryFactorySourceTime::AuxiliaryFactorySourceTime(void) { + GenericComponent::setName("auxiliaryfactorysourcetime"); +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::AuxiliaryFactorySourceTime::~AuxiliaryFactorySourceTime(void) {} + + +// --------------------------------------------------------------------------------------------------------------------- +// Add center frequency of source time function to auxiliary fields. +void +pylith::sources::AuxiliaryFactorySourceTime::addCenterFrequency(void) { // centerFrequency + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addCenterFrequency(void)"); + + const char* subfieldName = "center_frequency"; + const PylithReal timeScale = _scales->getTimeScale(); + + pylith::topology::Field::Description description; + description.label = subfieldName; + description.alias = subfieldName; + description.vectorFieldType = pylith::topology::Field::SCALAR; + description.numComponents = 1; + description.componentNames.resize(1); + description.componentNames[0] = subfieldName; + description.scale = 1.0 / timeScale; + description.validator = pylith::topology::FieldQuery::validatorNonnegative; + + _field->subfieldAdd(description, getSubfieldDiscretization(subfieldName)); + this->setSubfieldQuery(subfieldName); + + PYLITH_METHOD_END; +} // addCenterFrequency + + +// --------------------------------------------------------------------------------------------------------------------- +// Add time history start time field to auxiliary fields. +void +pylith::sources::AuxiliaryFactorySourceTime::addTimeHistoryStartTime(void) { + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addTimeHistoryStartTime(void)"); + + const char* subfieldName = "time_history_start_time"; + + assert(_scales); + pylith::topology::Field::Description description; + description.label = subfieldName; + description.alias = subfieldName; + description.vectorFieldType = pylith::topology::FieldBase::SCALAR; + description.numComponents = 1; + description.componentNames.resize(1); + description.componentNames[0] = subfieldName; + description.scale = _scales->getTimeScale(); + description.validator = NULL; + + _field->subfieldAdd(description, getSubfieldDiscretization(subfieldName)); + this->setSubfieldQuery(subfieldName); + + PYLITH_METHOD_END; +} // addTimeHistoryStartTime + + +// --------------------------------------------------------------------------------------------------------------------- +// Add time history value field to auxiliary fields. +void +pylith::sources::AuxiliaryFactorySourceTime::addTimeHistoryValue(void) { + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addTimeHistoryValue(void)"); + + const char* subfieldName = "time_history_value"; + + assert(_scales); + pylith::topology::Field::Description description; + description.label = subfieldName; + description.alias = subfieldName; + description.vectorFieldType = pylith::topology::FieldBase::SCALAR; + description.numComponents = 1; + description.componentNames.resize(1); + description.componentNames[0] = subfieldName; + description.validator = NULL; + + _field->subfieldAdd(description, getSubfieldDiscretization("time_history_amplitude")); + // No subfield query; populated by integrator or constraint at beginning of time step. + + PYLITH_METHOD_END; +} // addTimeHistoryValue + + +// --------------------------------------------------------------------------------------------------------------------- +void +pylith::sources::AuxiliaryFactorySourceTime::updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const PylithReal t, + const PylithReal timeScale, + spatialdata::spatialdb::TimeHistory* const dbTimeHistory) { + PYLITH_METHOD_BEGIN; + + assert(auxiliaryField); + assert(dbTimeHistory); + + PetscErrorCode err = 0; + + PetscSection auxiliaryFieldSection = auxiliaryField->getLocalSection();assert(auxiliaryFieldSection); + PetscInt pStart = 0, pEnd = 0; + err = PetscSectionGetChart(auxiliaryFieldSection, &pStart, &pEnd);PYLITH_CHECK_ERROR(err); + pylith::topology::VecVisitorMesh auxiliaryFieldVisitor(*auxiliaryField); + PetscScalar* auxiliaryFieldArray = auxiliaryFieldVisitor.localArray(); + if (auxiliaryFieldArray == NULL) { + PYLITH_METHOD_END; + } + + // Compute offset of time history subfields in auxiliary field. + const PetscInt i_startTime = auxiliaryField->getSubfieldInfo("time_history_start_time").index; + const PetscInt i_value = auxiliaryField->getSubfieldInfo("time_history_value").index; + + // Loop over all points in section. + for (PetscInt p = pStart; p < pEnd; ++p) { + // Skip points without values in section. + if (!auxiliaryFieldVisitor.sectionDof(p)) {continue;} + + // Get starting time and compute relative time for point. + const PetscInt offStartTime = auxiliaryFieldVisitor.sectionSubfieldOffset(i_startTime, p); + const PylithScalar tStart = auxiliaryFieldArray[offStartTime]; + const PylithScalar tRel = t - tStart; + + // Query time history for value (normalized amplitude). + PylithScalar value = 0.0; + if (tRel >= 0.0) { + PylithScalar tDim = tRel * timeScale; + const int err = dbTimeHistory->query(&value, tDim); + if (err) { + std::ostringstream msg; + msg << "Error querying for time '" << tDim << "' in time history database '" << dbTimeHistory->getDescription() << "'."; + throw std::runtime_error(msg.str()); + } // if + } // if + + // Update value (normalized amplitude) in auxiliary field. + const PetscInt offValue = auxiliaryFieldVisitor.sectionSubfieldOffset(i_value, p); + auxiliaryFieldArray[offValue] = value; + } // for + + PYLITH_METHOD_END; +} // updateAuxiliaryField + + +// End of file diff --git a/libsrc/pylith/sources/AuxiliaryFactorySourceTime.hh b/libsrc/pylith/sources/AuxiliaryFactorySourceTime.hh new file mode 100644 index 0000000000..fef8ad3759 --- /dev/null +++ b/libsrc/pylith/sources/AuxiliaryFactorySourceTime.hh @@ -0,0 +1,77 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2017 University of California, Davis +// +// See COPYING for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file libsrc/sources/AuxiliaryFactorySourceTime.hh + * + * @brief C++ helper class for setting up auxiliary subfields for the wellbore source equation. + */ + +#if !defined(pylith_sources_auxiliaryfactorysourcetime_hh) +#define pylith_sources_auxiliaryfactorysourcetime_hh + +#include "sourcesfwd.hh" // forward declarations +#include "pylith/sources/AuxiliaryFactoryMomentTensorForce.hh" // ISA AuxiliaryFactoryMomentTensorForce + +class pylith::sources::AuxiliaryFactorySourceTime : public pylith::sources::AuxiliaryFactoryMomentTensorForce { + friend class TestAuxiliaryFactorySourceTime; // unit testing + + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + AuxiliaryFactorySourceTime(void); + + /// Destructor. + virtual ~AuxiliaryFactorySourceTime(void); + + /// Add center frequency subfield to auxiliary subfields. + void addCenterFrequency(void); + + /// Add time history amplitude field to auxiliary fields. + void addTimeHistoryAmplitude(void); + + /// Add time history start time field to auxiliary fields. + void addTimeHistoryStartTime(void); + + /// Add time history value field to auxiliary fields. + void addTimeHistoryValue(void); + + /** Update auxiliary field for current time. + * + * @param[inout] auxiliaryField Auxiliary field to update. + * @param[in] t Current time. + * @param[in] timeScale Time scale for nondimensionalization. + * @param[in] dbTimeHistory Time history database. + */ + static + void updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const PylithReal t, + const PylithReal timeScale, + spatialdata::spatialdb::TimeHistory* const dbTimeHistory); + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + AuxiliaryFactorySourceTime(const AuxiliaryFactorySourceTime &); ///< Not implemented. + const AuxiliaryFactorySourceTime& operator=(const AuxiliaryFactorySourceTime&); ///< Not implemented + +}; // class AuxiliaryFactorySourceTime + +#endif // pylith_sources_auxiliaryfactorysourcetime_hh + +// End of file diff --git a/libsrc/pylith/sources/DerivedFactoryMomentTensorForce.cc b/libsrc/pylith/sources/DerivedFactoryMomentTensorForce.cc new file mode 100644 index 0000000000..57f146caf3 --- /dev/null +++ b/libsrc/pylith/sources/DerivedFactoryMomentTensorForce.cc @@ -0,0 +1,121 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +#include + +#include "DerivedFactoryMomentTensorForce.hh" // implementation of object methods + +#include "pylith/topology/Field.hh" // USES Field +#include "pylith/scales/Scales.hh" // USES Scales + +#include "pylith/utils/error.hh" // USES PYLITH_METHOD* +#include "pylith/utils/journals.hh" // USES PYLITH_JOURNAL* + +#include + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::DerivedFactoryMomentTensorForce::DerivedFactoryMomentTensorForce(void) { + GenericComponent::setName("derivedfactorymomenttensorforce"); +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::DerivedFactoryMomentTensorForce::~DerivedFactoryMomentTensorForce(void) {} + + +// --------------------------------------------------------------------------------------------------------------------- +// Add Cauchy stress subfield to derived field. +void +pylith::sources::DerivedFactoryMomentTensorForce::addCauchyStress(void) { + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addCauchyStress(void)"); + + const char* fieldName = "cauchy_stress"; + const char* componentNames[6] = { "stress_xx", "stress_yy", "stress_zz", "stress_xy", "stress_yz", "stress_xz" }; + const int stressSize = (3 == _spaceDim) ? 6 : (2 == _spaceDim) ? 4 : 1; + const PylithReal pressureScale = _scales->getRigidityScale(); + + pylith::topology::Field::Description description; + description.label = fieldName; + description.alias = fieldName; + description.vectorFieldType = (3 == _spaceDim) ? pylith::topology::Field::TENSOR : pylith::topology::Field::OTHER; + description.numComponents = stressSize; + description.componentNames.resize(stressSize); + for (int i = 0; i < stressSize; ++i) { + description.componentNames[i] = componentNames[i]; + } // for + description.scale = pressureScale; + description.validator = NULL; + + _field->subfieldAdd(description, getSubfieldDiscretization(fieldName)); + + PYLITH_METHOD_END; +} // addCauchyStress + + +// --------------------------------------------------------------------------------------------------------------------- +// Add Cauchy (infinitesimal) strain subfield to derived fields. +void +pylith::sources::DerivedFactoryMomentTensorForce::addCauchyStrain(void) { + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addCauchyStrain(void)"); + + const char* fieldName = "cauchy_strain"; + const char* componentNames[6] = { "strain_xx", "strain_yy", "strain_zz", "strain_xy", "strain_yz", "strain_xz" }; + const int strainSize = (3 == _spaceDim) ? 6 : (2 == _spaceDim) ? 4 : 1; + + pylith::topology::Field::Description description; + description.label = fieldName; + description.alias = fieldName; + description.vectorFieldType = (3 == _spaceDim) ? pylith::topology::Field::TENSOR : pylith::topology::Field::OTHER; + description.numComponents = strainSize; + description.componentNames.resize(strainSize); + for (int i = 0; i < strainSize; ++i) { + description.componentNames[i] = componentNames[i]; + } // for + description.scale = 1.0; + description.validator = NULL; + + _field->subfieldAdd(description, getSubfieldDiscretization(fieldName)); + + PYLITH_METHOD_END; +} // addCauchyStrain + + +// --------------------------------------------------------------------------------------------------------------------- +// Add subfields using discretizations provided. +void +pylith::sources::DerivedFactoryMomentTensorForce::addSubfields(void) { + PYLITH_METHOD_BEGIN; + PYLITH_JOURNAL_DEBUG("addSubfields(void)"); + + if (_subfieldDiscretizations.find("cauchy_stress") != _subfieldDiscretizations.end()) { + addCauchyStress(); + } // if + if (_subfieldDiscretizations.find("cauchy_strain") != _subfieldDiscretizations.end()) { + addCauchyStrain(); + } // if + + PYLITH_METHOD_END; + +} + + +// End of file diff --git a/libsrc/pylith/sources/DerivedFactoryMomentTensorForce.hh b/libsrc/pylith/sources/DerivedFactoryMomentTensorForce.hh new file mode 100644 index 0000000000..89cf2f124b --- /dev/null +++ b/libsrc/pylith/sources/DerivedFactoryMomentTensorForce.hh @@ -0,0 +1,61 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file libsrc/sources/DerivedFactoryMomentTensorForce.hh + * + * @brief C++ helper class for setting up derived subfields for elastic sources. + */ + +#if !defined(pylith_sources_derivedfactorymomenttensorforce_hh) +#define pylith_sources_derivedfactorymomenttensorforce_hh + +#include "sourcesfwd.hh" // forward declarations +#include "pylith/topology/FieldFactory.hh" // ISA AuxiliaryFactory + +class pylith::sources::DerivedFactoryMomentTensorForce : public pylith::topology::FieldFactory { + friend class TestDerivedFactoryMomentTensorForce; // unit testing + + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + DerivedFactoryMomentTensorForce(void); + + /// Destructor. + virtual ~DerivedFactoryMomentTensorForce(void); + + /// Add Cauchy stress subfield to derived field. + void addCauchyStress(void); + + /// Add Cauchy (infinitesimal) strain subfield to derived field. + void addCauchyStrain(void); + + /// Add subfields using discretizations provided. + void addSubfields(void); + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + DerivedFactoryMomentTensorForce(const DerivedFactoryMomentTensorForce &); ///< Not implemented. + const DerivedFactoryMomentTensorForce& operator=(const DerivedFactoryMomentTensorForce&); ///< Not implemented + +}; // class DerivedFactoryMomentTensorForce + +#endif // pylith_materials_derivedfactorymomenttensorforce_hh + +// End of file diff --git a/libsrc/pylith/sources/GaussianWavelet.cc b/libsrc/pylith/sources/GaussianWavelet.cc new file mode 100644 index 0000000000..96799b9cf7 --- /dev/null +++ b/libsrc/pylith/sources/GaussianWavelet.cc @@ -0,0 +1,99 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +#include + +#include "pylith/sources/GaussianWavelet.hh" // implementation of object methods + +#include "pylith/sources/AuxiliaryFactorySourceTime.hh" // USES AuxiliaryFactorySourceTime +#include "pylith/fekernels/GaussianWavelet.hh" // USES GaussianWavelet kernels +#include "pylith/utils/journals.hh" // USES PYLITH_COMPONENT_* +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_BEGIN/END + +#include "spatialdata/geocoords/CoordSys.hh" // USES CoordSys + +#include // USES typeid() + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::GaussianWavelet::GaussianWavelet(void) : + _auxiliaryFactory(new pylith::sources::AuxiliaryFactorySourceTime) { + pylith::utils::PyreComponent::setName("gaussianwavelet"); +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::GaussianWavelet::~GaussianWavelet(void) { + deallocate(); +} // destructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Deallocate PETSc and local data structures. +void +pylith::sources::GaussianWavelet::deallocate(void) { + SourceTimeFunctionMomentTensorForce::deallocate(); + + delete _auxiliaryFactory;_auxiliaryFactory = NULL; +} // deallocate + + +// --------------------------------------------------------------------------------------------------------------------- +// Get auxiliary factory associated with physics. +pylith::sources::AuxiliaryFactoryMomentTensorForce* +pylith::sources::GaussianWavelet::getAuxiliaryFactory(void) { + return _auxiliaryFactory; +} // getAuxiliaryFactory + + +// --------------------------------------------------------------------------------------------------------------------- +// Add source time subfields to auxiliary field. +void +pylith::sources::GaussianWavelet::addAuxiliarySubfields(void) { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("addAuxiliarySubfields(void)"); + + // :ATTENTION: The order for adding subfields must match the order of the auxiliary fields in the point-wise + // functions (kernels). + + _auxiliaryFactory->addTimeDelay(); // numA - 2 + _auxiliaryFactory->addCenterFrequency(); // numA - 1 + + PYLITH_METHOD_END; +} // addAuxiliarySubfields + + +// --------------------------------------------------------------------------------------------------------------------- +// Get g1v kernel for residual, G(t,s). +PetscPointFunc +pylith::sources::GaussianWavelet::getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("getKernelg1v_explicit(coordsys="<getSpaceDim(); + PetscPointFunc g1v = + (3 == spaceDim) ? pylith::fekernels::GaussianWavelet3D::g1v : + (2 == spaceDim) ? pylith::fekernels::GaussianWaveletPlaneStrain::g1v : + NULL; + + PYLITH_METHOD_RETURN(g1v); +} // getKernelResidualStress + + +// End of file diff --git a/libsrc/pylith/sources/GaussianWavelet.hh b/libsrc/pylith/sources/GaussianWavelet.hh new file mode 100644 index 0000000000..6f7520f044 --- /dev/null +++ b/libsrc/pylith/sources/GaussianWavelet.hh @@ -0,0 +1,81 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file libsrc/sources/GaussianWavelet.hh + * + * @brief C++ class for gaussian source time function. + */ + +#if !defined(pylith_materials_gaussianwavelet_hh) +#define pylith_materials_gaussianwavelet_hh + +#include "sourcesfwd.hh" // forward declarations + +#include "pylith/sources/SourceTimeFunctionMomentTensorForce.hh" // ISA SourceTimeFunctionMomentTensorForce + +class pylith::sources::GaussianWavelet : public pylith::sources::SourceTimeFunctionMomentTensorForce { + friend class TestGaussianWavelet; // unit testing + + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + GaussianWavelet(void); + + /// Destructor. + ~GaussianWavelet(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void); + + /** Add source time subfields to auxiliary field. + * + * @param[inout] auxiliaryField Auxiliary field. + */ + void addAuxiliarySubfields(void); + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return residual kernel for g1v. + */ + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const; + + // PRIVATE MEMBERS ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + pylith::sources::AuxiliaryFactorySourceTime* _auxiliaryFactory; ///< Factory for creating auxiliary subfields. + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + GaussianWavelet(const GaussianWavelet&); ///< Not implemented. + const GaussianWavelet& operator=(const GaussianWavelet&); /// Not implemented. + +}; // class GaussianWavelet + +#endif // pylith_materials_gaussianwavelet_hh + +// End of file diff --git a/libsrc/pylith/sources/Makefile.am b/libsrc/pylith/sources/Makefile.am new file mode 100644 index 0000000000..7634ff9de2 --- /dev/null +++ b/libsrc/pylith/sources/Makefile.am @@ -0,0 +1,39 @@ +# -*- Makefile -*- +# +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University of Chicago +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2017 University of California, Davis +# +# See COPYING for license information. +# +# ---------------------------------------------------------------------- +# + +subpackage = sources +include $(top_srcdir)/subpackage.am + +subpkginclude_HEADERS = \ + Source.hh \ + MomentTensorForce.hh \ + AuxiliaryFactoryMomentTensorForce.hh \ + AuxiliaryFactorySourceTime.hh \ + DerivedFactoryMomentTensorForce.hh \ + SquareWavelet.hh \ + RickerWavelet.hh \ + GaussianWavelet.hh \ + TimeHistoryWavelet.hh \ + SourceTimeFunctionMomentTensorForce.hh \ + sourcesfwd.hh + + +noinst_HEADERS = + + +# End of file diff --git a/libsrc/pylith/sources/MomentTensorForce.cc b/libsrc/pylith/sources/MomentTensorForce.cc new file mode 100644 index 0000000000..acae57cad2 --- /dev/null +++ b/libsrc/pylith/sources/MomentTensorForce.cc @@ -0,0 +1,315 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2015 University of California, Davis +// +// See COPYING for license information. +// +// ---------------------------------------------------------------------- +// + +#include + +#include "pylith/sources/MomentTensorForce.hh" // implementation of object methods + +// #include "pylith/sources/AuxiliaryFactorySourceTime.hh" // USES AuxiliaryFactorySourceTime +#include "pylith/sources/SourceTimeFunctionMomentTensorForce.hh" // HASA SourceTimeFunctionMomentTensorSource +#include "pylith/sources/AuxiliaryFactoryMomentTensorForce.hh" // USES AuxiliaryFactoryMomentTensorForce +#include "pylith/sources/DerivedFactoryMomentTensorForce.hh" // USES DerivedFactoryMomentTensorForce +#include "pylith/feassemble/IntegratorDomain.hh" // USES IntegratorDomain +#include "pylith/topology/Mesh.hh" // USES Mesh +#include "pylith/topology/Field.hh" // USES Field::SubfieldInfo +#include "pylith/topology/FieldOps.hh" // USES FieldOps +#include "pylith/fekernels/DispVel.hh" // USES DispVel kernels +#include "pylith/scales/Scales.hh" // USES Scales +#include "spatialdata/spatialdb/TimeHistory.hh" // USES TimeHistory + +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_* +#include "pylith/utils/journals.hh" // USES PYLITH_COMPONENT_* + +#include "spatialdata/geocoords/CoordSys.hh" // USES CoordSys + +#include // USES typeid() + +// --------------------------------------------------------------------------------------------------------------------- +typedef pylith::feassemble::IntegratorDomain::ResidualKernels ResidualKernels; +typedef pylith::feassemble::IntegratorDomain::JacobianKernels JacobianKernels; +typedef pylith::feassemble::IntegratorDomain::ProjectKernels ProjectKernels; +typedef pylith::feassemble::Integrator::EquationPart EquationPart; + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::MomentTensorForce::MomentTensorForce(void) : + _sourceTimeFunction(NULL), + _derivedFactory(new pylith::sources::DerivedFactoryMomentTensorForce) { + pylith::utils::PyreComponent::setName("momenttensorforce"); +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::MomentTensorForce::~MomentTensorForce(void) { + deallocate(); +} // destructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Deallocate PETSc and local data structures. +void +pylith::sources::MomentTensorForce::deallocate(void) { + Source::deallocate(); + + delete _derivedFactory;_derivedFactory = NULL; + _sourceTimeFunction = NULL; +} // deallocate + + +// --------------------------------------------------------------------------------------------------------------------- +// Set source time function. +void +pylith::sources::MomentTensorForce::setSourceTimeFunction(pylith::sources::SourceTimeFunctionMomentTensorForce* const sourceTimeFunction) { + _sourceTimeFunction = sourceTimeFunction; +} // setSourceTimeFunction + + +// --------------------------------------------------------------------------------------------------------------------- +// Get bulk source time function. +pylith::sources::SourceTimeFunctionMomentTensorForce* +pylith::sources::MomentTensorForce::getSourceTimeFunction(void) const { + return _sourceTimeFunction; +} // getSourceTimeFunction + + +// --------------------------------------------------------------------------------------------------------------------- +// Verify configuration is acceptable. +void +pylith::sources::MomentTensorForce::verifyConfiguration(const pylith::topology::Field& solution) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("verifyConfiguration(solution="<setLabelName(getLabelName()); + integrator->setLabelValue(getLabelValue()); + integrator->createLabelDS(solution, solution.getMesh().getDimension()); + + _setKernelsResidual(integrator, solution); + + _setKernelsUpdateStateVars(integrator, solution); + _setKernelsDerivedField(integrator, solution); + + PYLITH_METHOD_RETURN(integrator); +} // createIntegrator + + +// --------------------------------------------------------------------------------------------------------------------- +// Create auxiliary field. +pylith::topology::Field* +pylith::sources::MomentTensorForce::createAuxiliaryField(const pylith::topology::Field& solution, + const pylith::topology::Mesh& domainMesh) { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("createAuxiliaryField(solution="<setLabel("MomentTensorForce auxiliary field"); + + assert(_sourceTimeFunction); + pylith::sources::AuxiliaryFactoryMomentTensorForce* auxiliaryFactory = _sourceTimeFunction->getAuxiliaryFactory();assert(auxiliaryFactory); + + assert(_scales); + auxiliaryFactory->initialize(auxiliaryField, *_scales, domainMesh.getDimension()); + + // :ATTENTION: The order for adding subfields must match the order of the auxiliary fields in the FE kernels. + + auxiliaryFactory->addMomentTensor(); // 0 + + _sourceTimeFunction->addAuxiliarySubfields(); + + auxiliaryField->subfieldsSetup(); + auxiliaryField->createDiscretization(); + pylith::topology::FieldOps::checkDiscretization(solution, *auxiliaryField); + auxiliaryField->allocate(); + auxiliaryField->createOutputVector(); + + assert(auxiliaryFactory); + auxiliaryFactory->setValuesFromDB(); + + // Scale Moment Tensor Values + PetscDM dm = auxiliaryField->getDM(); + PetscVec v = auxiliaryField->getLocalVector(); + PylithScalar* array; + PylithScalar* ptr; + PetscErrorCode err; + err = VecGetArray(v, &array);PYLITH_CHECK_ERROR(err); + PetscInt dim; + err = DMGetDimension(dm, &dim);PYLITH_CHECK_ERROR(err); + for (int p = 0; p < _pointCoords.size() / dim; ++p) { + if (_cellNumber[p] < 0) continue; + err = DMPlexPointLocalRef(dm, _cellNumber[p], array, (void*) &ptr);PYLITH_CHECK_ERROR(err); + ptr[0] /= _cellVolume[p]; + } + err = VecRestoreArray(v, &array);PYLITH_CHECK_ERROR(err); + + // Debug option + auxiliaryField->view("MomentTensor auxiliary field."); + + PYLITH_METHOD_RETURN(auxiliaryField); +} // createAuxiliaryField + + +// --------------------------------------------------------------------------------------------------------------------- +// Update auxiliary subfields at beginning of time step. +void +pylith::sources::MomentTensorForce::updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const double t) { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("updateAuxiliaryField(auxiliaryField="<getTimeScale(); + + _sourceTimeFunction->updateAuxiliaryField(auxiliaryField, t, timeScale); + + // if (_useTimeHistory) { + // assert(_scales); + // const PylithScalar timeScale = _scales->getTimeScale(); + // AuxiliaryFactorySourceTime::updateAuxiliaryField(auxiliaryField, t, timeScale, _dbTimeHistory); + // } // if + + PYLITH_METHOD_END; +} // updateAuxiliaryField + + +// --------------------------------------------------------------------------------------------------------------------- +// Create derived field. +pylith::topology::Field* +pylith::sources::MomentTensorForce::createDerivedField(const pylith::topology::Field& solution, + const pylith::topology::Mesh& domainMesh) { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("createDerivedField(solution="<getAuxiliaryFactory(); +} // _getAuxiliaryFactory + + +// --------------------------------------------------------------------------------------------------------------------- +// Update kernel constants. +void +pylith::sources::MomentTensorForce::_updateKernelConstants(const PylithReal dt) { + assert(_sourceTimeFunction); + _sourceTimeFunction->updateKernelConstants(&_kernelConstants, dt); +} // _updateKernelConstants + + +// --------------------------------------------------------------------------------------------------------------------- +// Get derived factory associated with physics. +pylith::topology::FieldFactory* +pylith::sources::MomentTensorForce::_getDerivedFactory(void) { + return _derivedFactory; +} // _getDerivedFactory + + +// --------------------------------------------------------------------------------------------------------------------- +// Set kernels for RHS residual G(t,s). +void +pylith::sources::MomentTensorForce::_setKernelsResidual(pylith::feassemble::IntegratorDomain* integrator, + const topology::Field& solution) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("_setKernelsResidual(integrator="< kernels(1); + switch (_formulation) { + case QUASISTATIC: { + break; + } // QUASISTATIC + case DYNAMIC_IMEX: + case DYNAMIC: { + // Velocity + const PetscPointFunc g0v = NULL; + const PetscPointFunc g1v = _sourceTimeFunction->getKernelg1v_explicit(coordsys); + kernels[0] = ResidualKernels(getSubfieldName(), pylith::feassemble::Integrator::RHS, g0v, g1v); + // kernels[0] = ResidualKernels("velocity", pylith::feassemble::Integrator::RHS, g0v, g1v); + break; + } // DYNAMIC + default: + PYLITH_COMPONENT_LOGICERROR("Unknown formulation for equations (" << _formulation << ")."); + } // switch + + assert(integrator); + integrator->setKernelsResidual(kernels, solution); + + PYLITH_METHOD_END; +} // _setKernelsResidual + + +// --------------------------------------------------------------------------------------------------------------------- +// Set kernels for computing updated state variables in auxiliary field. +void +pylith::sources::MomentTensorForce::_setKernelsUpdateStateVars(pylith::feassemble::IntegratorDomain* integrator, + const topology::Field& solution) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("_setKernelsUpdateStateVars(integrator="< kernels; + _sourceTimeFunction->addKernelsUpdateStateVars(&kernels, coordsys); + + integrator->setKernelsUpdateStateVars(kernels); + + PYLITH_METHOD_END; +} // _setKernelsUpdateStateVars + + +// --------------------------------------------------------------------------------------------------------------------- +// Set kernels for computing derived field. +void +pylith::sources::MomentTensorForce::_setKernelsDerivedField(pylith::feassemble::IntegratorDomain* integrator, + const topology::Field& solution) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("_setKernelsDerivedField(integrator="< + +#include "pylith/sources/RickerWavelet.hh" // implementation of object methods + +#include "pylith/sources/AuxiliaryFactorySourceTime.hh" // USES AuxiliaryFactorySourceTime +#include "pylith/fekernels/RickerWavelet.hh" // USES RickerWavelet kernels +#include "pylith/utils/journals.hh" // USES PYLITH_COMPONENT_* +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_BEGIN/END + +#include "spatialdata/geocoords/CoordSys.hh" // USES CoordSys + +#include // USES typeid() + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::RickerWavelet::RickerWavelet(void) : + _auxiliaryFactory(new pylith::sources::AuxiliaryFactorySourceTime) { + pylith::utils::PyreComponent::setName("rickerwavelet"); +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::RickerWavelet::~RickerWavelet(void) { + deallocate(); +} // destructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Deallocate PETSc and local data structures. +void +pylith::sources::RickerWavelet::deallocate(void) { + SourceTimeFunctionMomentTensorForce::deallocate(); + + delete _auxiliaryFactory;_auxiliaryFactory = NULL; +} // deallocate + + +// --------------------------------------------------------------------------------------------------------------------- +// Get auxiliary factory associated with physics. +pylith::sources::AuxiliaryFactoryMomentTensorForce* +pylith::sources::RickerWavelet::getAuxiliaryFactory(void) { + return _auxiliaryFactory; +} // getAuxiliaryFactory + + +// --------------------------------------------------------------------------------------------------------------------- +// Add source time subfields to auxiliary field. +void +pylith::sources::RickerWavelet::addAuxiliarySubfields(void) { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("addAuxiliarySubfields(void)"); + + // :ATTENTION: The order for adding subfields must match the order of the auxiliary fields in the point-wise + // functions (kernels). + + _auxiliaryFactory->addTimeDelay(); // numA - 2 + _auxiliaryFactory->addCenterFrequency(); // numA - 1 + + PYLITH_METHOD_END; +} // addAuxiliarySubfields + + +// --------------------------------------------------------------------------------------------------------------------- +// Get g1v kernel for residual, G(t,s). +PetscPointFunc +pylith::sources::RickerWavelet::getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("getKernelg1v_explicit(coordsys="<getSpaceDim(); + PetscPointFunc g1v = + (3 == spaceDim) ? pylith::fekernels::RickerWavelet3D::g1v : + (2 == spaceDim) ? pylith::fekernels::RickerWaveletPlaneStrain::g1v : + NULL; + + PYLITH_METHOD_RETURN(g1v); +} // getKernelResidualStress + + +// End of file diff --git a/libsrc/pylith/sources/RickerWavelet.hh b/libsrc/pylith/sources/RickerWavelet.hh new file mode 100644 index 0000000000..a426363129 --- /dev/null +++ b/libsrc/pylith/sources/RickerWavelet.hh @@ -0,0 +1,81 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file libsrc/sources/RickerWavelet.hh + * + * @brief C++ class for Ricker source time function. + */ + +#if !defined(pylith_materials_rickerwavelet_hh) +#define pylith_materials_rickerwavelet_hh + +#include "sourcesfwd.hh" // forward declarations + +#include "pylith/sources/SourceTimeFunctionMomentTensorForce.hh" // ISA SourceTimeFunctionMomentTensorForce + +class pylith::sources::RickerWavelet : public pylith::sources::SourceTimeFunctionMomentTensorForce { + friend class TestRickerWavelet; // unit testing + + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + RickerWavelet(void); + + /// Destructor. + ~RickerWavelet(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void); + + /** Add source time subfields to auxiliary field. + * + * @param[inout] auxiliaryField Auxiliary field. + */ + void addAuxiliarySubfields(void); + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return residual kernel for g1v. + */ + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const; + + // PRIVATE MEMBERS ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + pylith::sources::AuxiliaryFactorySourceTime* _auxiliaryFactory; ///< Factory for creating auxiliary subfields. + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + RickerWavelet(const RickerWavelet&); ///< Not implemented. + const RickerWavelet& operator=(const RickerWavelet&); /// Not implemented. + +}; // class RickerWavelet + +#endif // pylith_materials_rickerwavelet_hh + +// End of file diff --git a/libsrc/pylith/sources/Source.cc b/libsrc/pylith/sources/Source.cc new file mode 100644 index 0000000000..9ea57f1385 --- /dev/null +++ b/libsrc/pylith/sources/Source.cc @@ -0,0 +1,235 @@ +// -*- C++ -*- +// +// --------------------------------------------------------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2015 University of California, Davis +// +// See COPYING for license information. +// +// --------------------------------------------------------------------------------------------------------------------- +// + +#include + +#include "Source.hh" // implementation of object methods + +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_* +#include "pylith/utils/journals.hh" // USES PYLITH_COMPONENT_* + +#include // USES assert() +#include // USES std::runtime_error + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::Source::Source(void) : + _subfieldName(""), + _description(""), + _labelName(""), + _labelValue(1) { + // +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::Source::~Source(void) { + deallocate(); +} // destructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Deallocate PETSc and local data structures. +void +pylith::sources::Source::deallocate(void) { + PYLITH_METHOD_BEGIN; + + pylith::problems::Physics::deallocate(); + + PYLITH_METHOD_END; +} // deallocate + + +// ------------------------------------------------------------------------------------------------ +// Set descriptive label of source. +void +pylith::sources::Source::setDescription(const char* value) { + PYLITH_COMPONENT_DEBUG("setDescription(value="< +pylith::sources::Source::createConstraints(const pylith::topology::Field& solution) { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("createConstraints(solution="< constraintArray; + + PYLITH_METHOD_RETURN(constraintArray); +} // createConstraints + + +// ------------------------------------------------------------------------------------------------ +// Set point names and coordinates of points . +void +pylith::sources::Source::setPoints(const PylithReal* pointCoords, + const int numPoints, + const int spaceDim, + const char* const* pointNames, + const int numPointNames) { + PYLITH_METHOD_BEGIN; + + assert(pointCoords && pointNames); + assert(numPoints == numPointNames); + + // Copy point coordinates. + const PylithInt size = numPoints * spaceDim; + _pointCoords.resize(size); + for (PylithInt i = 0; i < size; ++i) { + _pointCoords[i] = pointCoords[i]; + } // for + + // Copy point names. + _pointNames.resize(numPointNames); + for (PylithInt i = 0; i < numPointNames; ++i) { + _pointNames[i] = pointNames[i]; + } // for + + PYLITH_METHOD_END; +} // setPoints + + +// ------------------------------------------------------------------------------------------------ +// Convert cartesian positions to a labeled source +void +pylith::sources::Source::locateSource(const pylith::topology::Field& solution, + const char labelName[], + const int labelValue) { + // printf("In MomentTensorForce begin\n"); + // DMView(solution.getDM(), NULL); + PetscErrorCode err; + PetscDM dmSoln = solution.getDM();assert(dmSoln); + // transform points of source to mesh coordinates in python + // DM from solution + Vec vecPoints; + DMLabel label; + PetscSF sfPoints = NULL; + const PetscInt *localPoints; + const PetscSFNode *remotePoints; + PetscInt numRoots = -1, numLeaves, dim, d; + PetscMPIInt rank; + PetscScalar *a; + + err = DMGetCoordinateDim(dmSoln, &dim);PYLITH_CHECK_ERROR(err); + err = VecCreateSeqWithArray(PETSC_COMM_SELF, dim, _pointCoords.size(), + &_pointCoords[0], &vecPoints);PYLITH_CHECK_ERROR(err); + + // Debug + // PetscPrintf(PetscObjectComm((PetscObject) dmSoln), "_pointCoords\n"); + // PetscPrintf(PetscObjectComm((PetscObject) dmSoln), " x = %g\n", _pointCoords[0]); + // PetscPrintf(PetscObjectComm((PetscObject) dmSoln), " y = %g\n", _pointCoords[1]); + // Erzatz from ex17 + // err = VecCreateSeq(PETSC_COMM_SELF, dim, &vecPoints);PYLITH_CHECK_ERROR(err); + // err = VecSetBlockSize(vecPoints, _pointCoords.size());PYLITH_CHECK_ERROR(err); + // err = VecGetArray(vecPoints, &a);PYLITH_CHECK_ERROR(err); + // for (d = 0; d < _pointCoords.size(); ++d) { + // a[d] = _pointCoords[d]; + // } + // err = VecRestoreArray(vecPoints, &a);PYLITH_CHECK_ERROR(err); + + err = DMLocatePoints(dmSoln, vecPoints, DM_POINTLOCATION_NONE, &sfPoints);PYLITH_CHECK_ERROR(err); + // err = PetscSFView(sfPoints, NULL);PYLITH_CHECK_ERROR(err); + err = VecDestroy(&vecPoints);PYLITH_CHECK_ERROR(err); + err = DMCreateLabel(dmSoln,labelName);PYLITH_CHECK_ERROR(err); + err = DMGetLabel(dmSoln,labelName, &label);PYLITH_CHECK_ERROR(err); + err = PetscSFGetGraph(sfPoints, &numRoots, &numLeaves, &localPoints, &remotePoints);PYLITH_CHECK_ERROR(err); + err = MPI_Comm_rank(PetscObjectComm((PetscObject) dmSoln), &rank);PYLITH_CHECK_ERROR(err); + // Debug + // PetscPrintf(PetscObjectComm((PetscObject) dmSoln), "localPoints: %D\n",Thread 1 "mpinemesis" hit Breakpoint 1, + // pylith::sources::Source numLeaves); + // PetscMPIInt rank; + err = MPI_Comm_rank(PetscObjectComm((PetscObject)dmSoln), &rank); + + PetscInt pcs = _pointCoords.size() / dim; + _cellNumber.resize(pcs); + _cellVolume.resize(pcs); + + for (PetscInt p = 0; p < pcs; ++p) { + PetscPrintf(PETSC_COMM_SELF, "[%i] OUTPUT rank: %i, index: %i, label: %s, labelValue: %i \n", (int)rank, (PetscInt)remotePoints[p].rank, (PetscInt)remotePoints[p].index, labelName, (int) labelValue); + if ((remotePoints[p].index >= 0)) { + PetscReal cV; + err = DMLabelSetValue(label, remotePoints[p].index, labelValue);PYLITH_CHECK_ERROR(err); + err = DMPlexComputeCellGeometryFVM(dmSoln,remotePoints[p].index, &cV, NULL, NULL);PYLITH_CHECK_ERROR(err); + _cellVolume[p] = cV; + _cellNumber[p] = remotePoints[p].index; + } else { + _cellVolume[p] = -1.; + _cellNumber[p] = -1; + } + } // for + PetscIS cellIS; + err = DMLabelGetStratumIS(label, labelValue, &cellIS);PYLITH_CHECK_ERROR(err); + if (cellIS) { + PetscInt numCells; + const PetscInt* cells; + err = ISGetSize(cellIS, &numCells);PYLITH_CHECK_ERROR(err); + err = ISGetIndices(cellIS, &cells);PYLITH_CHECK_ERROR(err); + for (PetscInt p = 0; p < pcs; ++p) { + PetscInt loc; + if (_cellNumber[p] < 0) continue; + err = PetscFindInt(_cellNumber[p], numCells, cells, &loc);PYLITH_CHECK_ERROR(err); + assert(loc >= 0); + _cellNumber[p] = loc; + } + err = ISRestoreIndices(cellIS, &cells);PYLITH_CHECK_ERROR(err); + } + err = DMLabelView(label, NULL);PYLITH_CHECK_ERROR(err); + + err = PetscSFDestroy(&sfPoints);PYLITH_CHECK_ERROR(err); + // printf("In MomentTensorForce end\n"); + // // DMView(dmSoln, NULL); +} + + +// End of file diff --git a/libsrc/pylith/sources/Source.hh b/libsrc/pylith/sources/Source.hh new file mode 100644 index 0000000000..5674748a2a --- /dev/null +++ b/libsrc/pylith/sources/Source.hh @@ -0,0 +1,140 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2015 University of California, Davis +// +// See COPYING for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file libsrc/sources/Source.hh + * + * @brief C++ abstract base class for sources. + */ + +#if !defined(pylith_sources_source_hh) +#define pylith_sources_source_hh + +#include "sourcesfwd.hh" // forward declarations +#include "pylith/topology/topologyfwd.hh" +#include "pylith/utils/petscfwd.h" +#include "spatialdata/geocoords/geocoordsfwd.hh" // USES CoordSys +#include "pylith/problems/Physics.hh" // ISA Physics + +#include // HASA std::string + +// Source ------------------------------------------------------------- +/** @brief C++ abstract base class for sources. + * + */ + +class pylith::sources::Source : public pylith::problems::Physics { + friend class TestSource; // unit testing + + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + Source(void); + + /// Destructor. + virtual ~Source(void); + + /// Deallocate PETSc and local data structures. + virtual + void deallocate(void); + + /** Set descriptive label for source. + * + * @param value Label of source. + */ + void setDescription(const char* value); + + /** Get descruptive label of source. + * + * @returns Label of source + */ + const char* getDescription(void) const; + + /** Set first choice for reference direction to discriminate among tangential directions in 3-D. + * + * @param vec Reference direction unit vector. + * /** Create constraint and set kernels. + * + * @param[in] solution Solution field. + * @returns Constraint if applicable, otherwise NULL. + */ + + /** Set name of solution subfield associated with boundary condition. + * + * @param[in] value Name of solution subfield. + */ + void setSubfieldName(const char* value); + + /** Get name of solution subfield associated with boundary condition. + * + * @preturn Name of solution subfield. + */ + const char* getSubfieldName(void) const; + + virtual + std::vector createConstraints(const pylith::topology::Field& solution); + + /** Set coordinates and names of points. + * + * @param[in] points Array of coordinates [numPoints * spaceDim]. + * @param[in] numPoints Number of points. + * @param[in] spaceDim Spatial dimension for coordinates. + * @param[in] pointNames Array with point names. + * @param[in] numPointNames Number of point banes. + */ + void setPoints(const PylithReal* pointCoords, + const int numPoints, + const int spaceDim, + const char* const* pointNames, + const int numPointNames); + + /** Assign source label from coordinates. + */ + void locateSource(const pylith::topology::Field& solution, + const char labelName[], + const int labelValue); + + // PROTECTED MEMBERS /////////////////////////////////////////////////////////////////////////////////////////////// +protected: + + pylith::scalar_array _pointCoords; ///< Array of point coordinates. + pylith::string_vector _pointNames; ///< Array of point names. + std::string _description; ///< Descriptive label for source. + std::string _labelName; ///< Name of label to identify source points in mesh. + int _labelValue; ///< Value of label to identify source points in mesh. + std::string _subfieldName; ///< Name of solution subfield for boundary condition. + pylith::int_array _cellNumber; ///< Numbers of cells used for source + pylith::scalar_array _cellVolume; ///< Volumes of cell used for source + + // PRIVATE MEMBERS ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + pylith::topology::Mesh* _pointMesh; ///< Mesh for points (no cells). + pylith::topology::Field* _pointSoln; ///< Solution field at points. + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + Source(const Source&); ///< Not implemented. + const Source& operator=(const Source&); ///< Not implemented + +}; // Source + +#endif // pylith_sources_source_hh + +// End of file diff --git a/libsrc/pylith/sources/SourceTimeFunctionMomentTensorForce.cc b/libsrc/pylith/sources/SourceTimeFunctionMomentTensorForce.cc new file mode 100644 index 0000000000..0212ebfd43 --- /dev/null +++ b/libsrc/pylith/sources/SourceTimeFunctionMomentTensorForce.cc @@ -0,0 +1,103 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +#include + +#include "pylith/sources/SourceTimeFunctionMomentTensorForce.hh" // implementation of object methods + +#include "pylith/feassemble/Integrator.hh" // USES NEW_JACOBIAN_NEVER + +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_BEGIN/END +#include "pylith/utils/journals.hh" // USES PYLITH_COMPONENT_DEBUG + +#include "spatialdata/geocoords/CoordSys.hh" // USES CoordSys + +#include // USES typeid() + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::SourceTimeFunctionMomentTensorForce::SourceTimeFunctionMomentTensorForce(void) : + _JacobianTriggers(pylith::feassemble::Integrator::NEW_JACOBIAN_NEVER) {} + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::SourceTimeFunctionMomentTensorForce::~SourceTimeFunctionMomentTensorForce(void) { + deallocate(); +} // destructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Deallocate PETSc and local data structures. +void +pylith::sources::SourceTimeFunctionMomentTensorForce::deallocate(void) { +} + + +// --------------------------------------------------------------------------------------------------------------------- +// Get triggers for needing to compute the elastic constants for the RHS Jacobian. +int +pylith::sources::SourceTimeFunctionMomentTensorForce::getJacobianTriggers(void) const { + return _JacobianTriggers; +} // getJacobianTriggers + + +// --------------------------------------------------------------------------------------------------------------------- +// Update kernel constants. +void +pylith::sources::SourceTimeFunctionMomentTensorForce::updateKernelConstants(pylith::real_array* kernelConstants, + const PylithReal dt) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("updateKernelConstants(kernelConstants"<* kernels, + const spatialdata::geocoords::CoordSys* coordsys) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("addKernelsUpdateStateVars(kernels="<* kernels, + const spatialdata::geocoords::CoordSys* coordsys) const; + + /** Update kernel constants. + * + * @param[inout] kernelConstants Array of constants used in integration kernels. + * @param[in] dt Current time step. + */ + virtual + void updateKernelConstants(pylith::real_array* kernelConstants, + const PylithReal dt) const; + + /** Update auxiliary field for current time. + * + * @param[inout] auxiliaryField Auxiliary field to update. + * @param[in] t Current time. + * @param[in] timeScale Time scale for nondimensionalization. + */ + virtual + void updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const PylithReal t, + const PylithReal timeScale); + + // PROTECTED MEMBERS /////////////////////////////////////////////////////////////////////////////////////////////// + + int _JacobianTriggers; ///< Triggers for needing to recompute the RHS Jacobian. + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + SourceTimeFunctionMomentTensorForce(const SourceTimeFunctionMomentTensorForce&); ///< Not implemented. + const SourceTimeFunctionMomentTensorForce& operator=(const SourceTimeFunctionMomentTensorForce&); /// Not + + /// implemented. + +}; // class SourceTimeFunctionMomentTensorForce + +#endif // pylith_sources_sourcetimefunctionmomenttensorforce_hh + +// End of file diff --git a/libsrc/pylith/sources/SquareWavelet.cc b/libsrc/pylith/sources/SquareWavelet.cc new file mode 100644 index 0000000000..8036ff386d --- /dev/null +++ b/libsrc/pylith/sources/SquareWavelet.cc @@ -0,0 +1,99 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +#include + +#include "pylith/sources/SquareWavelet.hh" // implementation of object methods + +#include "pylith/sources/AuxiliaryFactorySourceTime.hh" // USES AuxiliaryFactorySourceTime +#include "pylith/fekernels/SquareWavelet.hh" // USES SquareWavelet kernels +#include "pylith/utils/journals.hh" // USES PYLITH_COMPONENT_* +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_BEGIN/END + +#include "spatialdata/geocoords/CoordSys.hh" // USES CoordSys + +#include // USES typeid() + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::SquareWavelet::SquareWavelet(void) : + _auxiliaryFactory(new pylith::sources::AuxiliaryFactorySourceTime) { + pylith::utils::PyreComponent::setName("squarewavelet"); +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::SquareWavelet::~SquareWavelet(void) { + deallocate(); +} // destructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Deallocate PETSc and local data structures. +void +pylith::sources::SquareWavelet::deallocate(void) { + SourceTimeFunctionMomentTensorForce::deallocate(); + + delete _auxiliaryFactory;_auxiliaryFactory = NULL; +} // deallocate + + +// --------------------------------------------------------------------------------------------------------------------- +// Get auxiliary factory associated with physics. +pylith::sources::AuxiliaryFactoryMomentTensorForce* +pylith::sources::SquareWavelet::getAuxiliaryFactory(void) { + return _auxiliaryFactory; +} // getAuxiliaryFactory + + +// --------------------------------------------------------------------------------------------------------------------- +// Add source time subfields to auxiliary field. +void +pylith::sources::SquareWavelet::addAuxiliarySubfields(void) { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("addAuxiliarySubfields(void)"); + + // :ATTENTION: The order for adding subfields must match the order of the auxiliary fields in the point-wise + // functions (kernels). + + _auxiliaryFactory->addTimeDelay(); // numA - 2 + _auxiliaryFactory->addCenterFrequency(); // numA - 1 + + PYLITH_METHOD_END; +} // addAuxiliarySubfields + + +// --------------------------------------------------------------------------------------------------------------------- +// Get g1v kernel for residual, G(t,s). +PetscPointFunc +pylith::sources::SquareWavelet::getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("getKernelg1v_explicit(coordsys="<getSpaceDim(); + PetscPointFunc g1v = + (3 == spaceDim) ? pylith::fekernels::SquareWavelet3D::g1v : + (2 == spaceDim) ? pylith::fekernels::SquareWaveletPlaneStrain::g1v : + NULL; + + PYLITH_METHOD_RETURN(g1v); +} // getKernelResidualStress + + +// End of file diff --git a/libsrc/pylith/sources/SquareWavelet.hh b/libsrc/pylith/sources/SquareWavelet.hh new file mode 100644 index 0000000000..f5149d7524 --- /dev/null +++ b/libsrc/pylith/sources/SquareWavelet.hh @@ -0,0 +1,81 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file libsrc/sources/SquareWavelet.hh + * + * @brief C++ class for Square source time function. + */ + +#if !defined(pylith_materials_squarewavelet_hh) +#define pylith_materials_squarewavelet_hh + +#include "sourcesfwd.hh" // forward declarations + +#include "pylith/sources/SourceTimeFunctionMomentTensorForce.hh" // ISA SourceTimeFunctionMomentTensorForce + +class pylith::sources::SquareWavelet : public pylith::sources::SourceTimeFunctionMomentTensorForce { + friend class TestSquareWavelet; // unit testing + + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + SquareWavelet(void); + + /// Destructor. + ~SquareWavelet(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void); + + /** Add source time subfields to auxiliary field. + * + * @param[inout] auxiliaryField Auxiliary field. + */ + void addAuxiliarySubfields(void); + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return residual kernel for g1v. + */ + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const; + + // PRIVATE MEMBERS ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + pylith::sources::AuxiliaryFactorySourceTime* _auxiliaryFactory; ///< Factory for creating auxiliary subfields. + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + SquareWavelet(const SquareWavelet&); ///< Not implemented. + const SquareWavelet& operator=(const SquareWavelet&); /// Not implemented. + +}; // class SquareWavelet + +#endif // pylith_materials_squarewavelet_hh + +// End of file diff --git a/libsrc/pylith/sources/TimeHistoryWavelet.cc b/libsrc/pylith/sources/TimeHistoryWavelet.cc new file mode 100644 index 0000000000..204f056427 --- /dev/null +++ b/libsrc/pylith/sources/TimeHistoryWavelet.cc @@ -0,0 +1,154 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +#include +#include "spatialdata/spatialdb/TimeHistory.hh" // USES TimeHistory +#include "pylith/sources/TimeHistoryWavelet.hh" // implementation of object methods + +#include "pylith/sources/AuxiliaryFactorySourceTime.hh" // USES AuxiliaryFactorySourceTime + +#include "pylith/fekernels/TimeHistoryWavelet.hh" // USES TimeHistoryWavelet kernels + +#include "pylith/utils/journals.hh" // USES PYLITH_COMPONENT_* +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_BEGIN/END + +#include "spatialdata/geocoords/CoordSys.hh" // USES CoordSys + +#include // USES typeid() + +// --------------------------------------------------------------------------------------------------------------------- +// Default constructor. +pylith::sources::TimeHistoryWavelet::TimeHistoryWavelet(void) : + _dbTimeHistory(NULL), + _auxiliaryFactory(new pylith::sources::AuxiliaryFactorySourceTime), + _useTimeHistory(true) { + pylith::utils::PyreComponent::setName("timehistorywavelet"); +} // constructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Destructor. +pylith::sources::TimeHistoryWavelet::~TimeHistoryWavelet(void) { + deallocate(); +} // destructor + + +// --------------------------------------------------------------------------------------------------------------------- +// Deallocate PETSc and local data structures. +void +pylith::sources::TimeHistoryWavelet::deallocate(void) { + SourceTimeFunctionMomentTensorForce::deallocate(); + + delete _auxiliaryFactory;_auxiliaryFactory = NULL; +} // deallocate + + +// --------------------------------------------------------------------------------------------------------------------- +// Set time history database. +void +pylith::sources::TimeHistoryWavelet::setTimeHistoryDB(spatialdata::spatialdb::TimeHistory* th) { + PYLITH_COMPONENT_DEBUG("setTimeHistoryDB(th"<addTimeHistoryAmplitude(); // numA - 3 + _auxiliaryFactory->addTimeHistoryStartTime(); // numA - 2 + _auxiliaryFactory->addTimeHistoryValue(); // numA - 1 + if (_dbTimeHistory) { + _dbTimeHistory->open(); + } // if + PYLITH_METHOD_END; +} // addAuxiliarySubfields + + +// --------------------------------------------------------------------------------------------------------------------- +// Get g1v kernel for residual, G(t,s). +PetscPointFunc +pylith::sources::TimeHistoryWavelet::getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const { + PYLITH_METHOD_BEGIN; + PYLITH_COMPONENT_DEBUG("getKernelg1v_explicit(coordsys="<getSpaceDim(); + PetscPointFunc g1v = + (3 == spaceDim) ? pylith::fekernels::TimeHistoryWavelet3D::g1v : + (2 == spaceDim) ? pylith::fekernels::TimeHistoryWaveletPlaneStrain::g1v : + NULL; + + PYLITH_METHOD_RETURN(g1v); +} // getKernelResidualStress + + +// --------------------------------------------------------------------------------------------------------------------- +// Update auxiliary fields. +void +pylith::sources::TimeHistoryWavelet::updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const PylithReal t, + const PylithReal timeScale) { + if (_useTimeHistory) { + AuxiliaryFactorySourceTime::updateAuxiliaryField(auxiliaryField, t, timeScale, _dbTimeHistory); + } // if +} + + +// End of file diff --git a/libsrc/pylith/sources/TimeHistoryWavelet.hh b/libsrc/pylith/sources/TimeHistoryWavelet.hh new file mode 100644 index 0000000000..6f6cbf476d --- /dev/null +++ b/libsrc/pylith/sources/TimeHistoryWavelet.hh @@ -0,0 +1,117 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file libsrc/sources/TimeHistoryWavelet.hh + * + * @brief C++ class for Ricker source time function. + */ + +#if !defined(pylith_materials_timehistorywavelet_hh) +#define pylith_materials_timehistorywavelet_hh + +#include "sourcesfwd.hh" // forward declarations + +#include "pylith/sources/SourceTimeFunctionMomentTensorForce.hh" // ISA SourceTimeFunctionMomentTensorForce + +class pylith::sources::TimeHistoryWavelet : public pylith::sources::SourceTimeFunctionMomentTensorForce { + friend class TestTimeHistoryWavelet; // unit testing + + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + TimeHistoryWavelet(void); + + /// Destructor. + ~TimeHistoryWavelet(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Set time history database. + * + * @param[in] db Time history database. + */ + void setTimeHistoryDB(spatialdata::spatialdb::TimeHistory* th); + + /** Get time history database. + * + * @preturns Time history database. + */ + const spatialdata::spatialdb::TimeHistory* getTimeHistoryDB(void); + + /** Use time history term in time history expression. + * + * @param[in] value True if using time history term in expression. + */ + void useTimeHistory(const bool value); + + /** Get flag associated with using time history term in time history expression. + * + * @returns True if using time history term in expression, false otherwise. + */ + bool useTimeHistory(void) const; + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void); + + /** Add source time subfields to auxiliary field. + * + * @param[inout] auxiliaryField Auxiliary field. + */ + void addAuxiliarySubfields(void); + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return residual kernel for g1v. + */ + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const; + + /** Update auxiliary field for current time. + * + * @param[inout] auxiliaryField Auxiliary field to update. + * @param[in] t Current time. + * @param[in] timeScale Time scale for nondimensionalization. + */ + void updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const PylithReal t, + const PylithReal timeScale) override; + + // PRIVATE MEMBERS ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + pylith::sources::AuxiliaryFactorySourceTime* _auxiliaryFactory; ///< Factory for creating auxiliary subfields. + spatialdata::spatialdb::TimeHistory* _dbTimeHistory; ///< Time history database. + bool _useTimeHistory; ///< Use time history term. + + // NOT IMPLEMENTED ///////////////////////////////////////////////////////////////////////////////////////////////// +private: + + TimeHistoryWavelet(const TimeHistoryWavelet&); ///< Not implemented. + const TimeHistoryWavelet& operator=(const TimeHistoryWavelet&); /// Not implemented. + +}; // class TimeHistoryWavelet + +#endif // pylith_materials_timehistorywavelet_hh + +// End of file diff --git a/libsrc/pylith/sources/sourcesfwd.hh b/libsrc/pylith/sources/sourcesfwd.hh new file mode 100644 index 0000000000..dacb8814c1 --- /dev/null +++ b/libsrc/pylith/sources/sourcesfwd.hh @@ -0,0 +1,51 @@ +// -*- C++ -*- +// +// ====================================================================== +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2017 University of California, Davis +// +// See COPYING for license information. +// +// ====================================================================== +// + +/** @file libsrc/sources/sourcesfwd.hh + * + * @brief Forward declarations for PyLith sources objects. + * + * Including this header file eliminates the need to use separate + * forward declarations. + */ + +#if !defined(pylith_sources_sourcesfwd_hh) +#define pylith_sources_sourcesfwd_hh + +namespace pylith { + namespace sources { + // New stuff + class Source; + + class MomentTensorForce; + class AuxiliaryFactoryMomentTensorForce; + class DerivedFactoryMomentTensorForce; + + class SourceTimeFunctionMomentTensorForce; + class AuxiliaryFactorySourceTime; + class SquareWavelet; + class RickerWavelet; + class GaussianWavelet; + class TimeHistoryWavelet; + + } // sources +} // pylith + +#endif // pylith_sources_sourcesfwd_hh + +// End of file diff --git a/modulesrc/Makefile.am b/modulesrc/Makefile.am index 148f94b645..280fa28219 100644 --- a/modulesrc/Makefile.am +++ b/modulesrc/Makefile.am @@ -19,6 +19,7 @@ SUBDIRS = \ mpi \ problems \ scales \ + sources \ topology \ utils diff --git a/modulesrc/include/physicsarray.i b/modulesrc/include/physicsarray.i index fd129f27f9..65e4c832b2 100644 --- a/modulesrc/include/physicsarray.i +++ b/modulesrc/include/physicsarray.i @@ -80,6 +80,48 @@ delete[] $1; } +// ---------------------------------------------------------------------- +// List of sources. +%typemap(in)(pylith::sources::Source *sources[], + const int numSources) +{ + // Check to make sure input is a list. + if (PyList_Check($input)) + { + const int size = PyList_Size($input); + $2 = size; + $1 = (size > 0) ? new pylith::sources::Source *[size] : 0; + for (int i = 0; i < size; i++) + { + PyObject *s = PyList_GetItem($input, i); + pylith::sources::Source *sources = 0; + int err = SWIG_ConvertPtr(s, (void **)&sources, + $descriptor(pylith::sources::Source *), + 0); + if (SWIG_IsOK(err)) + $1[i] = (pylith::sources::Source *)sources; + else + { + PyErr_SetString(PyExc_TypeError, "List must contain sources."); + delete[] $1; + return NULL; + } // if + } // for + } + else + { + PyErr_SetString(PyExc_TypeError, "Expected list of sources."); + return NULL; + } // if/else +} // typemap(in) [List of sources.] + +// This cleans up the array we malloc'd before the function call +%typemap(freearg)(pylith::sources::Source *sources[], + const int numSources) +{ + delete[] $1; +} + // ---------------------------------------------------------------------- // List of initial conditions. %typemap(in) (pylith::problems::InitialCondition* ic[], diff --git a/modulesrc/problems/Problem.i b/modulesrc/problems/Problem.i index 0f69b249b2..bfa1278507 100644 --- a/modulesrc/problems/Problem.i +++ b/modulesrc/problems/Problem.i @@ -107,6 +107,14 @@ public: void setMaterials(pylith::materials::Material* materials[], const int numMaterials); + /** Set sources. + * + * @param[in] sources Array of sources. + * @param[in] numSource Number of sources. + */ + void setSources(pylith::sources::Source* sources[], + const int numSources); + /** Set boundary conditions. * * @param[in] bc Array of boundary conditions. diff --git a/modulesrc/sources/GaussianWavelet.i b/modulesrc/sources/GaussianWavelet.i new file mode 100644 index 0000000000..1878df9253 --- /dev/null +++ b/modulesrc/sources/GaussianWavelet.i @@ -0,0 +1,67 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file modulesrc/sources/GaussianWavelet.i + * + * Python interface to C++ GaussianWavelet. + */ + +namespace pylith { + namespace sources { + class GaussianWavelet : public pylith::sources::SourceTimeFunctionMomentTensorForce { + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + GaussianWavelet(void); + + /// Destructor. + ~GaussianWavelet(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void); + + /** Add source time function subfields to auxiliary field. + * + * @param[inout] auxiliaryField Auxiliary field. + */ + void addAuxiliarySubfields(void); + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return residual kernel for g1v + . + */ + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const; + + }; + + // class GaussianWavelet + + } // sources +} // pylith + +// End of file diff --git a/modulesrc/sources/Makefile.am b/modulesrc/sources/Makefile.am new file mode 100644 index 0000000000..aed37dcc8f --- /dev/null +++ b/modulesrc/sources/Makefile.am @@ -0,0 +1,74 @@ +# -*- Makefile -*- +# +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University of Chicago +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2017 University of California, Davis +# +# See COPYING for license information. +# +# ---------------------------------------------------------------------- +# + +subpackage = sources +include $(top_srcdir)/subpackage.am +include $(top_srcdir)/modulesrc/module.am + +subpkgpython_LTLIBRARIES = _sources.la + +subpkgpython_PYTHON = sources.py + +swig_sources = \ + sources.i \ + ../problems/Physics.i \ + Source.i \ + MomentTensorForce.i \ + SourceTimeFunctionMomentTensorForce.i \ + RickerWavelet.i \ + GaussianWavelet.i \ + TimeHistoryWavelet.i \ + ../utils/PyreComponent.i + +swigincludedir = $(pkgdatadir)/swig/$(subpackage) +swiginclude_HEADERS = \ + Source.i + +swig_generated = \ + sources_wrap.cxx \ + sources.py + +_sources_la_LDFLAGS = -module -avoid-version \ + -g $(AM_LDFLAGS) $(PYTHON_LA_LDFLAGS) + +dist__sources_la_SOURCES = $(swig_sources) $(swig_generated) + +_sources_la_LIBADD = \ + $(top_builddir)/libsrc/pylith/libpylith.la \ + -lspatialdata \ + $(PETSC_LIB) \ + $(PYTHON_BLDLIBRARY) $(PYTHON_LIBS) $(PYTHON_SYSLIBS) +if ENABLE_CUBIT + _sources_la_LIBADD += -lnetcdf +endif + +if ENABLE_SWIG +$(srcdir)/sources_wrap.cxx $(srcdir)/sources.py: $(swig_sources) + $(SWIG) $(PETSC_CC_INCLUDES) -Wall -c++ -python $< +else +$(srcdir)/sources_wrap.cxx $(srcdir)/sources.py: + $(error Missing SWIG generated files. Make sure SWIG is installed and reconfigure with --enable-swig) +endif + + +MAINTAINERCLEANFILES = \ + $(srcdir)/sources_wrap.cxx \ + $(srcdir)/sources.py + + +# End of file diff --git a/modulesrc/sources/MomentTensorForce.i b/modulesrc/sources/MomentTensorForce.i new file mode 100644 index 0000000000..b4fca5fe50 --- /dev/null +++ b/modulesrc/sources/MomentTensorForce.i @@ -0,0 +1,105 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2016 University of California, Davis +// +// See COPYING for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file modulesrc/sources/MomentTensorForce.i + * + * Python interface to C++ MomentTensorForce. + */ + +namespace pylith { + namespace sources { + class MomentTensorForce : public pylith::sources::Source { + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + MomentTensorForce(void); + + /// Destructor. + ~MomentTensorForce(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Set source time function. + * + * @param[in] sourceTimeFunction Source time function for moment tensor force. + */ + void setSourceTimeFunction(pylith::sources::SourceTimeFunctionMomentTensorForce* const sourceTimeFunction); + + /** Get source time function. + * + * @returns Source time function for moment tensor force. + */ + pylith::sources::SourceTimeFunctionMomentTensorForce* getSourceTimeFunction(void) const; + + /** Verify configuration is acceptable. + * + * @param[in] solution Solution field. + */ + void verifyConfiguration(const pylith::topology::Field& solution) const; + + /** Create integrator and set kernels. + * + * @param[in] solution Solution field. + * + * @returns Integrator if applicable, otherwise NULL. + */ + pylith::feassemble::Integrator* createIntegrator(const pylith::topology::Field& solution); + + /** Create auxiliary field. + * + * @param[in] solution Solution field. + * @param[in\ domainMesh Finite-element mesh associated with integration domain. + * + * @returns Auxiliary field if applicable, otherwise NULL. + */ + pylith::topology::Field* createAuxiliaryField(const pylith::topology::Field& solution, + const pylith::topology::Mesh& domainMesh); + + /** Create derived field. + * + * @param[in] solution Solution field. + * @param[in\ domainMesh Finite-element mesh associated with integration domain. + * + * @returns Derived field if applicable, otherwise NULL. + */ + pylith::topology::Field* createDerivedField(const pylith::topology::Field& solution, + const pylith::topology::Mesh& domainMesh); + + // PROTECTED METHODS /////////////////////////////////////////////////////////////////////////////////////// +protected: + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::feassemble::AuxiliaryFactory* _getAuxiliaryFactory(void); + + /** Update kernel constants. + * + * @param[in] dt Current time step. + */ + void _updateKernelConstants(const PylithReal dt); + + }; // class MomentTensorForce + + } // sources +} // pylith + +// End of file \ No newline at end of file diff --git a/modulesrc/sources/RickerWavelet.i b/modulesrc/sources/RickerWavelet.i new file mode 100644 index 0000000000..06510d028b --- /dev/null +++ b/modulesrc/sources/RickerWavelet.i @@ -0,0 +1,67 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file modulesrc/sources/RickerWavelet.i + * + * Python interface to C++ RickerWavelet. + */ + +namespace pylith { + namespace sources { + class RickerWavelet : public pylith::sources::SourceTimeFunctionMomentTensorForce { + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + RickerWavelet(void); + + /// Destructor. + ~RickerWavelet(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void); + + /** Add source time function subfields to auxiliary field. + * + * @param[inout] auxiliaryField Auxiliary field. + */ + void addAuxiliarySubfields(void); + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return residual kernel for g1v + . + */ + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const; + + }; + + // class RickerWavelet + + } // sources +} // pylith + +// End of file diff --git a/modulesrc/sources/Source.i b/modulesrc/sources/Source.i new file mode 100644 index 0000000000..de8639d413 --- /dev/null +++ b/modulesrc/sources/Source.i @@ -0,0 +1,103 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2016 University of California, Davis +// +// See COPYING for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file modulesrc/sources/Source.i + * + * Python interface to C++ abstract base class Source. + */ + +namespace pylith { + namespace sources { + class Source : public pylith::problems::Physics { + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////// +public: + + /** Default constructor. + * + * @param dimension Spatial dimension associated with source. + */ + Source(const int dimension); + + /// Destructor. + virtual ~Source(void); + + /// Deallocate PETSc and local data structures. + virtual + void deallocate(void); + + /** Set descriptive label for source. + * + * @param value Label of source. + */ + void setDescription(const char* value); + + /** Get descruptive label of source. + * + * @returns Label of source + */ + const char* getDescription(void) const; + + /** Set name of solution subfield associated with source. + * + * @param[in] value Name of solution subfield. + */ + void setSubfieldName(const char* value); + + /** Get name of solution subfield associated with source. + * + * @preturn Name of solution subfield. + */ + const char* getSubfieldName(void) const; + + /** Create constraint and set kernels. + * + * @param[in] solution Solution field. + * @returns Constraint if applicable, otherwise NULL. + */ + virtual + std::vector createConstraints(const pylith::topology::Field& solution); + + /** Set coordinates and names of points. + * + * @param[in] points Array of coordinates [numPoints * spaceDim]. + * @param[in] numPoints Number of points. + * @param[in] spaceDim Spatial dimension for coordinates. + * @param[in] pointNames Array with point names. + * @param[in] numPointNames Number of point names. + */ + %apply(double* IN_ARRAY2, int DIM1, int DIM2) { + (const PylithReal* pointCoords, + const int numPoints, + const int spaceDim) + }; + %apply(const char* const* string_list, const int list_len){ + (const char* const* pointNames, const int numPointNames) + }; + void setPoints(const PylithReal* pointCoords, + const int numPoints, + const int spaceDim, + const char* const* pointNames, + const int numPointNames); + %clear(const PylithReal* pointCoords, const int numPoints, const int spaceDim); + %clear(const char* const* pointNames, const int numPointNames); + }; // class Source + + } // sources +} // pylith + +// End of file \ No newline at end of file diff --git a/modulesrc/sources/SourceTimeFunctionMomentTensorForce.i b/modulesrc/sources/SourceTimeFunctionMomentTensorForce.i new file mode 100644 index 0000000000..a9cc95feab --- /dev/null +++ b/modulesrc/sources/SourceTimeFunctionMomentTensorForce.i @@ -0,0 +1,84 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file modulesrc/sources/SourceTimeFunctionMomentTensorForce.i + * + * Python interface to C++ abstract base class SourceTimeFunctionMomentTensorForce. + */ + +namespace pylith { + namespace sources { + class SourceTimeFunctionMomentTensorForce : public pylith::utils::PyreComponent { + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + SourceTimeFunctionMomentTensorForce(void); + + /// Destructor. + virtual ~SourceTimeFunctionMomentTensorForce(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + virtual + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void) = 0; + + /// Add sourcetimefunction subfields to auxiliary field. + virtual + void addAuxiliarySubfields(void) = 0; + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return RHS residual kernel for stress. + */ + virtual + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const = 0; + + /** Add kernels for updating state variables. + * + * @param[inout] kernels Array of kernels for updating state variables. + * @param[in] coordsys Coordinate system. + */ + virtual + void addKernelsUpdateStateVars(std::vector* kernels, + const spatialdata::geocoords::CoordSys* coordsys) const; + + /** Update kernel constants. + * + * @param[inout] kernelConstants Array of constants used in integration kernels. + * @param[in] dt Current time step. + */ + virtual + void updateKernelConstants(pylith::real_array* kernelConstants, + const PylithReal dt) const; + + }; + + // class SourceTimeFunctionMomentTensorForce + + } // sources +} // pylith + +// End of file diff --git a/modulesrc/sources/SquareWavelet.i b/modulesrc/sources/SquareWavelet.i new file mode 100644 index 0000000000..5afa1dddf6 --- /dev/null +++ b/modulesrc/sources/SquareWavelet.i @@ -0,0 +1,67 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file modulesrc/sources/SquareWavelet.i + * + * Python interface to C++ SquareWavelet. + */ + +namespace pylith { + namespace sources { + class SquareWavelet : public pylith::sources::SourceTimeFunctionMomentTensorForce { + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + SquareWavelet(void); + + /// Destructor. + ~SquareWavelet(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void); + + /** Add source time function subfields to auxiliary field. + * + * @param[inout] auxiliaryField Auxiliary field. + */ + void addAuxiliarySubfields(void); + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return residual kernel for g1v + . + */ + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const; + + }; + + // class SquareWavelet + + } // sources +} // pylith + +// End of file diff --git a/modulesrc/sources/TimeHistoryWavelet.i b/modulesrc/sources/TimeHistoryWavelet.i new file mode 100644 index 0000000000..31cd1c5851 --- /dev/null +++ b/modulesrc/sources/TimeHistoryWavelet.i @@ -0,0 +1,101 @@ +// -*- C++ -*- +// +// ---------------------------------------------------------------------- +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University at Buffalo +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2021 University of California, Davis +// +// See LICENSE.md for license information. +// +// ---------------------------------------------------------------------- +// + +/** @file modulesrc/sources/TimeHistoryWavelet.i + * + * Python interface to C++ TimeHistoryWavelet. + */ + +namespace pylith { + namespace sources { + class TimeHistoryWavelet: public pylith::sources::SourceTimeFunctionMomentTensorForce { + // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////////// +public: + + /// Default constructor. + TimeHistoryWavelet(void); + + /// Destructor. + ~TimeHistoryWavelet(void); + + /// Deallocate PETSc and local data structures. + void deallocate(void); + + /** Set time history database. + * + * @param[in] db Time history database. + */ + void setTimeHistoryDB(spatialdata::spatialdb::TimeHistory* th); + + /** Get time history database. + * + * @preturns Time history database. + */ + const spatialdata::spatialdb::TimeHistory* getTimeHistoryDB(void); + + /** Use time history term in time history expression. + * + * @param[in] value True if using time history term in expression. + */ + void useTimeHistory(const bool value); + + /** Get flag associated with using time history term in time history expression. + * + * @returns True if using time history term in expression, false otherwise. + */ + bool useTimeHistory(void) const; + + /** Get auxiliary factory associated with physics. + * + * @return Auxiliary factory for physics object. + */ + pylith::sources::AuxiliaryFactoryMomentTensorForce* getAuxiliaryFactory(void); + + /** Add source time function subfields to auxiliary field. + * + * @param[inout] auxiliaryField Auxiliary field. + */ + void addAuxiliarySubfields(void); + + /** Get g1v kernel for residual, G(t,s). + * + * @param[in] coordsys Coordinate system. + * + * @return residual kernel for g1v + * . + */ + PetscPointFunc getKernelg1v_explicit(const spatialdata::geocoords::CoordSys* coordsys) const; + + /** Update auxiliary field for current time. + * + * @param[inout] auxiliaryField Auxiliary field to update. + * @param[in] t Current time. + * @param[in] timeScale Time scale for nondimensionalization. + */ + void updateAuxiliaryField(pylith::topology::Field* auxiliaryField, + const PylithReal t, + const PylithReal timeScale); + + }; + + // class TimeHistoryWavelet + + } // sources +} // pylith + +// End of file diff --git a/modulesrc/sources/sources.i b/modulesrc/sources/sources.i new file mode 100644 index 0000000000..dee6a1c37a --- /dev/null +++ b/modulesrc/sources/sources.i @@ -0,0 +1,64 @@ +// ====================================================================== +// +// Brad T. Aagaard, U.S. Geological Survey +// Charles A. Williams, GNS Science +// Matthew G. Knepley, University of Chicago +// +// This code was developed as part of the Computational Infrastructure +// for Geodynamics (http://geodynamics.org). +// +// Copyright (c) 2010-2017 University of California, Davis +// +// See COPYING for license information. +// +// ====================================================================== +// +// SWIG interface +%module sources + +// Header files for module C++ code +%{ +#include "pylith/sources/Source.hh" +#include "pylith/sources/MomentTensorForce.hh" +#include "pylith/sources/SquareWavelet.hh" +#include "pylith/sources/RickerWavelet.hh" +#include "pylith/sources/GaussianWavelet.hh" +#include "pylith/sources/SourceTimeFunctionMomentTensorForce.hh" +#include "pylith/sources/TimeHistoryWavelet.hh" +#include "pylith/utils/arrayfwd.hh" +%} + +%include "exception.i" +%exception { + try { + $action + } catch (const std::exception& err) { + SWIG_exception(SWIG_RuntimeError, err.what()); + } // try/catch + } // exception + +%include "typemaps.i" +%include "../include/scalartypemaps.i" +%include "../include/chararray.i" + +// Numpy interface stuff +%{ +#define SWIG_FILE_WITH_INIT +%} +%include "../include/numpy.i" +%init %{ +import_array(); +%} + +// Interfaces +%include "../utils/PyreComponent.i" +%include "../problems/Physics.i" +%include "Source.i" +%include "MomentTensorForce.i" +%include "SourceTimeFunctionMomentTensorForce.i" +%include "SquareWavelet.i" +%include "RickerWavelet.i" +%include "GaussianWavelet.i" +%include "TimeHistoryWavelet.i" + +// End of file diff --git a/portinfo b/portinfo new file mode 100644 index 0000000000..801c94f77d --- /dev/null +++ b/portinfo @@ -0,0 +1,124 @@ +/* portinfo. Generated from portinfo.in by configure. */ +/* portinfo.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* define if the compiler supports basic C++14 syntax */ +#define HAVE_CXX14 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `hdf5' library (-lhdf5). */ +#define HAVE_LIBHDF5 1 + +/* Define to 1 if you have the `proj' library (-lproj). */ +#define HAVE_LIBPROJ 1 + +/* Defined if you have NETCDF4 support */ +#define HAVE_NETCDF4 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Define NETCDF4 version */ +#define NETCDF4_VERSION "4.9.3" + +/* Name of package */ +#define PACKAGE "pylith" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "https://geodynamics.org/resources/pylith" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "PyLith" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "PyLith 5.0.0dev" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "pylith" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "5.0.0dev" + +/* Define PyLith doi */ +#define PYLITH_DOI "10.5281/zenodo.14635926" + +/* Define GIT branch for package source. */ +#define PYLITH_GIT_BRANCH "point_source_merge" + +/* Define date of GIT commit for package source. */ +#define PYLITH_GIT_DATE "2026-01-21 00:51:59 +0000" + +/* Define GIT hash for package source. */ +#define PYLITH_GIT_HASH "b9330e90fe77d0eb38bb26366e587a3053b73286" + +/* Define git revision commit for package source. */ +#define PYLITH_GIT_REVISION "v4.2.0-222-gb9330e90f" + +/* Set to 0 if source is from GIT, 1 otherwise. */ +#define PYLITH_RELEASE_VERSION 0 + +/* Define PyLith version */ +#define PYLITH_VERSION "5.0.0dev" + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "5.0.0dev" + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define __FUNCTION_NAME__ to __func__. */ +#define __FUNCTION_NAME__ __PRETTY_FUNCTION__ diff --git a/pylith/Makefile.am b/pylith/Makefile.am index 9ed0b30bc9..dcb8525617 100644 --- a/pylith/Makefile.am +++ b/pylith/Makefile.am @@ -139,6 +139,16 @@ EXTRA_DIST = \ scales/QuasistaticPoroelasticity.py \ scales/QuasistaticElasticity.py \ scales/__init__.py \ + sources/SourceTimeFunctionMomentTensorForce.py \ + sources/Source.py \ + sources/SquareWavelet.py \ + sources/RickerWavelet.py \ + sources/MomentTensorForce.py \ + sources/GaussianWavelet.py \ + sources/AuxSubfieldsSourceTime.py \ + sources/AuxSubfieldsMomentTensorForce.py \ + sources/TimeHistoryWavelet.py \ + sources/__init__.py \ testing/FullTestApp.py \ testing/SolutionPoints.py \ testing/TestCases.py \ diff --git a/pylith/meshio/MeshIOPetsc.py b/pylith/meshio/MeshIOPetsc.py index 02b70239e6..674c50a533 100644 --- a/pylith/meshio/MeshIOPetsc.py +++ b/pylith/meshio/MeshIOPetsc.py @@ -5,7 +5,7 @@ # Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. # All rights reserved. # -# See https://mit-license.org/ and LICENSE.md and for license information. +# See https://mit-license.org/ and LICENSE.md and for license information. # ================================================================================================= import pathlib @@ -57,7 +57,7 @@ def __init__(self, mode=MeshIOObj.READ, name="meshiopetsc"): def preinitialize(self): """Do minimal initialization.""" MeshIOObj.preinitialize(self) - ModuleMeshIOPetsc.setFilename(self, self.filename) + if len(self.filename) > 0: ModuleMeshIOPetsc.setFilename(self, self.filename) ModuleMeshIOPetsc.setPrefix(self, self.prefix) ModuleMeshIOPetsc.setGmshMarkRecursive(self, self.gmshMarkRecursive) @@ -72,7 +72,7 @@ def _createModuleObj(self): ModuleMeshIOPetsc.__init__(self) def _validate(self, context): - if 0 == len(self.filename) and self.mode == self.READ and not pathlib.Path(self.filename).is_file(): + if 0 < len(self.filename) and self.mode == self.READ and not pathlib.Path(self.filename).is_file(): context.error(IOError(f"Input mesh '{self.filename}' not found.")) # FACTORIES //////////////////////////////////////////////////////////// diff --git a/pylith/meshio/Xdmf.py b/pylith/meshio/Xdmf.py index 14703b2b98..d69b1941b1 100644 --- a/pylith/meshio/Xdmf.py +++ b/pylith/meshio/Xdmf.py @@ -5,7 +5,7 @@ # Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. # All rights reserved. # -# See https://mit-license.org/ and LICENSE.md and for license information. +# See https://mit-license.org/ and LICENSE.md and for license information. # ================================================================================================= @@ -150,7 +150,7 @@ def _getXdmfVectorFieldType(self, vectorFieldString): """Get Xdmf vector field type. """ import numpy - + if type(vectorFieldString) == str: vectorFieldTypeName = vectorFieldString.lower() elif type(vectorFieldString) == bytes: @@ -449,8 +449,12 @@ def _writeGridField(self, field, iTime): raise ValueError( "Unexpected shape for dataset '%s'." % field.name) else: - assert(3 == len(field.data.shape)) - numTimeSteps, numPoints, numComponents = field.data.shape + if 2 == len(field.data.shape): + numPoints, numComponents = field.data.shape + numTimeSteps = 1 + else: + assert(3 == len(field.data.shape)) + numTimeSteps, numPoints, numComponents = field.data.shape if 2 == self._getSpaceDim() and field.vectorFieldType == "Vector": diff --git a/pylith/problems/Problem.py b/pylith/problems/Problem.py index e63213fbf1..cc875cb813 100644 --- a/pylith/problems/Problem.py +++ b/pylith/problems/Problem.py @@ -39,6 +39,15 @@ def faultFactory(name): return facility(name, family="fault", factory=FaultCohesiveKin) +def sourceFactory(name): + """Factory for source items. + """ + # from pythia.pyre.inventory import facility + # from pylith.sources.WellboreSource import WellboreSource + # return facility(name, family="source", factory=WellboreSource) + from pythia.pyre.inventory import facility + from pylith.sources.MomentTensorForce import MomentTensorForce + return facility(name, family="source", factory=MomentTensorForce) def observerFactory(name): """Factory for output items.""" @@ -121,6 +130,9 @@ class Problem(PetscComponent, ModuleProblem): "Interior surfaces with constraints or constitutive models." ) + sources = pythia.pyre.inventory.facilityArray("sources", itemFactory=sourceFactory, factory=EmptyBin) + sources.meta['tip'] = "Point sources." + from pylith.problems.SingleObserver import SingleSolnObserver observers = pythia.pyre.inventory.facilityArray( @@ -191,6 +203,11 @@ def preinitialize(self, mesh): interface.preinitialize(self) ModuleProblem.setInterfaces(self, self.interfaces.components()) + # Preinitialize Sources + for source in self.sources.components(): + source.preinitialize(self) + ModuleProblem.setSources(self, self.sources.components()) + # Preinitialize observers. for observer in self.observers.components(): observer.preinitialize(self) diff --git a/pylith/sources/AuxSubfieldsMomentTensorForce.py b/pylith/sources/AuxSubfieldsMomentTensorForce.py new file mode 100644 index 0000000000..ee37d37836 --- /dev/null +++ b/pylith/sources/AuxSubfieldsMomentTensorForce.py @@ -0,0 +1,64 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University of Chicago +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2016 University of California, Davis +# +# See COPYING for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/AuxSubfieldsMomentTensorForce.py +# +# @brief Python container for momenttensorforce equation subfields. + +from pylith.utils.PetscComponent import PetscComponent + + +class AuxSubfieldsMomentTensorForce(PetscComponent): + """Python container for momenttensorforce equation subfields. + + FACTORY: auxiliary_subfields + """ + + import pythia.pyre.inventory + + from pylith.topology.Subfield import Subfield + + momentTensor = pythia.pyre.inventory.facility( + "moment_tensor", family="auxiliary_subfield", factory=Subfield) + momentTensor.meta['tip'] = "Moment tensor subfield." + + timeDelay = pythia.pyre.inventory.facility( + "time_delay", family="auxiliary_subfield", factory=Subfield) + timeDelay.meta['tip'] = "time delay subfield." + + # PUBLIC METHODS ///////////////////////////////////////////////////// + + def __init__(self, name="auxsubfieldsmomenttensorforce"): + """Constructor. + """ + PetscComponent.__init__(self, name, facility="auxiliary_subfields") + return + + # PRIVATE METHODS //////////////////////////////////////////////////// + + def _configure(self): + PetscComponent._configure(self) + return + + +# FACTORIES //////////////////////////////////////////////////////////// + +def auxiliary_subfields(): + """Factory associated with AuxSubfieldsMomentTensorForce. + """ + return AuxSubfieldsMomentTensorForce() + + +# End of file diff --git a/pylith/sources/AuxSubfieldsSourceTime.py b/pylith/sources/AuxSubfieldsSourceTime.py new file mode 100644 index 0000000000..1132158623 --- /dev/null +++ b/pylith/sources/AuxSubfieldsSourceTime.py @@ -0,0 +1,60 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University of Chicago +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2016 University of California, Davis +# +# See COPYING for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/AuxSubfieldsSourceTime.py +# +# @brief Python container for SourceTime equation subfields. + +from pylith.utils.PetscComponent import PetscComponent + + +class AuxSubfieldsSourceTime(PetscComponent): + """Python container for SourceTime equation subfields. + + FACTORY: auxiliary_subfields + """ + + import pythia.pyre.inventory + + from pylith.topology.Subfield import Subfield + + CenterFrequency = pythia.pyre.inventory.facility( + "center_frequency", family="auxiliary_subfield", factory=Subfield) + CenterFrequency.meta['tip'] = "center frequency subfield." + + # PUBLIC METHODS ///////////////////////////////////////////////////// + + def __init__(self, name="auxsubfieldssourcetime"): + """Constructor. + """ + PetscComponent.__init__(self, name, facility="auxiliary_subfields") + return + + # PRIVATE METHODS //////////////////////////////////////////////////// + + def _configure(self): + PetscComponent._configure(self) + return + + +# FACTORIES //////////////////////////////////////////////////////////// + +def auxiliary_subfields(): + """Factory associated with AuxSubfieldsSourceTime. + """ + return AuxSubfieldsSourceTime() + + +# End of file diff --git a/pylith/sources/GaussianWavelet.py b/pylith/sources/GaussianWavelet.py new file mode 100644 index 0000000000..dffd096b14 --- /dev/null +++ b/pylith/sources/GaussianWavelet.py @@ -0,0 +1,68 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University at Buffalo +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2021 University of California, Davis +# +# See LICENSE.md for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/GaussianWavelet.py +# +# @brief Python source time functiof for a gaussian wavelet. +# +# Factory: momenttensorforce_sourcetimefunction + +from .SourceTimeFunctionMomentTensorForce import SourceTimeFunctionMomentTensorForce +from .sources import GaussianWavelet as ModuleGaussianWavelet + + +class GaussianWavelet(SourceTimeFunctionMomentTensorForce, ModuleGaussianWavelet): + """Python source time function for ricker source. + + FACTORY: momenttensorforce_sourcetimefunction + """ + + import pythia.pyre.inventory + + # PUBLIC METHODS ///////////////////////////////////////////////////// + + def __init__(self, name="gaussianwavelet"): + """Constructor. + """ + SourceTimeFunctionMomentTensorForce.__init__(self, name) + return + + def _defaults(self): + from .AuxSubfieldsSourceTime import AuxSubfieldsSourceTime + self.auxiliarySubfields = AuxSubfieldsSourceTime("auxiliary_subfields") + + def preinitialize(self, problem): + SourceTimeFunctionMomentTensorForce.preinitialize(self, problem) + + + return + + # PRIVATE METHODS //////////////////////////////////////////////////// + + def _createModuleObj(self): + """Call constructor for module object for access to C++ object. + """ + ModuleGaussianWavelet.__init__(self) + + +# FACTORIES //////////////////////////////////////////////////////////// + +def momenttensorforce_sourcetimefunction(): + """Factory associated with GaussianWavelet. + """ + return GaussianWavelet() + + +# End of file diff --git a/pylith/sources/MomentTensorForce.py b/pylith/sources/MomentTensorForce.py new file mode 100644 index 0000000000..3a6b5015cb --- /dev/null +++ b/pylith/sources/MomentTensorForce.py @@ -0,0 +1,80 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University of Chicago +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2016 University of California, Davis +# +# See COPYING for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/MomentTensorForce.py +# +# @brief Python object for solving the momenttensorforce equation. +# +# Factory: source + +from pylith.sources.TimeHistoryWavelet import TimeHistoryWavelet +from .Source import Source +from .sources import MomentTensorForce as ModuleMomentTensorForce + + +class MomentTensorForce(Source, ModuleMomentTensorForce): + """Python source property manager. + + FACTORY: source + """ + + import pythia.pyre.inventory + + source_time_function = pythia.pyre.inventory.facility( + "source_time_function", family="momenttensorforce_sourcetimefunction", factory=TimeHistoryWavelet) + source_time_function.meta['tip'] = "Source time function for moment tensor force." + + # PUBLIC METHODS ///////////////////////////////////////////////////// + + def __init__(self, name="momenttensorforce"): + """Constructor. + """ + Source.__init__(self, name) + return + + def _defaults(self): + from .AuxSubfieldsMomentTensorForce import AuxSubfieldsMomentTensorForce + self.auxiliarySubfields = AuxSubfieldsMomentTensorForce( + "auxiliary_subfields") + + def preinitialize(self, problem): + """Setup source. + """ + self.source_time_function.preinitialize(problem) + Source.preinitialize(self, problem) + + self.source_time_function.addAuxiliarySubfields(self, problem) + + return + + def _createModuleObj(self): + """Create handle to C++ MomentTensorForce. + """ + ModuleMomentTensorForce.__init__(self) + # Material sets auxiliary db in source_time_function. + ModuleMomentTensorForce.setSourceTimeFunction( + self, self.source_time_function) + return + + +# Factories + +def source(): + """Factory associated with MomentTensorForce. + """ + return MomentTensorForce() + + +# End of file diff --git a/pylith/sources/RickerWavelet.py b/pylith/sources/RickerWavelet.py new file mode 100644 index 0000000000..ab21245dd5 --- /dev/null +++ b/pylith/sources/RickerWavelet.py @@ -0,0 +1,67 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University at Buffalo +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2021 University of California, Davis +# +# See LICENSE.md for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/RickerWavelet.py +# +# @brief Python source time functiof for a ricker wavelet. +# +# Factory: pointforce_sourcetimefunction + +from .SourceTimeFunctionMomentTensorForce import SourceTimeFunctionMomentTensorForce +from .sources import RickerWavelet as ModuleRickerWavelet + + +class RickerWavelet(SourceTimeFunctionMomentTensorForce, ModuleRickerWavelet): + """Python source time function for ricker source. + + FACTORY: pointforce_sourcetimefunction + """ + + import pythia.pyre.inventory + + # PUBLIC METHODS ///////////////////////////////////////////////////// + + def __init__(self, name="rickerwavelet"): + """Constructor. + """ + SourceTimeFunctionMomentTensorForce.__init__(self, name) + return + + def _defaults(self): + from .AuxSubfieldsSourceTime import AuxSubfieldsSourceTime + self.auxiliarySubfields = AuxSubfieldsSourceTime("auxiliary_subfields") + + def preinitialize(self, problem): + SourceTimeFunctionMomentTensorForce.preinitialize(self, problem) + + return + + # PRIVATE METHODS //////////////////////////////////////////////////// + + def _createModuleObj(self): + """Call constructor for module object for access to C++ object. + """ + ModuleRickerWavelet.__init__(self) + + +# FACTORIES //////////////////////////////////////////////////////////// + +def momenttensorforce_sourcetimefunction(): + """Factory associated with RickerWavelet. + """ + return RickerWavelet() + + +# End of file diff --git a/pylith/sources/Source.py b/pylith/sources/Source.py new file mode 100644 index 0000000000..9c29170e7a --- /dev/null +++ b/pylith/sources/Source.py @@ -0,0 +1,94 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University of Chicago +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2016 University of California, Davis +# +# See COPYING for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/Source.py +# +# @brief Python abstract base class for managing input and out put +# sources not necessarily pertaining to domain boundaries +# +# Factory: source + +from pylith.problems.Physics import Physics +from .sources import Source as ModuleSource + + +def validateDescription(value): + """Validate description. + """ + if 0 == len(value): + raise ValueError("Description for material not specified.") + return value + + +class Source(Physics, ModuleSource): + """Python source property manager. + + FACTORY: source + """ + + import pythia.pyre.inventory + + field = pythia.pyre.inventory.str("field", default="displacement") + field.meta['tip'] = "Solution subfield associated with boundary condition." + + description = pythia.pyre.inventory.str( + "description", default="", validator=validateDescription) + description.meta['tip'] = "Descriptive label for material." + + # labelName = pythia.pyre.inventory.str("label", default="source-id", validator=pythia.pyre.inventory.choice(["source-id"])) + labelName = pythia.pyre.inventory.str("label", default="source-id") + labelName.meta['tip'] = "Name of label for source. Currently only 'source-id' is allowed." + + labelValue = pythia.pyre.inventory.int("label_value", default=1) + labelValue.meta['tip'] = "Value of label identifying source." + + from pylith.meshio.PointsList import PointsList + reader = pythia.pyre.inventory.facility( + "reader", factory=PointsList, family="points_list") + reader.meta['tip'] = "Reader for points list." + + def __init__(self, name="source"): + """Constructor. + """ + Physics.__init__(self, name) + return + + def preinitialize(self, problem): + """Setup source. + """ + Physics.preinitialize(self, problem) + ModuleSource.setSubfieldName(self, self.field) + ModuleSource.setDescription(self, self.description) + ModuleSource.setLabelName(self, self.labelName) + ModuleSource.setLabelValue(self, self.labelValue) + + sourceNames, sourceCoords = self.reader.read() + + # Convert to mesh coordinate system + from spatialdata.geocoords.Converter import convert + convert(sourceCoords, problem.mesh().getCoordSys(), self.reader.coordsys) + + # Nondimensionalize + if hasattr(problem.normalizer, 'lengthScale'): + sourceCoords /= problem.normalizer.lengthScale.value + else: + sourceCoords /= (problem.normalizer.shearWaveSpeed.value * + problem.normalizer.wavePeriod.value) + + ModuleSource.setPoints(self, sourceCoords, sourceNames) + return + + +# End of file diff --git a/pylith/sources/SourceTimeFunctionMomentTensorForce.py b/pylith/sources/SourceTimeFunctionMomentTensorForce.py new file mode 100644 index 0000000000..6b9054256c --- /dev/null +++ b/pylith/sources/SourceTimeFunctionMomentTensorForce.py @@ -0,0 +1,80 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University at Buffalo +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2021 University of California, Davis +# +# See LICENSE.md for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/SourceTimeFunctionMomentTensorForce.py +# +# @brief Python material for isotropic, linearly elastic, plane +# strain material. +# +# Factory: momenttensorforce_sourcetimefunction + +from pylith.utils.PetscComponent import PetscComponent +from .sources import SourceTimeFunctionMomentTensorForce as ModuleSourceTimeFunction + + +class SourceTimeFunctionMomentTensorForce(PetscComponent, ModuleSourceTimeFunction): + """Python object for sourcetimefunction of a momenttensor source. + + FACTORY: momenttensorforce_sourcetimefunction + """ + import pythia.pyre.inventory + + from pylith.topology.Subfield import subfieldFactory + from pylith.utils.EmptyBin import EmptyBin + + auxiliarySubfields = pythia.pyre.inventory.facilityArray( + "auxiliary_subfields", itemFactory=subfieldFactory, factory=EmptyBin) + auxiliarySubfields.meta['tip'] = "Discretization information for physical properties and state variables." + + # PUBLIC METHODS ///////////////////////////////////////////////////// + + def __init__(self, name): + """Constructor. + """ + PetscComponent.__init__( + self, name, facility="sourcetimefunctionmomenttensorforce") + return + + def preinitialize(self, problem): + from pylith.mpi.Communicator import mpi_comm_world + comm = mpi_comm_world() + if 0 == comm.rank: + self._info.log( + "Performing minimal initialization of momenttensorforce sourcetimefunction '%s'." % self.aliases[-1]) + + self._createModuleObj() + return + + def addAuxiliarySubfields(self, material, problem): + for subfield in self.auxiliarySubfields.components(): + fieldName = subfield.aliases[-1] + descriptor = subfield.getTraitDescriptor("quadrature_order") + if hasattr(descriptor.locator, "source") and descriptor.locator.source == "default": + quadOrder = problem.defaults.quadOrder + else: + quadOrder = subfield.quadOrder + material.setAuxiliarySubfieldDiscretization(fieldName, subfield.basisOrder, quadOrder, subfield.dimension, + subfield.cellBasis, subfield.feSpace, subfield.isBasisContinuous) + return + + # PRIVATE METHODS //////////////////////////////////////////////////// + + def _createModuleObj(self): + """Call constructor for module object for access to C++ object. + """ + raise NotImplementedError("Implement in derived class.") + + +# End of file diff --git a/pylith/sources/SquareWavelet.py b/pylith/sources/SquareWavelet.py new file mode 100644 index 0000000000..c8a879e97b --- /dev/null +++ b/pylith/sources/SquareWavelet.py @@ -0,0 +1,68 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University at Buffalo +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2021 University of California, Davis +# +# See LICENSE.md for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/SquareWavelet.py +# +# @brief Python source time functiof for a square wavelet. +# +# Factory: pointforce_sourcetimefunction + +from .SourceTimeFunctionMomentTensorForce import SourceTimeFunctionMomentTensorForce +from .sources import SquareWavelet as ModuleSquareWavelet + + +class SquareWavelet(SourceTimeFunctionMomentTensorForce, ModuleSquareWavelet): + """Python source time function for square source. + + FACTORY: pointforce_sourcetimefunction + """ + + import pythia.pyre.inventory + + # PUBLIC METHODS ///////////////////////////////////////////////////// + + def __init__(self, name="squarewavelet"): + """Constructor. + """ + SourceTimeFunctionMomentTensorForce.__init__(self, name) + return + + def _defaults(self): + from .AuxSubfieldsSourceTime import AuxSubfieldsSourceTime + self.auxiliarySubfields = AuxSubfieldsSourceTime("auxiliary_subfields") + + def preinitialize(self, problem): + SourceTimeFunctionMomentTensorForce.preinitialize(self, problem) + + + return + + # PRIVATE METHODS //////////////////////////////////////////////////// + + def _createModuleObj(self): + """Call constructor for module object for access to C++ object. + """ + ModuleSquareWavelet.__init__(self) + + +# FACTORIES //////////////////////////////////////////////////////////// + +def momenttensorforce_sourcetimefunction(): + """Factory associated with SquareWavelet. + """ + return SquareWavelet() + + +# End of file diff --git a/pylith/sources/TimeHistoryWavelet.py b/pylith/sources/TimeHistoryWavelet.py new file mode 100644 index 0000000000..1ec08a410b --- /dev/null +++ b/pylith/sources/TimeHistoryWavelet.py @@ -0,0 +1,98 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University at Buffalo +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2021 University of California, Davis +# +# See LICENSE.md for license information. +# +# ---------------------------------------------------------------------- +# +# @file pylith/sources/TimeHistoryWavelet.py +# +# @brief Python source time function for a user defined wavelet. +# +# Factory: pointforce_sourcetimefunction + +from .SourceTimeFunctionMomentTensorForce import SourceTimeFunctionMomentTensorForce +from .sources import TimeHistoryWavelet as ModuleTimeHistoryWavelet +from pylith.utils.NullComponent import NullComponent + + +class TimeHistoryWavelet(SourceTimeFunctionMomentTensorForce, ModuleTimeHistoryWavelet): + """Python source time function for time history source. + + FACTORY: pointforce_sourcetimefunction + """ + + import pythia.pyre.inventory + + useTimeHistory = pythia.pyre.inventory.bool("use_time_history", default=True) + useTimeHistory.meta['tip'] = "Use time history term in time-dependent expression." + + dbTimeHistory = pythia.pyre.inventory.facility( + "time_history", factory=NullComponent, family="temporal_database") + dbTimeHistory.meta['tip'] = "Time history with normalized amplitude as a function of time." + + # PUBLIC METHODS ///////////////////////////////////////////////////// + + def __init__(self, name="timehistorywavelet"): + """Constructor. + """ + SourceTimeFunctionMomentTensorForce.__init__(self, name) + return + + def _defaults(self): + from .AuxSubfieldsSourceTime import AuxSubfieldsSourceTime + self.auxiliarySubfields = AuxSubfieldsSourceTime("auxiliary_subfields") + + def preinitialize(self, problem): + """Do pre-initialization setup. + """ + from pylith.mpi.Communicator import mpi_is_root + if mpi_is_root(): + self._info.log( + "Performing minimal initialization of time-dependent Neumann boundary condition '%s'." % self.aliases[-1]) + + + SourceTimeFunctionMomentTensorForce.preinitialize(self, problem) + ModuleTimeHistoryWavelet.useTimeHistory(self, self.useTimeHistory) + if not isinstance(self.dbTimeHistory, NullComponent): + ModuleTimeHistoryWavelet.setTimeHistoryDB( + self, self.dbTimeHistory) + return + + def _validate(self, context): + if isinstance(self.inventory.dbTimeHistory, NullComponent): + trait = self.inventory.getTrait("time_history") + self._validationError(context, trait, + f"Missing time history database for time history wavelet source '{self.aliases[-1]}'.") + + def _validationError(self, context, trait, msg): + from pythia.pyre.inventory.Item import Item + error = ValueError(msg) + descriptor = self.getTraitDescriptor(trait.name) + context.error(error, items=[Item(trait, descriptor)]) + + # PRIVATE METHODS //////////////////////////////////////////////////// + + def _createModuleObj(self): + """Call constructor for module object for access to C++ object. + """ + ModuleTimeHistoryWavelet.__init__(self) + + +# FACTORIES //////////////////////////////////////////////////////////// + +def momenttensorforce_sourcetimefunction(): + """Factory associated with TimeHistoryWavelet. + """ + return TimeHistoryWavelet() + + +# End of file diff --git a/pylith/sources/__init__.py b/pylith/sources/__init__.py new file mode 100644 index 0000000000..6e69b6e03a --- /dev/null +++ b/pylith/sources/__init__.py @@ -0,0 +1,34 @@ +# ---------------------------------------------------------------------- +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University of Chicago +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2017 University of California, Davis +# +# See COPYING for license information. +# +# ---------------------------------------------------------------------- +# + +# @file pylith/sources/__init__" + +# @brief Python PyLith sources module initialization + +__all__ = [ + "Source", + "MomentTensorForce", + "AuxSubfieldsMomentTensorForce", + "SourceTimeFunctionMomentTensorForce", + "AuxSubfieldsSourceTime", + "SquareWavelet", + "RickerWavelet", + "TimeHistoryWavelet", + "GaussianWavelet" +] + + +# End of file diff --git a/tests/libtests/Makefile.am b/tests/libtests/Makefile.am index 08cc441497..3caad8b52e 100644 --- a/tests/libtests/Makefile.am +++ b/tests/libtests/Makefile.am @@ -16,7 +16,8 @@ SUBDIRS = \ materials \ meshio \ problems \ - scales \ + scales \ + sources \ topology \ testing \ utils diff --git a/tests/libtests/materials/TestMaterial.cc b/tests/libtests/materials/TestMaterial.cc index 087d0595b7..012a701f31 100644 --- a/tests/libtests/materials/TestMaterial.cc +++ b/tests/libtests/materials/TestMaterial.cc @@ -770,4 +770,766 @@ pylith::materials::TestMaterial_Data::~TestMaterial_Data(void) { } // destructor +// End of file + +#include "TestMaterial.hh" // Implementation of class methods + +#include "pylith/materials/Material.hh" // USES Material +#include "pylith/materials/Query.hh" // USES Query + +#include "pylith/topology/Mesh.hh" // USES Mesh +#include "pylith/topology/MeshOps.hh" // USES MeshOps::nondimensionalize() +#include "pylith/topology/Field.hh" // USES Field +#include "pylith/topology/Fields.hh" // USES Fields +#include "pylith/topology/VisitorMesh.hh" // USES VecVisitorMesh +#include "pylith/topology/FieldQuery.hh" // USES FieldQuery +#include "pylith/feassemble/AuxiliaryFactory.hh" // USES AuxiliaryFactory +#include "pylith/meshio/MeshIOAscii.hh" // USES MeshIOAscii +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_BEGIN/END +#include "pylith/utils/journals.hh" // pythia::journal + +#include "spatialdata/spatialdb/UserFunctionDB.hh" // USES UserFunctionDB +#include "spatialdata/geocoords/CoordSys.hh" // USES CoordSys +#include "spatialdata/spatialdb/GravityField.hh" // USES GravityField +#include "spatialdata/units/Nondimensional.hh" // USES Nondimensional + +// ---------------------------------------------------------------------- +// Setup testing data. +void +pylith::materials::TestMaterial::setUp(void) { + _mesh = new pylith::topology::Mesh();CPPUNIT_ASSERT(_mesh); + _solutionFields = NULL; +} // setUp + + +// ---------------------------------------------------------------------- +// Deallocate testing data. +void +pylith::materials::TestMaterial::tearDown(void) { + delete _solutionFields;_solutionFields = NULL; + delete _mesh;_mesh = NULL; +} // tearDown + + +// ---------------------------------------------------------------------- +// Test auxField(). +void +pylith::materials::TestMaterial::testAuxField(void) { + PYLITH_METHOD_BEGIN; + + _initializeFull(); + + Material* material = _material();CPPUNIT_ASSERT(material); + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + + const pylith::topology::Field* auxField = material->auxField();CPPUNIT_ASSERT(auxField); + for (int i = 0; i < data->numAuxSubfields; ++i) { + CPPUNIT_ASSERT(auxField->hasSubfield(data->auxSubfields[i])); + } // for + + CPPUNIT_ASSERT(!auxField->hasSubfield("abc4598245")); + + PYLITH_METHOD_END; +} // testAuxField + + +// ---------------------------------------------------------------------- +// Test auxSubfieldDiscretization(). +void +pylith::materials::TestMaterial::testAuxSubfieldDiscretization(void) { + PYLITH_METHOD_BEGIN; + + const topology::FieldBase::Discretization infoDefault = pylith::topology::Field::Discretization(1, 1, true, pylith::topology::FieldBase::POLYNOMIAL_SPACE); + const topology::FieldBase::Discretization infoA = pylith::topology::Field::Discretization(1, 2, false, pylith::topology::FieldBase::POLYNOMIAL_SPACE); + const topology::FieldBase::Discretization infoB = pylith::topology::Field::Discretization(2, 2, true, pylith::topology::FieldBase::POINT_SPACE); + + Material* material = _material();CPPUNIT_ASSERT(material); + material->auxSubfieldDiscretization("A", infoA.basisOrder, infoA.quadOrder, infoA.isBasisContinuous, infoA.feSpace); + material->auxSubfieldDiscretization("B", infoB.basisOrder, infoB.quadOrder, infoB.isBasisContinuous, infoB.feSpace); + + CPPUNIT_ASSERT(material->_auxiliaryFactory()); + { // A + const topology::FieldBase::Discretization& test = material->_auxiliaryFactory()->getSubfieldDiscretization("A"); + CPPUNIT_ASSERT_EQUAL(infoA.basisOrder, test.basisOrder); + CPPUNIT_ASSERT_EQUAL(infoA.quadOrder, test.quadOrder); + CPPUNIT_ASSERT_EQUAL(infoA.isBasisContinuous, test.isBasisContinuous); + CPPUNIT_ASSERT_EQUAL(infoA.feSpace, test.feSpace); + } // A + + { // B + const topology::FieldBase::Discretization& test = material->_auxiliaryFactory()->getSubfieldDiscretization("B"); + CPPUNIT_ASSERT_EQUAL(infoB.basisOrder, test.basisOrder); + CPPUNIT_ASSERT_EQUAL(infoB.quadOrder, test.quadOrder); + CPPUNIT_ASSERT_EQUAL(infoB.isBasisContinuous, test.isBasisContinuous); + CPPUNIT_ASSERT_EQUAL(infoB.feSpace, test.feSpace); + } // B + + { // C (default) + const topology::FieldBase::Discretization& test = material->_auxiliaryFactory()->getSubfieldDiscretization("C"); + CPPUNIT_ASSERT_EQUAL(infoDefault.basisOrder, test.basisOrder); + CPPUNIT_ASSERT_EQUAL(infoDefault.quadOrder, test.quadOrder); + CPPUNIT_ASSERT_EQUAL(infoDefault.isBasisContinuous, test.isBasisContinuous); + CPPUNIT_ASSERT_EQUAL(infoDefault.feSpace, test.feSpace); + } // C (default) + + { // default + const topology::FieldBase::Discretization& test = material->_auxiliaryFactory()->getSubfieldDiscretization("default"); + CPPUNIT_ASSERT_EQUAL(infoDefault.basisOrder, test.basisOrder); + CPPUNIT_ASSERT_EQUAL(infoDefault.quadOrder, test.quadOrder); + CPPUNIT_ASSERT_EQUAL(infoDefault.isBasisContinuous, test.isBasisContinuous); + CPPUNIT_ASSERT_EQUAL(infoDefault.feSpace, test.feSpace); + } // default + + PYLITH_METHOD_END; +} // testAuxSubfieldDiscretization + + +// ---------------------------------------------------------------------- +// Test auxFieldDB(). +void +pylith::materials::TestMaterial::testAuxFieldDB(void) { + PYLITH_METHOD_BEGIN; + + const std::string label = "test db"; + spatialdata::spatialdb::UserFunctionDB db; + db.setLabel(label.c_str()); + + Material* material = _material();CPPUNIT_ASSERT(material); + material->auxFieldDB(&db); + + CPPUNIT_ASSERT(material->_auxiliaryFactory()); + CPPUNIT_ASSERT(material->_auxiliaryFactory()->queryDB()); + CPPUNIT_ASSERT_EQUAL(label, std::string(material->_auxiliaryFactory()->queryDB()->getLabel())); + + PYLITH_METHOD_END; +} // testAuxFieldDB + + +// ---------------------------------------------------------------------- +// Test normalizer(). +void +pylith::materials::TestMaterial::testNormalizer(void) { + PYLITH_METHOD_BEGIN; + + spatialdata::units::Nondimensional normalizer; + const double scale = 5.0; + normalizer.setLengthScale(scale); + + Material* material = _material();CPPUNIT_ASSERT(material); + material->normalizer(normalizer); + CPPUNIT_ASSERT_EQUAL(scale, material->_normalizer->getLengthScale()); + + PYLITH_METHOD_END; +} // testNormalizer + + +// ---------------------------------------------------------------------- +// Test verifyConfiguration(). +void +pylith::materials::TestMaterial::testVerifyConfiguration(void) { + PYLITH_METHOD_BEGIN; + + // Call verifyConfiguration() + Material* material = _material();CPPUNIT_ASSERT(material); + CPPUNIT_ASSERT(_solutionFields); + material->verifyConfiguration(_solutionFields->get("solution")); + + // Nothing to test. + + PYLITH_METHOD_END; +} // testVerifyConfiguration + + +// ---------------------------------------------------------------------- +// Test dimension(), id(), and getLabel(). +void +pylith::materials::TestMaterial::testAccessors(void) { + PYLITH_METHOD_BEGIN; + + Material* material = _material();CPPUNIT_ASSERT(material); + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Test of Material::dimension() failed.", data->dimension, material->dimension()); + + const int matId = 1234; + material->id(matId); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Test of Material::id() failed.", matId, material->id()); + + const std::string& matLabel = "xyz"; + material->setLabel(matLabel.c_str()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Test of Material::getLabel() failed.", matLabel, std::string(material->getLabel())); + + PYLITH_METHOD_END; +} // testAccessors + + +// ---------------------------------------------------------------------- +// Test initialize(). +void +pylith::materials::TestMaterial::testInitialize(void) { + PYLITH_METHOD_BEGIN; + + // Call initialize() + _initializeFull(); // includes setting up auxField + + Material* material = _material();CPPUNIT_ASSERT(material); + const pylith::topology::Field* auxField = material->auxField();CPPUNIT_ASSERT(auxField); + + // material->_auxiliaryField->view("AUX FIELDS"); // :DEBUGGING: + + // Check result + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + CPPUNIT_ASSERT_EQUAL(std::string("auxiliary subfields"), std::string(auxField->getLabel())); + CPPUNIT_ASSERT_EQUAL(data->dimension, auxField->getSpaceDim()); + + PylithReal norm = 0.0; + PylithReal t = 0.0; + const PetscDM dm = auxField->dmMesh();CPPUNIT_ASSERT(dm); + pylith::topology::FieldQuery query(*auxField); + query.initializeWithDefaultQueryFns(); + CPPUNIT_ASSERT(data->normalizer); + query.openDB(data->auxDB, data->normalizer->getLengthScale()); + PetscErrorCode err = DMPlexComputeL2DiffLocal(dm, t, query.functions(), (void**)query.contextPtrs(), auxField->localVector(), &norm);CPPUNIT_ASSERT(!err); + query.closeDB(data->auxDB); + const PylithReal tolerance = 1.0e-6; + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Test of auxiliary field values failed.", 0.0, norm, tolerance); + +#if 1 + // Verify solution and perturbation fields can be exactly represented by discretization. + norm = 0.0; + t = 0.0; + + pylith::topology::Field& solution = _solutionFields->get("solution"); + // solution.view("SOLUTION"); // :DEBUG: + const PetscDM dmSoln = solution.dmMesh();CPPUNIT_ASSERT(dmSoln); + pylith::topology::FieldQuery solnQuery(solution); + solnQuery.initializeWithDefaultQueryFns(); + CPPUNIT_ASSERT(data->normalizer); + solnQuery.openDB(data->solnDB, data->normalizer->getLengthScale()); + err = DMPlexComputeL2DiffLocal(dmSoln, t, solnQuery.functions(), (void**)solnQuery.contextPtrs(), solution.localVector(), &norm);CPPUNIT_ASSERT(!err); + solnQuery.closeDB(data->solnDB); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Discretized solution field failed representation test.", 0.0, norm, tolerance); + + pylith::topology::Field& perturbation = _solutionFields->get("perturbation"); + // perturbation.view("PERTURBATION"); // :DEBUG: + const PetscDM dmPerturb = perturbation.dmMesh();CPPUNIT_ASSERT(dmPerturb); + pylith::topology::FieldQuery perturbQuery(perturbation); + perturbQuery.initializeWithDefaultQueryFns(); + CPPUNIT_ASSERT(data->normalizer); + perturbQuery.openDB(data->perturbDB, data->normalizer->getLengthScale()); + err = DMPlexComputeL2DiffLocal(dmPerturb, t, perturbQuery.functions(), (void**)perturbQuery.contextPtrs(), perturbation.localVector(), &norm);CPPUNIT_ASSERT(!err); + perturbQuery.closeDB(data->perturbDB); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Discretized perturbation field failed representation test.", 0.0, norm, tolerance); +#endif + + PYLITH_METHOD_END; +} // testInitialize + + +// ---------------------------------------------------------------------- +// Test computeResidual(). +void +pylith::materials::TestMaterial::testComputeResidual(void) { + PYLITH_METHOD_BEGIN; + + // Call initialize() + _initializeFull(); // includes setting up auxField + + CPPUNIT_ASSERT(_mesh); + CPPUNIT_ASSERT(_solutionFields); + pylith::topology::Field& solution = _solutionFields->get("solution"); + pylith::topology::Field& solutionDot = _solutionFields->get("solution_dot"); + + pylith::topology::Field residualRHS(*_mesh); + residualRHS.cloneSection(solution); + residualRHS.setLabel("residual RHS"); + residualRHS.createDiscretization(); + residualRHS.allocate(); + + pylith::topology::Field residualLHS(*_mesh); + residualLHS.cloneSection(solution); + residualLHS.setLabel("residual LHS"); + residualLHS.createDiscretization(); + residualLHS.allocate(); + + Material* material = _material();CPPUNIT_ASSERT(material); + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + +#if 0 // :DEBUG: + PetscOptionsSetValue(NULL, "-dm_plex_print_fem", "2"); // :DEBUG: + DMSetFromOptions(residualRHS.dmMesh()); // :DEBUG: +#endif // :DEBUG: + + const PylithReal t = data->t; + const PylithReal dt = data->dt; + material->computeRHSResidual(&residualRHS, t, dt, solution); + material->computeLHSResidual(&residualLHS, t, dt, solution, solutionDot); + + // We don't use Dirichlet BC, so we must manually zero out the residual values for constrained DOF. + _zeroBoundary(&residualRHS); + _zeroBoundary(&residualLHS); + +#if 0 // :DEBUG: + solution.view("SOLUTION"); // :DEBUG: + solutionDot.view("SOLUTION_DOT"); // :DEBUG: + residualRHS.view("RESIDUAL RHS"); // :DEBUG: + residualLHS.view("RESIDUAL LHS"); // :DEBUG: +#endif // :DEBUG: + + PetscErrorCode err; + PetscVec residualVec = NULL; + err = VecDuplicate(residualRHS.localVector(), &residualVec);CPPUNIT_ASSERT(!err); + err = VecWAXPY(residualVec, -1.0, residualRHS.localVector(), residualLHS.localVector());CPPUNIT_ASSERT(!err); + + PylithReal norm = 0.0; + PylithReal normRHS = 0.0; + PylithReal normLHS = 0.0; + err = VecNorm(residualRHS.localVector(), NORM_2, &normRHS);CPPUNIT_ASSERT(!err); + err = VecNorm(residualLHS.localVector(), NORM_2, &normLHS);CPPUNIT_ASSERT(!err); + err = VecNorm(residualVec, NORM_2, &norm);CPPUNIT_ASSERT(!err); + err = VecDestroy(&residualVec);CPPUNIT_ASSERT(!err); + const PylithReal tolerance = 1.0e-6; + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Test of F(s) - G(s) == 0 failed.", 0.0, norm, tolerance); + // Avoid trivial satisfaction of norm with zero values. + CPPUNIT_ASSERT_MESSAGE("RHS and LHS residuals are both exactly zero, which is suspicious.", normRHS > 0.0 || normLHS > 0.0); + + PYLITH_METHOD_END; +} // testComputeResidual + + +// ---------------------------------------------------------------------- +// Test computeJacobian(). +void +pylith::materials::TestMaterial::testComputeJacobian(void) { + PYLITH_METHOD_BEGIN; + + // Create linear problem (MMS) with two trial solutions, s and p. + // + // Check that Jg(s)*(p - s) = G(p) - G(s). + + // Call initialize() + _initializeFull(); + + CPPUNIT_ASSERT(_mesh); + CPPUNIT_ASSERT(_solutionFields); + pylith::topology::Field& solution = _solutionFields->get("solution"); + pylith::topology::Field& perturbation = _solutionFields->get("perturbation"); + + Material* material = _material();CPPUNIT_ASSERT(material); + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + + pylith::topology::Field residual1(*_mesh); + residual1.cloneSection(solution); + residual1.setLabel("residual1"); + residual1.createDiscretization(); + residual1.allocate(); + + pylith::topology::Field residual2(*_mesh); + residual2.cloneSection(perturbation); + residual2.setLabel("residual2"); + residual2.createDiscretization(); + residual2.allocate(); + +#if 0 // :DEBUG: + PetscOptionsSetValue(NULL, "-dm_plex_print_fem", "3"); // :DEBUG: + DMSetFromOptions(_solution1->dmMesh()); // :DEBUG: +#endif // :DEBUG: + + const PylithReal t = data->t; + const PylithReal dt = data->dt; + material->computeLHSResidual(&residual1, t, dt, solution); + material->computeLHSResidual(&residual2, t, dt, perturbation); + + // residual1.view("RESIDUAL 1 RHS"); // :DEBUG: + // residual2.view("RESIDUAL 2 RHS"); // :DEBUG: + + // Compute Jacobian + PetscErrorCode err; + PetscMat jacobianMat = NULL; + err = DMCreateMatrix(solution.dmMesh(), &jacobianMat);CPPUNIT_ASSERT(!err); + err = MatZeroEntries(jacobianMat);CPPUNIT_ASSERT(!err); + PetscMat precondMat = jacobianMat; // Use Jacobian == preconditioner + + material->computeLHSJacobian(jacobianMat, precondMat, t, dt, solution); + CPPUNIT_ASSERT_EQUAL(false, material->needNewLHSJacobian()); + // _zeroBoundary(&residual1); + // _zeroBoundary(&residual2, jacobianMat); + err = MatAssemblyBegin(jacobianMat, MAT_FINAL_ASSEMBLY);PYLITH_CHECK_ERROR(err); + err = MatAssemblyEnd(jacobianMat, MAT_FINAL_ASSEMBLY);PYLITH_CHECK_ERROR(err); + + // Check that J(s)*(p - s) = G(p) - G(s). + + PetscVec residualVec = NULL; + err = VecDuplicate(residual1.localVector(), &residualVec);CPPUNIT_ASSERT(!err); + err = VecWAXPY(residualVec, -1.0, residual1.localVector(), residual2.localVector());CPPUNIT_ASSERT(!err); + + PetscVec solnIncrVec = NULL; + err = VecDuplicate(solution.localVector(), &solnIncrVec);CPPUNIT_ASSERT(!err); + err = VecWAXPY(solnIncrVec, -1.0, solution.localVector(), perturbation.localVector());CPPUNIT_ASSERT(!err); + + // result = Jg*(-solnIncr) + residual + PetscVec resultVec = NULL; + err = VecDuplicate(residualVec, &resultVec);CPPUNIT_ASSERT(!err); + err = VecZeroEntries(resultVec);CPPUNIT_ASSERT(!err); + err = VecScale(solnIncrVec, -1.0);CPPUNIT_ASSERT(!err); + err = MatMultAdd(jacobianMat, solnIncrVec, residualVec, resultVec);CPPUNIT_ASSERT(!err); + +#if 0 // :DEBUG: + std::cout << "SOLN INCR" << std::endl; + VecView(solnIncrVec, PETSC_VIEWER_STDOUT_SELF); + std::cout << "G2-G1" << std::endl; + VecView(residualVec, PETSC_VIEWER_STDOUT_SELF); + std::cout << "RESULT" << std::endl; + VecView(resultVec, PETSC_VIEWER_STDOUT_SELF); +#endif // :DEBUG: + + PylithReal norm = 0.0; + err = VecNorm(resultVec, NORM_2, &norm);CPPUNIT_ASSERT(!err); + err = VecDestroy(&resultVec);CPPUNIT_ASSERT(!err); + err = VecDestroy(&solnIncrVec);CPPUNIT_ASSERT(!err); + err = VecDestroy(&residualVec);CPPUNIT_ASSERT(!err); + err = MatDestroy(&jacobianMat);CPPUNIT_ASSERT(!err); + + const PylithReal tolerance = 1.0e-6; + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Check of Jg(s)*(p-s) - (G(p) - G(s)) == 0 failed.", 0.0, norm, tolerance); + CPPUNIT_ASSERT_MESSAGE("Norm of resulting vector is exactly zero, which is suspicious.", norm > 0.0); + + PYLITH_METHOD_END; +} // testComputeJacobian + + +// ---------------------------------------------------------------------- +// Test computeLHSJacobianImplicit(). +void +pylith::materials::TestMaterial::testComputeLHSJacobianImplicit(void) { + PYLITH_METHOD_BEGIN; + + Material* material = _material();CPPUNIT_ASSERT(material); + const TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + if (data->isExplicit) { + PYLITH_METHOD_END; + } // if + + // Create linear problem (MMS) with two trial solutions, s,s_dor and p,p_dot. + // + // Check that Jf(s,s_dot)*(p - s) = F(p,p_dot) - F(s,s_dot). + + // Call initialize() + _initializeFull(); // includes setting up auxField + + CPPUNIT_ASSERT(_mesh); + CPPUNIT_ASSERT(_solutionFields); + pylith::topology::Field& solution = _solutionFields->get("solution"); + pylith::topology::Field& solutionDot = _solutionFields->get("solution_dot"); + pylith::topology::Field& perturbation = _solutionFields->get("perturbation"); + pylith::topology::Field& perturbationDot = _solutionFields->get("perturbation_dot"); + + pylith::topology::Field residual1(*_mesh); + residual1.cloneSection(solution); + residual1.setLabel("residual1"); + residual1.createDiscretization(); + residual1.allocate(); + + pylith::topology::Field residual2(*_mesh); + residual2.cloneSection(perturbation); + residual2.setLabel("residual2"); + residual2.createDiscretization(); + residual2.allocate(); + +#if 0 // :DEBUG: + PetscOptionsSetValue(NULL, "-dm_plex_print_fem", "2"); // :DEBUG: + DMSetFromOptions(_solution1->dmMesh()); // :DEBUG: +#endif // :DEBUG: + + const PylithReal t = data->t; + const PylithReal dt = data->dt; + const PylithReal s_tshift = data->s_tshift; + material->computeLHSResidual(&residual1, t, dt, solution, solutionDot); + material->computeLHSResidual(&residual2, t, dt, perturbation, perturbationDot); + + // residual1.view("RESIDUAL 1 LHS"); // :DEBUG: + // residual2.view("RESIDUAL 2 LHS"); // :DEBUG: + + PetscErrorCode err; + + PetscVec residualVec = NULL; + err = VecDuplicate(residual1.localVector(), &residualVec);CPPUNIT_ASSERT(!err); + err = VecWAXPY(residualVec, -1.0, residual1.localVector(), residual2.localVector());CPPUNIT_ASSERT(!err); + + PetscVec solnIncrVec = NULL; + err = VecDuplicate(solution.localVector(), &solnIncrVec);CPPUNIT_ASSERT(!err); + err = VecWAXPY(solnIncrVec, -1.0, solution.localVector(), perturbation.localVector());CPPUNIT_ASSERT(!err); + + // Compute Jacobian + PetscMat jacobianMat = NULL; + err = DMCreateMatrix(solution.dmMesh(), &jacobianMat);CPPUNIT_ASSERT(!err); + err = MatZeroEntries(jacobianMat);CPPUNIT_ASSERT(!err); + PetscMat precondMat = jacobianMat; // Use Jacobian == preconditioner + + material->computeLHSJacobianImplicit(jacobianMat, precondMat, t, dt, s_tshift, solution, solutionDot); + CPPUNIT_ASSERT_EQUAL(false, material->needNewLHSJacobian()); + err = MatAssemblyBegin(jacobianMat, MAT_FINAL_ASSEMBLY);PYLITH_CHECK_ERROR(err); + err = MatAssemblyEnd(jacobianMat, MAT_FINAL_ASSEMBLY);PYLITH_CHECK_ERROR(err); + + // result = J*(-solnIncr) + residual + PetscVec resultVec = NULL; + err = VecDuplicate(residualVec, &resultVec);CPPUNIT_ASSERT(!err); + err = VecZeroEntries(resultVec);CPPUNIT_ASSERT(!err); + err = VecScale(solnIncrVec, -1.0);CPPUNIT_ASSERT(!err); + err = MatMultAdd(jacobianMat, solnIncrVec, residualVec, resultVec);CPPUNIT_ASSERT(!err); + +#if 0 // :DEBUG: + std::cout << "SOLN INCR" << std::endl; + VecView(solnIncrVec, PETSC_VIEWER_STDOUT_SELF); + std::cout << "F2-F1" << std::endl; + VecView(residualVec, PETSC_VIEWER_STDOUT_SELF); + std::cout << "RESULT" << std::endl; + VecView(resultVec, PETSC_VIEWER_STDOUT_SELF); +#endif // :DEBUG: + + PylithReal norm = 0.0, normSolnIncr = 0.0, normResidual = 0.0; + err = VecNorm(resultVec, NORM_2, &norm);CPPUNIT_ASSERT(!err); + err = VecNorm(solnIncrVec, NORM_2, &normSolnIncr);CPPUNIT_ASSERT(!err); + err = VecNorm(residualVec, NORM_2, &normResidual);CPPUNIT_ASSERT(!err); + err = VecDestroy(&resultVec);CPPUNIT_ASSERT(!err); + err = VecDestroy(&solnIncrVec);CPPUNIT_ASSERT(!err); + err = VecDestroy(&residualVec);CPPUNIT_ASSERT(!err); + err = MatDestroy(&jacobianMat);CPPUNIT_ASSERT(!err); + + const PylithReal tolerance = 1.0e-6; + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Check of Jf(s)*(p-s) - (F(p) - F(s)) == 0 failed.", 0.0, norm, tolerance); + CPPUNIT_ASSERT_MESSAGE("Norm of resulting vector is exactly zero, which is suspicious.", (0 < normResidual && 0 < norm) || (0 == normResidual && 0 == norm)); + + PYLITH_METHOD_END; +} // testComputeLHSJacobianImplicit + + +// ---------------------------------------------------------------------- +// Test computeLHSJacobianExplicit(). +void +pylith::materials::TestMaterial::testComputeLHSJacobianInverseExplicit(void) { + PYLITH_METHOD_BEGIN; + + Material* material = _material();CPPUNIT_ASSERT(material); + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + if (!data->isExplicit) { + PYLITH_METHOD_END; + } // if + + CPPUNIT_ASSERT_MESSAGE("Test not implemented.", false); // :TODO: ADD MORE HERE + + PYLITH_METHOD_END; +} // testComputeLHSJacobianInverseExplicit + + +// ---------------------------------------------------------------------- +// Test updateStateVars(). +void +pylith::materials::TestMaterial::testUpdateStateVars(void) { + PYLITH_METHOD_BEGIN; + + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + if (!data->auxUpdateDB) { + PYLITH_METHOD_END; + } // if + + // Call initialize() + _initializeFull(); // includes setting up auxField + + // We test updating the state variables in the auxiliary field by + // passing the perturbation as the "new" solution and the existing + // auxiliary field. We test whether the "updated" auxiliary field + // matches the database with the updated auxiliary field. + + Material* material = _material();CPPUNIT_ASSERT(material); + CPPUNIT_ASSERT(_solutionFields); + pylith::topology::Field& perturbation = _solutionFields->get("perturbation"); +#if 0 + material->_auxiliaryField->view("INITIAL_AUX FIELDS"); // :DEBUGGING: +#endif + material->_updateStateVars(data->t, data->dt, perturbation); + + const pylith::topology::Field* auxField = material->auxField();CPPUNIT_ASSERT(auxField); + material->_auxiliaryField->view("UPDATED_AUX FIELDS"); // :DEBUGGING: + + // Check updated auxiliary field. + PylithReal norm = 0.0; + PylithReal t = 0.0; + const PetscDM dm = auxField->dmMesh();CPPUNIT_ASSERT(dm); + pylith::topology::FieldQuery query(*auxField); + query.initializeWithDefaultQueryFns(); + CPPUNIT_ASSERT(data->normalizer); + query.openDB(data->auxUpdateDB, data->normalizer->getLengthScale()); +#if 0 // :DEBUG: + PetscOptionsSetValue(NULL, "-dm_plex_print_l2", "1"); // :DEBUG: + DMSetFromOptions(dm); // :DEBUG: +#endif + PetscErrorCode err = DMPlexComputeL2DiffLocal(dm, t, query.functions(), (void**)query.contextPtrs(), auxField->localVector(), &norm);CPPUNIT_ASSERT(!err); + query.closeDB(data->auxUpdateDB); + const PylithReal tolerance = 1.0e-6; + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Check of updated auxiliary field values failed.", 0.0, norm, tolerance); + + PYLITH_METHOD_END; +} // testUpdateStateVars + + +// ---------------------------------------------------------------------- +// Do minimal initilaization of test data. +void +pylith::materials::TestMaterial::_initializeMin(void) { + PYLITH_METHOD_BEGIN; + + Material* material = _material();CPPUNIT_ASSERT(material); + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + + pylith::meshio::MeshIOAscii iohandler; + CPPUNIT_ASSERT(data->meshFilename); + iohandler.filename(data->meshFilename); + iohandler.read(_mesh);CPPUNIT_ASSERT(_mesh); + + CPPUNIT_ASSERT_MESSAGE("Test mesh does not contain any cells.", _mesh->numCells() > 0); + CPPUNIT_ASSERT_MESSAGE("Test mesh does not contain any vertices.", _mesh->numVertices() > 0); + + // Setup coordinates. + _mesh->setCoordSys(data->cs); + CPPUNIT_ASSERT(data->normalizer); + pylith::topology::MeshOps::nondimensionalize(_mesh, *data->normalizer); + + // id and label initialized in derived class + material->normalizer(*data->normalizer); + material->gravityField(data->gravityField); + + // Setup solution fields. + delete _solutionFields;_solutionFields = new pylith::topology::Fields(*_mesh);CPPUNIT_ASSERT(_solutionFields); + _solutionFields->add("solution","solution"); + _solutionFields->add("solution_dot","solution_dot"); + _solutionFields->add("perturbation","perturbation"); + _solutionFields->add("perturbation_dot","perturbation_dot"); + this->_setupSolutionFields(); + + PYLITH_METHOD_END; +} // _initializeMin + + +// ---------------------------------------------------------------------- +// Complete initilaization of test data. +void +pylith::materials::TestMaterial::_initializeFull(void) { + PYLITH_METHOD_BEGIN; + + Material* material = _material();CPPUNIT_ASSERT(material); + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + CPPUNIT_ASSERT(_mesh); + + // Set auxiliary fields spatial database. + material->auxFieldDB(data->auxDB); + + for (int i = 0; i < data->numAuxSubfields; ++i) { + const pylith::topology::FieldBase::Discretization& info = data->auxDiscretizations[i]; + material->auxSubfieldDiscretization(data->auxSubfields[i], info.basisOrder, info.quadOrder, info.isBasisContinuous, info.feSpace); + } // for + + CPPUNIT_ASSERT(_solutionFields); + material->initialize(_solutionFields->get("solution")); + + PYLITH_METHOD_END; +} // _initializeFull + + +// ---------------------------------------------------------------------- +// Set field to zero on the boundary. +void +pylith::materials::TestMaterial::_zeroBoundary(pylith::topology::Field* field) { + PYLITH_METHOD_BEGIN; + + CPPUNIT_ASSERT(field); + TestMaterial_Data* data = _data();CPPUNIT_ASSERT(data); + CPPUNIT_ASSERT(data->boundaryLabel); + + PetscDM dmMesh = field->mesh().dmMesh();CPPUNIT_ASSERT(dmMesh); + PetscDMLabel label = NULL; + PetscIS pointIS = NULL; + const PetscInt *points; + PetscInt numPoints = 0; + PetscBool hasLabel = PETSC_FALSE; + PetscErrorCode err; + err = DMHasLabel(dmMesh, data->boundaryLabel, &hasLabel);CPPUNIT_ASSERT(!err);CPPUNIT_ASSERT(hasLabel); + err = DMGetLabel(dmMesh, data->boundaryLabel, &label);CPPUNIT_ASSERT(!err); + err = DMLabelGetStratumIS(label, 1, &pointIS);CPPUNIT_ASSERT(!err);CPPUNIT_ASSERT(pointIS); + err = ISGetLocalSize(pointIS, &numPoints);CPPUNIT_ASSERT(!err); + err = ISGetIndices(pointIS, &points);CPPUNIT_ASSERT(!err); + + pylith::topology::VecVisitorMesh fieldVisitor(*field); + PylithScalar* fieldArray = fieldVisitor.localArray();CPPUNIT_ASSERT(fieldArray); + + for (PylithInt p = 0; p < numPoints; ++p) { + const PylithInt p_bc = points[p]; + + const PylithInt off = fieldVisitor.sectionOffset(p_bc); + const PylithInt dof = fieldVisitor.sectionDof(p_bc); + for (PylithInt i = 0; i < dof; ++i) { + fieldArray[off+i] = 0.0; + } // for + } // for + + err = ISRestoreIndices(pointIS, &points);PYLITH_CHECK_ERROR(err); + err = ISDestroy(&pointIS);PYLITH_CHECK_ERROR(err); + + PYLITH_METHOD_END; +} // _zeroBoundary + + +// ---------------------------------------------------------------------- +// Constructor +pylith::materials::TestMaterial_Data::TestMaterial_Data(void) : + dimension(0), + meshFilename(0), + boundaryLabel(NULL), + cs(NULL), + gravityField(NULL), + + normalizer(new spatialdata::units::Nondimensional), + + t(0.0), + dt(0.0), + s_tshift(0.0), + perturbation(1.0e-4), + + numSolnSubfields(0), + solnDiscretizations(NULL), + solnDB(new spatialdata::spatialdb::UserFunctionDB), + perturbDB(new spatialdata::spatialdb::UserFunctionDB), + + numAuxSubfields(0), + auxSubfields(NULL), + auxDiscretizations(NULL), + auxDB(new spatialdata::spatialdb::UserFunctionDB), + auxUpdateDB(NULL), + + isExplicit(false) { // constructor + CPPUNIT_ASSERT(normalizer); + + CPPUNIT_ASSERT(solnDB); + solnDB->setLabel("solution"); + + CPPUNIT_ASSERT(perturbDB); + perturbDB->setLabel("solution+perturbation"); + + CPPUNIT_ASSERT(auxDB); + auxDB->setLabel("auxiliary field"); +} // constructor + + +// ---------------------------------------------------------------------- +// Destructor +pylith::materials::TestMaterial_Data::~TestMaterial_Data(void) { + delete cs;cs = NULL; + delete gravityField;gravityField = NULL; + delete normalizer;normalizer = NULL; + delete solnDB;solnDB = NULL; + delete auxDB;auxDB = NULL; + delete auxUpdateDB;auxUpdateDB = NULL; +} // destructor + + // End of file diff --git a/tests/libtests/sources/Makefile.am b/tests/libtests/sources/Makefile.am new file mode 100644 index 0000000000..f49710d792 --- /dev/null +++ b/tests/libtests/sources/Makefile.am @@ -0,0 +1,14 @@ +# ================================================================================================= +# This code is part of PyLith, developed through the Computational Infrastructure +# for Geodynamics (https://github.com/geodynamics/pylith). +# +# Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +# All rights reserved. +# +# See https://mit-license.org/ and LICENSE.md and for license information. +# ================================================================================================= + +# Placeholder for sources tests + + +# End of file diff --git a/tests/mmstests/Makefile.am b/tests/mmstests/Makefile.am index 27b90fa4b0..2b16c85f94 100644 --- a/tests/mmstests/Makefile.am +++ b/tests/mmstests/Makefile.am @@ -11,7 +11,8 @@ SUBDIRS = \ linearelasticity \ incompressibleelasticity \ - poroelasticity + poroelasticity \ + sources # End of file diff --git a/tests/mmstests/sources/Makefile.am b/tests/mmstests/sources/Makefile.am new file mode 100644 index 0000000000..8a93b11ddf --- /dev/null +++ b/tests/mmstests/sources/Makefile.am @@ -0,0 +1,15 @@ +# ================================================================================================= +# This code is part of PyLith, developed through the Computational Infrastructure +# for Geodynamics (https://github.com/geodynamics/pylith). +# +# Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +# All rights reserved. +# +# See https://mit-license.org/ and LICENSE.md and for license information. +# ================================================================================================= + +SUBDIRS = \ + momenttensor-2d + + +# End of file diff --git a/tests/mmstests/sources/momenttensor-2d/Makefile.am b/tests/mmstests/sources/momenttensor-2d/Makefile.am new file mode 100644 index 0000000000..da16df986d --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/Makefile.am @@ -0,0 +1,49 @@ +# ================================================================================================= +# This code is part of PyLith, developed through the Computational Infrastructure +# for Geodynamics (https://github.com/geodynamics/pylith). +# +# Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +# All rights reserved. +# +# See https://mit-license.org/ and LICENSE.md and for license information. +# ================================================================================================= + +include $(top_srcdir)/tests/check_catch2.am + +MMS_DRIVER = mmstest_sources_momenttensor2d + +TESTS = \ + run_MomentTensorSource2D.sh \ + run_MomentTensorUniformStrain2D.sh + +check_SCRIPTS = $(TESTS) + +check_PROGRAMS = $(MMS_DRIVER) + +mmstest_sources_momenttensor2d_SOURCES = \ + $(top_srcdir)/tests/src/MMSTest.cc \ + $(top_srcdir)/tests/src/driver_catch2.cc \ + TestMomentTensorSource.cc \ + TestCases.cc \ + MomentTensorSource2D.cc \ + MomentTensorUniformStrain2D.cc + +run_%.sh: + echo "#!/bin/bash" > $@ + echo "$(abs_builddir)/$(MMS_DRIVER) [$*]" >> $@ + chmod +x $@ + +dist_noinst_HEADERS = \ + TestMomentTensorSource.hh \ + MomentTensorSource2D.hh \ + MomentTensorUniformStrain2D.hh + +dist_noinst_DATA = \ + data/tri.mesh \ + data/quad.mesh + +export_datadir = $(abs_builddir) +include $(top_srcdir)/tests/data.am + + +# End of file diff --git a/tests/mmstests/sources/momenttensor-2d/MomentTensorSource2D.cc b/tests/mmstests/sources/momenttensor-2d/MomentTensorSource2D.cc new file mode 100644 index 0000000000..5c6ccfbe18 --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/MomentTensorSource2D.cc @@ -0,0 +1,431 @@ +// ================================================================================================= +// This code is part of PyLith, developed through the Computational Infrastructure +// for Geodynamics (https://github.com/geodynamics/pylith). +// +// Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +// All rights reserved. +// +// See https://mit-license.org/ and LICENSE.md and for license information. +// ================================================================================================= + +#include + +#include "MomentTensorSource2D.hh" // Implementation of test data + +#include "pylith/problems/TimeDependent.hh" // USES TimeDependent +#include "pylith/topology/Field.hh" // USES pylith::topology::Field::Discretization +#include "pylith/utils/journals.hh" // USES pythia::journal::debug_t + +#include "pylith/scales/ElasticityScales.hh" // USES ElasticityScales + +// --------------------------------------------------------------------------------------------------------------------- +namespace pylith { + class _MomentTensorSource2D; +} // pylith + +class pylith::_MomentTensorSource2D { + // Physical constants for the problem + static constexpr double LENGTH_SCALE = 1.0e+4; // 10 km + static constexpr double VELOCITY_SCALE = 3000.0; // 3 km/s (shear wave speed) + static constexpr double TIME_SCALE = LENGTH_SCALE / VELOCITY_SCALE; + static constexpr double DENSITY_SCALE = 2500.0; // kg/m^3 + static constexpr double PRESSURE_SCALE = DENSITY_SCALE * VELOCITY_SCALE * VELOCITY_SCALE; + + static constexpr double TIME_SNAPSHOT = 0.5; // Time for test evaluation + static constexpr double CENTER_FREQUENCY = 1.0; // Hz + static constexpr double TIME_DELAY = 0.5; // s + + // Density + static double density(const double x, + const double y) { + return 2500.0; + } // density + + static const char* density_units(void) { + return "kg/m**3"; + } // density_units + + // Vs + static double vs(const double x, + const double y) { + return 3000.0; + } // vs + + static const char* vs_units(void) { + return "m/s"; + } // vs_units + + // Vp + static double vp(const double x, + const double y) { + return sqrt(3.0)*vs(x,y); + } // vp + + static const char* vp_units(void) { + return "m/s"; + } // vp_units + + // Moment tensor components (in 2D: Mxx, Myy, Mxy, Myx) + // Using an isotropic source: Mxx = Myy = 1, Mxy = Myx = 0 + static double moment_xx(const double x, const double y) { + return 1.0e+15; // Newton-meters (Pa*m^3) + } + static double moment_yy(const double x, const double y) { + return 1.0e+15; + } + static double moment_xy(const double x, const double y) { + return 0.0; + } + static double moment_yx(const double x, const double y) { + return 0.0; + } + static const char* moment_units(void) { + return "Pa*m**3"; + } + + // Time delay + static double time_delay(const double x, const double y) { + return TIME_DELAY; + } + static const char* time_delay_units(void) { + return "s"; + } + + // Center frequency + static double center_frequency(const double x, const double y) { + return CENTER_FREQUENCY; + } + static const char* center_frequency_units(void) { + return "1/s"; + } + + // Solution subfields. + // For this MMS test, we use zero displacement/velocity to isolate testing of the + // moment tensor source term contribution. This verifies that: + // 1. The auxiliary fields are correctly set up + // 2. The kernel correctly computes the source contribution + // 3. The discretization converges at the expected rate + + // Displacement (zero - testing source term only) + static double disp_x(const double x, + const double y, + const double t) { + return 0.0; + } // disp_x + + static double disp_y(const double x, + const double y, + const double t) { + return 0.0; + } // disp_y + + static const char* disp_units(void) { + return "m"; + } // disp_units + + // Velocity (zero) + static double vel_x(const double x, + const double y, + const double t) { + return 0.0; + } // vel_x + + static double vel_y(const double x, + const double y, + const double t) { + return 0.0; + } // vel_y + + static const char* vel_units(void) { + return "m/s"; + } // vel_units + + // Acceleration (zero) + static double acc_x(const double x, + const double y, + const double t) { + return 0.0; + } // acc_x + + static double acc_y(const double x, + const double y, + const double t) { + return 0.0; + } // acc_y + + static const char* acc_units(void) { + return "m/s**2"; + } // acc_units + + static PetscErrorCode solnkernel_disp(PetscInt spaceDim, + PetscReal t, + const PetscReal x[], + PetscInt numComponents, + PetscScalar* s, + void* context) { + assert(2 == spaceDim); + assert(x); + assert(2 == numComponents); + assert(s); + + s[0] = disp_x(x[0], x[1], t); + s[1] = disp_y(x[0], x[1], t); + + return PETSC_SUCCESS; + } // solnkernel_disp + + static PetscErrorCode solnkernel_vel(PetscInt spaceDim, + PetscReal t, + const PetscReal x[], + PetscInt numComponents, + PetscScalar* s, + void* context) { + assert(2 == spaceDim); + assert(x); + assert(2 == numComponents); + assert(s); + + s[0] = vel_x(x[0], x[1], t); + s[1] = vel_y(x[0], x[1], t); + + return PETSC_SUCCESS; + } // solnkernel_vel + + static PetscErrorCode solnkernel_acc(PetscInt spaceDim, + PetscReal t, + const PetscReal x[], + PetscInt numComponents, + PetscScalar* s, + void* context) { + assert(2 == spaceDim); + assert(x); + assert(2 == numComponents); + assert(s); + + s[0] = acc_x(x[0], x[1], t); + s[1] = acc_y(x[0], x[1], t); + + return PETSC_SUCCESS; + } // solnkernel_acc + +public: + + static + TestMomentTensorSource_Data* createData(void) { + TestMomentTensorSource_Data* data = new TestMomentTensorSource_Data();assert(data); + + data->journalName = "MomentTensorSource2D"; + data->isJacobianLinear = true; + data->tolerance = 1.0e-6; + data->allowZeroResidual = true; // Zero solution with source gives non-zero residual + + data->meshFilename = ":UNKNOWN:"; // Set in child class. + data->boundaryLabel = "boundary"; + + // Initialize scales first before using them + pylith::scales::ElasticityScales::setDynamicElasticity(&data->scales, LENGTH_SCALE, VELOCITY_SCALE); + data->formulation = pylith::problems::Physics::DYNAMIC; + + data->t = TIME_SNAPSHOT; + data->dt = 0.05; + + // Material information + data->numAuxSubfields = 3; + static const char* _auxSubfields[3] = {"density", "shear_modulus", "bulk_modulus"}; + data->auxSubfields = _auxSubfields; + static const pylith::topology::Field::Discretization _auxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 1), // density + pylith::topology::Field::Discretization(0, 1), // shear_modulus + pylith::topology::Field::Discretization(0, 1), // bulk_modulus + }; + data->auxDiscretizations = const_cast(_auxDiscretizations); + + data->auxDB.addValue("density", density, density_units()); + data->auxDB.addValue("vp", vp, vp_units()); + data->auxDB.addValue("vs", vs, vs_units()); + data->auxDB.setCoordSys(data->cs); + + data->material.setFormulation(data->formulation); + data->material.useBodyForce(false); + data->rheology.useReferenceState(false); + + data->material.setIdentifier("elasticity"); + data->material.setName("material-id=24"); + data->material.setLabelValue(24); + + // Source information + data->numSourceAuxSubfields = 3; + static const char* _sourceAuxSubfields[3] = {"moment_tensor", "time_delay", "center_frequency"}; + data->sourceAuxSubfields = _sourceAuxSubfields; + static const pylith::topology::Field::Discretization _sourceAuxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 1), // moment_tensor + pylith::topology::Field::Discretization(0, 1), // time_delay + pylith::topology::Field::Discretization(0, 1), // center_frequency + }; + data->sourceAuxDiscretizations = const_cast(_sourceAuxDiscretizations); + + data->sourceAuxDB.addValue("moment_tensor_xx", moment_xx, moment_units()); + data->sourceAuxDB.addValue("moment_tensor_yy", moment_yy, moment_units()); + data->sourceAuxDB.addValue("moment_tensor_xy", moment_xy, moment_units()); + data->sourceAuxDB.addValue("moment_tensor_yx", moment_yx, moment_units()); + data->sourceAuxDB.addValue("time_delay", time_delay, time_delay_units()); + data->sourceAuxDB.addValue("center_frequency", center_frequency, center_frequency_units()); + data->sourceAuxDB.setCoordSys(data->cs); + + data->source.setFormulation(data->formulation); + data->source.setIdentifier("source"); + data->source.setName("moment-tensor-source"); + data->source.setLabelValue(24); + data->source.setSubfieldName("velocity"); // Apply source to velocity field for dynamic problems + + // Source point coordinates (center of domain) + data->numSourcePoints = 1; + static const PylithReal _sourcePointCoords[2] = {0.0, 0.0}; // Center of domain + data->sourcePointCoords = _sourcePointCoords; + static const char* _sourcePointNames[1] = {"source_point"}; + data->sourcePointNames = _sourcePointNames; + + // Boundary conditions + static const PylithInt constrainedDOF[2] = {0, 1}; + static const PylithInt numConstrained = 2; + pylith::bc::DirichletUserFn* bc = NULL; + data->bcs.resize(2); + bc = new pylith::bc::DirichletUserFn();assert(bc); + bc->setSubfieldName("displacement"); + bc->setLabelName("boundary"); + bc->setLabelValue(1); + bc->setConstrainedDOF(constrainedDOF, numConstrained); + bc->setUserFn(solnkernel_disp); + bc->setUserFnDot(solnkernel_vel); + data->bcs[0] = bc; + + bc = new pylith::bc::DirichletUserFn();assert(bc); + bc->setSubfieldName("velocity"); + bc->setLabelName("boundary"); + bc->setLabelValue(1); + bc->setConstrainedDOF(constrainedDOF, numConstrained); + bc->setUserFn(solnkernel_vel); + bc->setUserFnDot(solnkernel_acc); + data->bcs[1] = bc; + + static const pylith::testing::MMSTest::solution_fn _exactSolnFns[2] = { + solnkernel_disp, + solnkernel_vel, + }; + data->exactSolnFns = const_cast(_exactSolnFns); + static const pylith::testing::MMSTest::solution_fn _exactSolnDotFns[2] = { + solnkernel_vel, + solnkernel_acc, + }; + data->exactSolnDotFns = const_cast(_exactSolnDotFns); + + return data; + } // createData + +}; // _MomentTensorSource2D + +// ------------------------------------------------------------------------------------------------ +pylith::TestMomentTensorSource_Data* +pylith::MomentTensorSource2D::TriP1(void) { + TestMomentTensorSource_Data* data = pylith::_MomentTensorSource2D::createData();assert(data); + + data->meshFilename = "data/tri.mesh"; + data->useAsciiMesh = true; + + data->numSolnSubfields = 2; + static const pylith::topology::Field::Discretization _solnDiscretizations[2] = { + pylith::topology::Field::Discretization(1, 1), // disp + pylith::topology::Field::Discretization(1, 1), // vel + }; + data->solnDiscretizations = const_cast(_solnDiscretizations); + + return data; +} // TriP1 + + +// ------------------------------------------------------------------------------------------------ +pylith::TestMomentTensorSource_Data* +pylith::MomentTensorSource2D::TriP2(void) { + TestMomentTensorSource_Data* data = pylith::_MomentTensorSource2D::createData();assert(data); + + data->meshFilename = "data/tri.mesh"; + data->useAsciiMesh = true; + + static const pylith::topology::Field::Discretization _auxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 2), // density + pylith::topology::Field::Discretization(0, 2), // shear_modulus + pylith::topology::Field::Discretization(0, 2), // bulk_modulus + }; + data->auxDiscretizations = const_cast(_auxDiscretizations); + + static const pylith::topology::Field::Discretization _sourceAuxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 2), // moment_tensor + pylith::topology::Field::Discretization(0, 2), // time_delay + pylith::topology::Field::Discretization(0, 2), // center_frequency + }; + data->sourceAuxDiscretizations = const_cast(_sourceAuxDiscretizations); + + data->numSolnSubfields = 2; + static const pylith::topology::Field::Discretization _solnDiscretizations[2] = { + pylith::topology::Field::Discretization(2, 2), // disp + pylith::topology::Field::Discretization(2, 2), // vel + }; + data->solnDiscretizations = const_cast(_solnDiscretizations); + + return data; +} // TriP2 + + +// ------------------------------------------------------------------------------------------------ +pylith::TestMomentTensorSource_Data* +pylith::MomentTensorSource2D::QuadQ1(void) { + TestMomentTensorSource_Data* data = pylith::_MomentTensorSource2D::createData();assert(data); + + data->meshFilename = "data/quad.mesh"; + data->useAsciiMesh = true; + + data->numSolnSubfields = 2; + static const pylith::topology::Field::Discretization _solnDiscretizations[2] = { + pylith::topology::Field::Discretization(1, 1), // disp + pylith::topology::Field::Discretization(1, 1), // vel + }; + data->solnDiscretizations = const_cast(_solnDiscretizations); + + return data; +} // QuadQ1 + + +// ------------------------------------------------------------------------------------------------ +pylith::TestMomentTensorSource_Data* +pylith::MomentTensorSource2D::QuadQ2(void) { + TestMomentTensorSource_Data* data = pylith::_MomentTensorSource2D::createData();assert(data); + + data->meshFilename = "data/quad.mesh"; + data->useAsciiMesh = true; + + static const pylith::topology::Field::Discretization _auxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 2), // density + pylith::topology::Field::Discretization(0, 2), // shear_modulus + pylith::topology::Field::Discretization(0, 2), // bulk_modulus + }; + data->auxDiscretizations = const_cast(_auxDiscretizations); + + static const pylith::topology::Field::Discretization _sourceAuxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 2), // moment_tensor + pylith::topology::Field::Discretization(0, 2), // time_delay + pylith::topology::Field::Discretization(0, 2), // center_frequency + }; + data->sourceAuxDiscretizations = const_cast(_sourceAuxDiscretizations); + + data->numSolnSubfields = 2; + static const pylith::topology::Field::Discretization _solnDiscretizations[2] = { + pylith::topology::Field::Discretization(2, 2), // disp + pylith::topology::Field::Discretization(2, 2), // vel + }; + data->solnDiscretizations = const_cast(_solnDiscretizations); + + return data; +} // QuadQ2 + + +// End of file diff --git a/tests/mmstests/sources/momenttensor-2d/MomentTensorSource2D.hh b/tests/mmstests/sources/momenttensor-2d/MomentTensorSource2D.hh new file mode 100644 index 0000000000..6cc6e0147c --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/MomentTensorSource2D.hh @@ -0,0 +1,33 @@ +// ================================================================================================= +// This code is part of PyLith, developed through the Computational Infrastructure +// for Geodynamics (https://github.com/geodynamics/pylith). +// +// Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +// All rights reserved. +// +// See https://mit-license.org/ and LICENSE.md and for license information. +// ================================================================================================= +#pragma once + +#include "TestMomentTensorSource.hh" + +namespace pylith { + class MomentTensorSource2D; +} + +class pylith::MomentTensorSource2D { +public: + + // Data factory methods + + static TestMomentTensorSource_Data* TriP1(void); + + static TestMomentTensorSource_Data* TriP2(void); + + static TestMomentTensorSource_Data* QuadQ1(void); + + static TestMomentTensorSource_Data* QuadQ2(void); + +}; // class MomentTensorSource2D + +// End of file diff --git a/tests/mmstests/sources/momenttensor-2d/MomentTensorUniformStrain2D.cc b/tests/mmstests/sources/momenttensor-2d/MomentTensorUniformStrain2D.cc new file mode 100644 index 0000000000..9b1435c6cb --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/MomentTensorUniformStrain2D.cc @@ -0,0 +1,457 @@ +// ================================================================================================= +// This code is part of PyLith, developed through the Computational Infrastructure +// for Geodynamics (https://github.com/geodynamics/pylith). +// +// Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +// All rights reserved. +// +// See https://mit-license.org/ and LICENSE.md and for license information. +// ================================================================================================= + +#include + +#include "MomentTensorUniformStrain2D.hh" // Implementation of test data + +#include "pylith/problems/TimeDependent.hh" // USES TimeDependent +#include "pylith/topology/Field.hh" // USES pylith::topology::Field::Discretization +#include "pylith/utils/journals.hh" // USES pythia::journal::debug_t + +#include "pylith/scales/ElasticityScales.hh" // USES ElasticityScales + +// --------------------------------------------------------------------------------------------------------------------- +namespace pylith { + class _MomentTensorUniformStrain2D; +} // pylith + +/** MMS test with linear (uniform strain) solution for moment tensor source. + * + * The manufactured solution uses a linear displacement field: + * u_x(x,t) = A * x * t + * u_y(x,t) = B * y * t + * + * This gives uniform strain and can be exactly represented by linear elements. + * For linear elasticity (no body force), the residual depends only on the + * inertia and stress divergence terms. Since the strain is uniform, the + * stress divergence is zero. + * + * With the moment tensor source, the weak form residual includes an additional + * source term contribution. For MMS, we verify that the discrete residual + * matches the analytical one. + */ +class pylith::_MomentTensorUniformStrain2D { + static pylith::scales::Scales scales; + + // Physical constants + static constexpr double LENGTH_SCALE = 1.0e+4; // 10 km + static constexpr double VELOCITY_SCALE = 3000.0; // 3 km/s + static constexpr double TIME_SCALE = LENGTH_SCALE / VELOCITY_SCALE; + static constexpr double DENSITY_SCALE = 2500.0; // kg/m^3 + static constexpr double PRESSURE_SCALE = DENSITY_SCALE * VELOCITY_SCALE * VELOCITY_SCALE; + + // Solution parameters (nondimensional) + static constexpr double AMPLITUDE_X = 0.01; // Strain amplitude in x + static constexpr double AMPLITUDE_Y = 0.02; // Strain amplitude in y + static constexpr double TIME_SNAPSHOT = 0.5; // Nondimensional time + + // Source parameters + static constexpr double CENTER_FREQUENCY = 1.0; // Hz (dimensional) + static constexpr double TIME_DELAY = 0.5; // s (dimensional) + static constexpr double MOMENT_MAGNITUDE = 1.0e+15; // Pa*m^3 (dimensional) + + // Density + static double density(const double x, + const double y) { + return 2500.0; + } // density + + static const char* density_units(void) { + return "kg/m**3"; + } // density_units + + // Vs + static double vs(const double x, + const double y) { + return 3000.0; + } // vs + + static const char* vs_units(void) { + return "m/s"; + } // vs_units + + // Vp + static double vp(const double x, + const double y) { + return sqrt(3.0)*vs(x,y); + } // vp + + static const char* vp_units(void) { + return "m/s"; + } // vp_units + + // Moment tensor components (isotropic source in 2D: Mxx = Myy, Mxy = Myx = 0) + static double moment_xx(const double x, const double y) { + return MOMENT_MAGNITUDE; + } + static double moment_yy(const double x, const double y) { + return MOMENT_MAGNITUDE; + } + static double moment_xy(const double x, const double y) { + return 0.0; + } + static double moment_yx(const double x, const double y) { + return 0.0; + } + static const char* moment_units(void) { + return "Pa*m**3"; + } + + // Time delay + static double time_delay(const double x, const double y) { + return TIME_DELAY; + } + static const char* time_delay_units(void) { + return "s"; + } + + // Center frequency + static double center_frequency(const double x, const double y) { + return CENTER_FREQUENCY; + } + static const char* center_frequency_units(void) { + return "1/s"; + } + + // Solution subfields - Linear displacement field (uniform strain) + + // Displacement: u_x = A_x * x * t, u_y = A_y * y * t + static double disp_x(const double x, + const double y, + const double t) { + return AMPLITUDE_X * x * t; + } // disp_x + + static double disp_y(const double x, + const double y, + const double t) { + return AMPLITUDE_Y * y * t; + } // disp_y + + static const char* disp_units(void) { + return "m"; + } // disp_units + + // Velocity: v_x = A_x * x, v_y = A_y * y + static double vel_x(const double x, + const double y, + const double t) { + return AMPLITUDE_X * x; + } // vel_x + + static double vel_y(const double x, + const double y, + const double t) { + return AMPLITUDE_Y * y; + } // vel_y + + static const char* vel_units(void) { + return "m/s"; + } // vel_units + + // Acceleration: a_x = 0, a_y = 0 (constant velocity) + static double acc_x(const double x, + const double y, + const double t) { + return 0.0; + } // acc_x + + static double acc_y(const double x, + const double y, + const double t) { + return 0.0; + } // acc_y + + static const char* acc_units(void) { + return "m/s**2"; + } // acc_units + + static PetscErrorCode solnkernel_disp(PetscInt spaceDim, + PetscReal t, + const PetscReal x[], + PetscInt numComponents, + PetscScalar* s, + void* context) { + assert(2 == spaceDim); + assert(x); + assert(2 == numComponents); + assert(s); + + s[0] = disp_x(x[0], x[1], t); + s[1] = disp_y(x[0], x[1], t); + + return PETSC_SUCCESS; + } // solnkernel_disp + + static PetscErrorCode solnkernel_vel(PetscInt spaceDim, + PetscReal t, + const PetscReal x[], + PetscInt numComponents, + PetscScalar* s, + void* context) { + assert(2 == spaceDim); + assert(x); + assert(2 == numComponents); + assert(s); + + s[0] = vel_x(x[0], x[1], t); + s[1] = vel_y(x[0], x[1], t); + + return PETSC_SUCCESS; + } // solnkernel_vel + + static PetscErrorCode solnkernel_acc(PetscInt spaceDim, + PetscReal t, + const PetscReal x[], + PetscInt numComponents, + PetscScalar* s, + void* context) { + assert(2 == spaceDim); + assert(x); + assert(2 == numComponents); + assert(s); + + s[0] = acc_x(x[0], x[1], t); + s[1] = acc_y(x[0], x[1], t); + + return PETSC_SUCCESS; + } // solnkernel_acc + +public: + + static + TestMomentTensorSource_Data* createData(void) { + TestMomentTensorSource_Data* data = new TestMomentTensorSource_Data();assert(data); + + data->journalName = "MomentTensorUniformStrain2D"; + data->isJacobianLinear = true; + data->tolerance = 1.0e-5; // Slightly larger tolerance for wave solution + data->allowZeroResidual = false; // Nonzero solution should give nonzero residual check + + data->meshFilename = ":UNKNOWN:"; // Set in child class. + data->boundaryLabel = "boundary"; + + // Initialize scales first before using them + pylith::scales::ElasticityScales::setDynamicElasticity(&data->scales, LENGTH_SCALE, VELOCITY_SCALE); + scales.setLengthScale(data->scales.getLengthScale()); + scales.setTimeScale(data->scales.getTimeScale()); + scales.setRigidityScale(data->scales.getRigidityScale()); + scales.setDisplacementScale(data->scales.getDisplacementScale()); + scales.setTemperatureScale(data->scales.getTemperatureScale()); + + data->formulation = pylith::problems::Physics::DYNAMIC; + + data->t = TIME_SNAPSHOT; + data->dt = 0.05; + + // Material information + data->numAuxSubfields = 3; + static const char* _auxSubfields[3] = {"density", "shear_modulus", "bulk_modulus"}; + data->auxSubfields = _auxSubfields; + static const pylith::topology::Field::Discretization _auxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 1), // density + pylith::topology::Field::Discretization(0, 1), // shear_modulus + pylith::topology::Field::Discretization(0, 1), // bulk_modulus + }; + data->auxDiscretizations = const_cast(_auxDiscretizations); + + data->auxDB.addValue("density", density, density_units()); + data->auxDB.addValue("vp", vp, vp_units()); + data->auxDB.addValue("vs", vs, vs_units()); + data->auxDB.setCoordSys(data->cs); + + data->material.setFormulation(data->formulation); + data->material.useBodyForce(false); + data->rheology.useReferenceState(false); + + data->material.setIdentifier("elasticity"); + data->material.setName("material-id=24"); + data->material.setLabelValue(24); + + // Source information + data->numSourceAuxSubfields = 3; + static const char* _sourceAuxSubfields[3] = {"moment_tensor", "time_delay", "center_frequency"}; + data->sourceAuxSubfields = _sourceAuxSubfields; + static const pylith::topology::Field::Discretization _sourceAuxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 1), // moment_tensor + pylith::topology::Field::Discretization(0, 1), // time_delay + pylith::topology::Field::Discretization(0, 1), // center_frequency + }; + data->sourceAuxDiscretizations = const_cast(_sourceAuxDiscretizations); + + data->sourceAuxDB.addValue("moment_tensor_xx", moment_xx, moment_units()); + data->sourceAuxDB.addValue("moment_tensor_yy", moment_yy, moment_units()); + data->sourceAuxDB.addValue("moment_tensor_xy", moment_xy, moment_units()); + data->sourceAuxDB.addValue("moment_tensor_yx", moment_yx, moment_units()); + data->sourceAuxDB.addValue("time_delay", time_delay, time_delay_units()); + data->sourceAuxDB.addValue("center_frequency", center_frequency, center_frequency_units()); + data->sourceAuxDB.setCoordSys(data->cs); + + data->source.setFormulation(data->formulation); + data->source.setIdentifier("source"); + data->source.setName("moment-tensor-source"); + data->source.setLabelValue(24); + data->source.setSubfieldName("velocity"); // Apply source to velocity field for dynamic problems + + // Source point coordinates (center of domain) + data->numSourcePoints = 1; + static const PylithReal _sourcePointCoords[2] = {0.0, 0.0}; // Center of domain + data->sourcePointCoords = _sourcePointCoords; + static const char* _sourcePointNames[1] = {"source_point"}; + data->sourcePointNames = _sourcePointNames; + + // Boundary conditions + static const PylithInt constrainedDOF[2] = {0, 1}; + static const PylithInt numConstrained = 2; + pylith::bc::DirichletUserFn* bc = NULL; + data->bcs.resize(2); + bc = new pylith::bc::DirichletUserFn();assert(bc); + bc->setSubfieldName("displacement"); + bc->setLabelName("boundary"); + bc->setLabelValue(1); + bc->setConstrainedDOF(constrainedDOF, numConstrained); + bc->setUserFn(solnkernel_disp); + bc->setUserFnDot(solnkernel_vel); + data->bcs[0] = bc; + + bc = new pylith::bc::DirichletUserFn();assert(bc); + bc->setSubfieldName("velocity"); + bc->setLabelName("boundary"); + bc->setLabelValue(1); + bc->setConstrainedDOF(constrainedDOF, numConstrained); + bc->setUserFn(solnkernel_vel); + bc->setUserFnDot(solnkernel_acc); + data->bcs[1] = bc; + + static const pylith::testing::MMSTest::solution_fn _exactSolnFns[2] = { + solnkernel_disp, + solnkernel_vel, + }; + data->exactSolnFns = const_cast(_exactSolnFns); + static const pylith::testing::MMSTest::solution_fn _exactSolnDotFns[2] = { + solnkernel_vel, + solnkernel_acc, + }; + data->exactSolnDotFns = const_cast(_exactSolnDotFns); + + return data; + } // createData + +}; // _MomentTensorUniformStrain2D + +// Static member initialization +pylith::scales::Scales pylith::_MomentTensorUniformStrain2D::scales; + +// ------------------------------------------------------------------------------------------------ +pylith::TestMomentTensorSource_Data* +pylith::MomentTensorUniformStrain2D::TriP1(void) { + TestMomentTensorSource_Data* data = pylith::_MomentTensorUniformStrain2D::createData();assert(data); + + data->meshFilename = "data/tri.mesh"; + data->useAsciiMesh = true; + + data->numSolnSubfields = 2; + static const pylith::topology::Field::Discretization _solnDiscretizations[2] = { + pylith::topology::Field::Discretization(1, 1), // disp + pylith::topology::Field::Discretization(1, 1), // vel + }; + data->solnDiscretizations = const_cast(_solnDiscretizations); + + return data; +} // TriP1 + + +// ------------------------------------------------------------------------------------------------ +pylith::TestMomentTensorSource_Data* +pylith::MomentTensorUniformStrain2D::TriP2(void) { + TestMomentTensorSource_Data* data = pylith::_MomentTensorUniformStrain2D::createData();assert(data); + + data->meshFilename = "data/tri.mesh"; + data->useAsciiMesh = true; + + static const pylith::topology::Field::Discretization _auxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 2), // density + pylith::topology::Field::Discretization(0, 2), // shear_modulus + pylith::topology::Field::Discretization(0, 2), // bulk_modulus + }; + data->auxDiscretizations = const_cast(_auxDiscretizations); + + static const pylith::topology::Field::Discretization _sourceAuxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 2), // moment_tensor + pylith::topology::Field::Discretization(0, 2), // time_delay + pylith::topology::Field::Discretization(0, 2), // center_frequency + }; + data->sourceAuxDiscretizations = const_cast(_sourceAuxDiscretizations); + + data->numSolnSubfields = 2; + static const pylith::topology::Field::Discretization _solnDiscretizations[2] = { + pylith::topology::Field::Discretization(2, 2), // disp + pylith::topology::Field::Discretization(2, 2), // vel + }; + data->solnDiscretizations = const_cast(_solnDiscretizations); + + return data; +} // TriP2 + + +// ------------------------------------------------------------------------------------------------ +pylith::TestMomentTensorSource_Data* +pylith::MomentTensorUniformStrain2D::QuadQ1(void) { + TestMomentTensorSource_Data* data = pylith::_MomentTensorUniformStrain2D::createData();assert(data); + + data->meshFilename = "data/quad.mesh"; + data->useAsciiMesh = true; + + data->numSolnSubfields = 2; + static const pylith::topology::Field::Discretization _solnDiscretizations[2] = { + pylith::topology::Field::Discretization(1, 1), // disp + pylith::topology::Field::Discretization(1, 1), // vel + }; + data->solnDiscretizations = const_cast(_solnDiscretizations); + + return data; +} // QuadQ1 + + +// ------------------------------------------------------------------------------------------------ +pylith::TestMomentTensorSource_Data* +pylith::MomentTensorUniformStrain2D::QuadQ2(void) { + TestMomentTensorSource_Data* data = pylith::_MomentTensorUniformStrain2D::createData();assert(data); + + data->meshFilename = "data/quad.mesh"; + data->useAsciiMesh = true; + + static const pylith::topology::Field::Discretization _auxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 2), // density + pylith::topology::Field::Discretization(0, 2), // shear_modulus + pylith::topology::Field::Discretization(0, 2), // bulk_modulus + }; + data->auxDiscretizations = const_cast(_auxDiscretizations); + + static const pylith::topology::Field::Discretization _sourceAuxDiscretizations[3] = { + pylith::topology::Field::Discretization(0, 2), // moment_tensor + pylith::topology::Field::Discretization(0, 2), // time_delay + pylith::topology::Field::Discretization(0, 2), // center_frequency + }; + data->sourceAuxDiscretizations = const_cast(_sourceAuxDiscretizations); + + data->numSolnSubfields = 2; + static const pylith::topology::Field::Discretization _solnDiscretizations[2] = { + pylith::topology::Field::Discretization(2, 2), // disp + pylith::topology::Field::Discretization(2, 2), // vel + }; + data->solnDiscretizations = const_cast(_solnDiscretizations); + + return data; +} // QuadQ2 + + +// End of file diff --git a/tests/mmstests/sources/momenttensor-2d/MomentTensorUniformStrain2D.hh b/tests/mmstests/sources/momenttensor-2d/MomentTensorUniformStrain2D.hh new file mode 100644 index 0000000000..7799579dd7 --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/MomentTensorUniformStrain2D.hh @@ -0,0 +1,38 @@ +// ================================================================================================= +// This code is part of PyLith, developed through the Computational Infrastructure +// for Geodynamics (https://github.com/geodynamics/pylith). +// +// Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +// All rights reserved. +// +// See https://mit-license.org/ and LICENSE.md and for license information. +// ================================================================================================= +#pragma once + +#include "TestMomentTensorSource.hh" + +namespace pylith { + class MomentTensorUniformStrain2D; +} + +/** MMS test with nonzero uniform strain solution for moment tensor source. + * + * The manufactured solution uses a linear displacement field (uniform strain) + * with the moment tensor source contribution. + */ +class pylith::MomentTensorUniformStrain2D { +public: + + // Data factory methods + + static TestMomentTensorSource_Data* TriP1(void); + + static TestMomentTensorSource_Data* TriP2(void); + + static TestMomentTensorSource_Data* QuadQ1(void); + + static TestMomentTensorSource_Data* QuadQ2(void); + +}; // class MomentTensorUniformStrain2D + +// End of file diff --git a/tests/mmstests/sources/momenttensor-2d/TestCases.cc b/tests/mmstests/sources/momenttensor-2d/TestCases.cc new file mode 100644 index 0000000000..c03943bf61 --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/TestCases.cc @@ -0,0 +1,70 @@ +// ================================================================================================= +// This code is part of PyLith, developed through the Computational Infrastructure +// for Geodynamics (https://github.com/geodynamics/pylith). +// +// Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +// All rights reserved. +// +// See https://mit-license.org/ and LICENSE.md and for license information. +// ================================================================================================= + +/** Test cases for TestMomentTensorSource + * + * Note: We only test discretization since the moment tensor source is a forcing + * term that doesn't depend on the solution, so it has no Jacobian contribution. + */ + +#include "TestMomentTensorSource.hh" // USES TestMomentTensorSource + +#include "catch2/catch_test_macros.hpp" + +// ------------------------------------------------------------------------------------------------ +#include "MomentTensorSource2D.hh" + +// TriP1 +TEST_CASE("MomentTensorSource2D::TriP1::testDiscretization", "[MomentTensorSource2D][TriP1][discretization]") { + pylith::TestMomentTensorSource(pylith::MomentTensorSource2D::TriP1()).testDiscretization(); +} + +// TriP2 +TEST_CASE("MomentTensorSource2D::TriP2::testDiscretization", "[MomentTensorSource2D][TriP2][discretization]") { + pylith::TestMomentTensorSource(pylith::MomentTensorSource2D::TriP2()).testDiscretization(); +} + +// QuadQ1 +TEST_CASE("MomentTensorSource2D::QuadQ1::testDiscretization", "[MomentTensorSource2D][QuadQ1][discretization]") { + pylith::TestMomentTensorSource(pylith::MomentTensorSource2D::QuadQ1()).testDiscretization(); +} + +// QuadQ2 +TEST_CASE("MomentTensorSource2D::QuadQ2::testDiscretization", "[MomentTensorSource2D][QuadQ2][discretization]") { + pylith::TestMomentTensorSource(pylith::MomentTensorSource2D::QuadQ2()).testDiscretization(); +} + +// ------------------------------------------------------------------------------------------------ +#include "MomentTensorUniformStrain2D.hh" + +// MomentTensorUniformStrain2D - Nonzero manufactured solution tests + +// TriP1 +TEST_CASE("MomentTensorUniformStrain2D::TriP1::testDiscretization", "[MomentTensorUniformStrain2D][TriP1][discretization]") { + pylith::TestMomentTensorSource(pylith::MomentTensorUniformStrain2D::TriP1()).testDiscretization(); +} + +// TriP2 +TEST_CASE("MomentTensorUniformStrain2D::TriP2::testDiscretization", "[MomentTensorUniformStrain2D][TriP2][discretization]") { + pylith::TestMomentTensorSource(pylith::MomentTensorUniformStrain2D::TriP2()).testDiscretization(); +} + +// QuadQ1 +TEST_CASE("MomentTensorUniformStrain2D::QuadQ1::testDiscretization", "[MomentTensorUniformStrain2D][QuadQ1][discretization]") { + pylith::TestMomentTensorSource(pylith::MomentTensorUniformStrain2D::QuadQ1()).testDiscretization(); +} + +// QuadQ2 +TEST_CASE("MomentTensorUniformStrain2D::QuadQ2::testDiscretization", "[MomentTensorUniformStrain2D][QuadQ2][discretization]") { + pylith::TestMomentTensorSource(pylith::MomentTensorUniformStrain2D::QuadQ2()).testDiscretization(); +} + + +// End of file diff --git a/tests/mmstests/sources/momenttensor-2d/TestMomentTensorSource.cc b/tests/mmstests/sources/momenttensor-2d/TestMomentTensorSource.cc new file mode 100644 index 0000000000..2ad96dccdd --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/TestMomentTensorSource.cc @@ -0,0 +1,214 @@ +// ================================================================================================= +// This code is part of PyLith, developed through the Computational Infrastructure +// for Geodynamics (https://github.com/geodynamics/pylith). +// +// Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +// All rights reserved. +// +// See https://mit-license.org/ and LICENSE.md and for license information. +// ================================================================================================= + +#include + +#include "TestMomentTensorSource.hh" // Implementation of class methods + +#include "pylith/problems/TimeDependent.hh" // USES TimeDependent + +#include "pylith/materials/Query.hh" // USES Query + +#include "pylith/topology/Mesh.hh" // USES Mesh +#include "pylith/topology/MeshOps.hh" // USES MeshOps::nondimensionalize() +#include "pylith/topology/Field.hh" // USES Field +#include "pylith/topology/VisitorMesh.hh" // USES VecVisitorMesh +#include "pylith/topology/FieldQuery.hh" // USES FieldQuery +#include "pylith/feassemble/AuxiliaryFactory.hh" // USES AuxiliaryFactory +#include "pylith/problems/SolutionFactory.hh" // USES SolutionFactory +#include "pylith/meshio/MeshIOAscii.hh" // USES MeshIOAscii +#include "pylith/meshio/MeshIOPetsc.hh" // USES MeshIOPetsc +#include "pylith/utils/error.hh" // USES PYLITH_METHOD_BEGIN/END +#include "pylith/utils/journals.hh" // pythia::journal + +#include "pylith/scales/ElasticityScales.hh" // USES ElasticityScales + +// ------------------------------------------------------------------------------------------------ +// Constuctor. +pylith::TestMomentTensorSource::TestMomentTensorSource(TestMomentTensorSource_Data* data) : + _data(data) { + assert(_data); + + GenericComponent::setName(_data->journalName); + _jacobianConvergenceRate = _data->jacobianConvergenceRate; + _tolerance = _data->tolerance; + _isJacobianLinear = _data->isJacobianLinear; + _allowZeroResidual = _data->allowZeroResidual; +} // constructor + + +// ------------------------------------------------------------------------------------------------ +// Destructor. +pylith::TestMomentTensorSource::~TestMomentTensorSource(void) { + delete _data;_data = NULL; +} // destructor + + +// ------------------------------------------------------------------------------------------------ +// Initialize objects for test. +void +pylith::TestMomentTensorSource::_initialize(void) { + PYLITH_METHOD_BEGIN; + assert(_mesh); + assert(_data); + + PetscErrorCode err = PETSC_SUCCESS; + + if (_data->useAsciiMesh) { + pylith::meshio::MeshIOAscii iohandler; + iohandler.setFilename(_data->meshFilename); + iohandler.read(_mesh);assert(_mesh); + } else { + if (_data->meshOptions) { + err = PetscOptionsInsertString(NULL, _data->meshOptions);PYLITH_CHECK_ERROR(err); + } // if + pylith::meshio::MeshIOPetsc iohandler; + iohandler.setFilename(_data->meshFilename); + iohandler.read(_mesh);assert(_mesh); + } // if/else + + assert(pylith::topology::MeshOps::getNumCells(*_mesh) > 0); + assert(pylith::topology::MeshOps::getNumVertices(*_mesh) > 0); + + // Set up coordinates. + _mesh->setCoordSys(&_data->cs); + pylith::topology::MeshOps::nondimensionalize(_mesh, _data->scales); + + // Set up material + _data->material.setBulkRheology(&_data->rheology); + _data->material.setAuxiliaryFieldDB(&_data->auxDB); + + for (size_t i = 0; i < _data->numAuxSubfields; ++i) { + const pylith::topology::FieldBase::Discretization& info = _data->auxDiscretizations[i]; + _data->material.setAuxiliarySubfieldDiscretization(_data->auxSubfields[i], info.basisOrder, info.quadOrder, + _data->spaceDim, pylith::topology::FieldBase::DEFAULT_BASIS, + info.feSpace, info.isBasisContinuous); + } // for + + // Set up source + _data->source.setSourceTimeFunction(&_data->sourceTimeFunction); + _data->source.setAuxiliaryFieldDB(&_data->sourceAuxDB); + + // Set source point coordinates + if (_data->numSourcePoints > 0 && _data->sourcePointCoords && _data->sourcePointNames) { + _data->source.setPoints(_data->sourcePointCoords, _data->numSourcePoints, _data->spaceDim, + _data->sourcePointNames, _data->numSourcePoints); + } // if + + for (size_t i = 0; i < _data->numSourceAuxSubfields; ++i) { + const pylith::topology::FieldBase::Discretization& info = _data->sourceAuxDiscretizations[i]; + _data->source.setAuxiliarySubfieldDiscretization(_data->sourceAuxSubfields[i], info.basisOrder, info.quadOrder, + _data->spaceDim, pylith::topology::FieldBase::DEFAULT_BASIS, + info.feSpace, info.isBasisContinuous); + } // for + + // Set up problem. + assert(_problem); + _problem->setScales(_data->scales); + pylith::materials::Material* materials[1] = { &_data->material }; + _problem->setMaterials(materials, 1); + _problem->setBoundaryConditions(_data->bcs.data(), _data->bcs.size()); + pylith::sources::Source* sources[1] = { &_data->source }; + _problem->setSources(sources, 1); + _problem->setStartTime(_data->t); + _problem->setEndTime(_data->t+_data->dt); + _problem->setInitialTimeStep(_data->dt); + _problem->setFormulation(_data->formulation); + + // Set up solution field. + assert(!_solution); + _solution = new pylith::topology::Field(*_mesh);assert(_solution); + _solution->setLabel("solution"); + pylith::problems::SolutionFactory factory(*_solution, _data->scales); + factory.addDisplacement(_data->solnDiscretizations[0]); + assert(pylith::problems::Physics::DYNAMIC == _data->formulation); + assert(2 == _data->numSolnSubfields); + factory.addVelocity(_data->solnDiscretizations[1]); + _problem->setSolution(_solution); + + pylith::testing::MMSTest::_initialize(); + + PYLITH_METHOD_END; +} // _initialize + + +// ------------------------------------------------------------------------------------------------ +// Set functions for computing the exact solution and its time derivative. +void +pylith::TestMomentTensorSource::_setExactSolution(void) { + assert(_data->exactSolnFns); + + const pylith::topology::Field* solution = _problem->getSolution();assert(solution); + + PetscErrorCode err = PETSC_SUCCESS; + PetscDS ds = NULL; + err = DMGetDS(solution->getDM(), &ds);PYLITH_CHECK_ERROR(err); + for (size_t i = 0; i < _data->numSolnSubfields; ++i) { + err = PetscDSSetExactSolution(ds, i, _data->exactSolnFns[i], NULL);PYLITH_CHECK_ERROR(err); + if (_data->exactSolnDotFns) { + err = PetscDSSetExactSolutionTimeDerivative(ds, i, _data->exactSolnDotFns[i], NULL);PYLITH_CHECK_ERROR(err); + } // if + } // for +} // _setExactSolution + + +// ------------------------------------------------------------------------------------------------ +// Constructor +pylith::TestMomentTensorSource_Data::TestMomentTensorSource_Data(void) : + spaceDim(2), + meshFilename(NULL), + meshOptions(NULL), + boundaryLabel(NULL), + useAsciiMesh(true), + + jacobianConvergenceRate(1.0), + tolerance(1.0e-9), + isJacobianLinear(true), + allowZeroResidual(false), + + t(0.0), + dt(0.05), + formulation(pylith::problems::Physics::DYNAMIC), + + numSolnSubfields(0), + solnDiscretizations(NULL), + + numAuxSubfields(0), + auxSubfields(NULL), + auxDiscretizations(NULL), + + numSourceAuxSubfields(0), + sourceAuxSubfields(NULL), + sourceAuxDiscretizations(NULL), + + numSourcePoints(0), + sourcePointCoords(NULL), + sourcePointNames(NULL) { + auxDB.setDescription("material auxiliary field spatial database"); + sourceAuxDB.setDescription("source auxiliary field spatial database"); + cs.setSpaceDim(spaceDim); + + const double lengthScale = 8.0e+3; + const double velocityScale = 3000.0; + pylith::scales::ElasticityScales::setDynamicElasticity(&scales, lengthScale, velocityScale); +} // constructor + + +// ------------------------------------------------------------------------------------------------ +// Destructor +pylith::TestMomentTensorSource_Data::~TestMomentTensorSource_Data(void) { + for (size_t i = 0; i < bcs.size(); ++i) { + delete bcs[i];bcs[i] = NULL; + } // for + +} // destructor + + +// End of file diff --git a/tests/mmstests/sources/momenttensor-2d/TestMomentTensorSource.hh b/tests/mmstests/sources/momenttensor-2d/TestMomentTensorSource.hh new file mode 100644 index 0000000000..ec966a1a50 --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/TestMomentTensorSource.hh @@ -0,0 +1,129 @@ +// ================================================================================================= +// This code is part of PyLith, developed through the Computational Infrastructure +// for Geodynamics (https://github.com/geodynamics/pylith). +// +// Copyright (c) 2010-2025, University of California, Davis and the PyLith Development Team. +// All rights reserved. +// +// See https://mit-license.org/ and LICENSE.md and for license information. +// ================================================================================================= +#pragma once + +#include "tests/src/MMSTest.hh" // ISA MMSTEST + +#include "pylith/materials/Elasticity.hh" // USES Elasticity +#include "pylith/materials/IsotropicLinearElasticity.hh" // USES IsotropicLinearElasticity +#include "pylith/sources/MomentTensorForce.hh" // USES MomentTensorForce +#include "pylith/sources/RickerWavelet.hh" // USES RickerWavelet +#include "pylith/bc/DirichletUserFn.hh" // USES DirichletUserFn + +#include "spatialdata/spatialdb/UserFunctionDB.hh" // USES UserFunctionDB +#include "spatialdata/geocoords/CSCart.hh" // USES CSCart +#include "pylith/scales/Scales.hh" // USES Scales + +#include "pylith/problems/Physics.hh" // USES FormulationEnum +#include "pylith/topology/Field.hh" // HASA FieldBase::Discretization + +namespace pylith { + class TestMomentTensorSource; + class TestMomentTensorSource_Data; +} + +/// C++ class for testing moment tensor source using MMS. +class pylith::TestMomentTensorSource : public pylith::testing::MMSTest { + // PUBLIC METHODS ///////////////////////////////////////////////////////////////////////////// +public: + + /** Constructor + * + * @param[in] data Data for MMS test. + */ + TestMomentTensorSource(TestMomentTensorSource_Data* data); + + /// Destructor. + ~TestMomentTensorSource(void); + + // PROTECTED METHODS ////////////////////////////////////////////////////////////////////////// +protected: + + /// Initialize objects for test. + void _initialize(void); + + /// Set exact solution and time derivative of solution in domain. + void _setExactSolution(void); + + // PROTECTED MEMBERS ////////////////////////////////////////////////////////////////////////// +protected: + + TestMomentTensorSource_Data* _data; ///< Test parameters. + +}; // class TestMomentTensorSource + +// ================================================================================================ +class pylith::TestMomentTensorSource_Data { + // PUBLIC METHODS ///////////////////////////////////////////////////////////////////////////// +public: + + /// Constructor + TestMomentTensorSource_Data(void); + + /// Destructor + ~TestMomentTensorSource_Data(void); + + // PUBLIC MEMBERS ///////////////////////////////////////////////////////////////////////////// +public: + + const char* journalName; ///< Name for MMSTest journals. + int spaceDim; ///< Spatial dimension of domain. + const char* meshFilename; ///< Name of file with ASCII mesh. + const char* meshOptions; ///< Command line options for mesh. + const char* boundaryLabel; ///< Group defining domain boundary. + bool useAsciiMesh; ///< Use MeshIOAscii to read mesh, otherwise use PETSc. + + PylithReal jacobianConvergenceRate; ///< Expected convergence rate for Jacobian (when not linear). + PylithReal tolerance; ///< Tolerance for discretization and residual test. + bool isJacobianLinear; ///< Jacobian should be linear. + bool allowZeroResidual; ///< Allow residual to be exactly zero. + + PylithReal t; ///< Time for MMS solution. + PylithReal dt; ///< Time step in simulation. + spatialdata::geocoords::CSCart cs; ///< Coordinate system. + pylith::scales::Scales scales; ///< Scales for nondimensionalization. + pylith::problems::Physics::FormulationEnum formulation; ///< Time stepping formulation + + pylith::materials::Elasticity material; ///< Material. + pylith::materials::IsotropicLinearElasticity rheology; ///< Bulk rheology for material. + pylith::sources::MomentTensorForce source; ///< Moment tensor source. + pylith::sources::RickerWavelet sourceTimeFunction; ///< Source time function. + std::vector bcs; ///< Dirichlet boundary conditions. + + // Solution field. + size_t numSolnSubfields; ///< Number of solution fields. + pylith::topology::Field::Discretization const* solnDiscretizations; ///< Discretizations for solution fields. + + /// Array of functions providing exact solution. + pylith::testing::MMSTest::solution_fn* exactSolnFns; + + /// Array of functions providing exact solution time derivative. + pylith::testing::MMSTest::solution_fn* exactSolnDotFns; + + // Material auxiliary fields. + size_t numAuxSubfields; ///< Number of auxiliary subfields for materials. + const char** auxSubfields; ///< Names of auxiliary subfields for materials. + pylith::topology::Field::Discretization const* auxDiscretizations; ///< Discretizations for auxiliary subfields. + spatialdata::spatialdb::UserFunctionDB auxDB; ///< Spatial database for auxiliary field. + + // Source auxiliary fields. + size_t numSourceAuxSubfields; ///< Number of auxiliary subfields for source. + const char** sourceAuxSubfields; ///< Names of auxiliary subfields for source. + pylith::topology::Field::Discretization const* sourceAuxDiscretizations; ///< Discretizations for source auxiliary subfields. + spatialdata::spatialdb::UserFunctionDB sourceAuxDB; ///< Spatial database for source auxiliary field. + + // Source point locations. + size_t numSourcePoints; ///< Number of source points. + const PylithReal* sourcePointCoords; ///< Coordinates of source points [numSourcePoints * spaceDim]. + const char* const* sourcePointNames; ///< Names of source points. + +}; // TestMomentTensorSource_Data + +// End of file diff --git a/tests/mmstests/sources/momenttensor-2d/data/quad.mesh b/tests/mmstests/sources/momenttensor-2d/data/quad.mesh new file mode 100644 index 0000000000..3c3fc4212a --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/data/quad.mesh @@ -0,0 +1,78 @@ +mesh = { + dimension = 2 + use-index-zero = true + vertices = { + dimension = 2 + count = 16 + coordinates = { + 0 -4.0e+3 -4.0e+3 + 1 -4.0e+3 -2.0e+3 + 2 -4.0e+3 +2.0e+3 + 3 -4.0e+3 +4.0e+3 + 4 -2.0e+3 -4.0e+3 + 5 -2.0e+3 -2.0e+3 + 6 -2.0e+3 +2.0e+3 + 7 -2.0e+3 +4.0e+3 + 8 +2.0e+3 -4.0e+3 + 9 +2.0e+3 -2.0e+3 + 10 +2.0e+3 +2.0e+3 + 11 +2.0e+3 +4.0e+3 + 12 +4.0e+3 -4.0e+3 + 13 +4.0e+3 -2.0e+3 + 14 +4.0e+3 +2.0e+3 + 15 +4.0e+3 +4.0e+3 + } + } + cells = { + count = 9 + num-corners = 4 + simplices = { + 0 0 4 5 1 + 1 1 5 6 2 + 2 2 6 7 3 + 3 4 8 9 5 + 4 5 9 10 6 + 5 6 10 11 7 + 6 8 12 13 9 + 7 9 13 14 10 + 8 10 14 15 11 + } + material-ids = { + 0 24 + 1 24 + 2 24 + 3 24 + 4 24 + 5 24 + 6 24 + 7 24 + 8 24 + } + } + vertex-group = { + name = boundary_vertices + count = 12 + indices = { + 0 1 2 3 4 7 8 11 12 13 14 15 + } + } + face-group = { + name = boundary + count = 12 + indices = { + 0 0 1 + 0 0 4 + 1 1 2 + 2 2 3 + 2 3 7 + 3 4 8 + 5 7 11 + 6 8 12 + 6 12 13 + 7 13 14 + 8 14 15 + 8 11 15 + } + } + +} diff --git a/tests/mmstests/sources/momenttensor-2d/data/tri.mesh b/tests/mmstests/sources/momenttensor-2d/data/tri.mesh new file mode 100644 index 0000000000..c8ca67d822 --- /dev/null +++ b/tests/mmstests/sources/momenttensor-2d/data/tri.mesh @@ -0,0 +1,80 @@ +mesh = { + dimension = 2 + use-index-zero = true + vertices = { + dimension = 2 + count = 12 + coordinates = { + 0 -4.0e+3 -4.0e+3 + 1 -4.0e+3 0.0e+3 + 2 -4.0e+3 +4.0e+3 + 3 -2.0e+3 -2.0e+3 + 4 -2.0e+3 +2.0e+3 + 5 0.0e+3 -4.0e+3 + 6 0.0e+3 +4.0e+3 + 7 +2.0e+3 -2.0e+3 + 8 +2.0e+3 +2.0e+3 + 9 +4.0e+3 -4.0e+3 + 10 +4.0e+3 0.0e+3 + 11 +4.0e+3 +4.0e+3 + } + } + cells = { + count = 14 + num-corners = 3 + simplices = { + 0 0 3 1 + 1 1 3 4 + 2 1 4 2 + 3 0 5 3 + 4 2 4 6 + 5 3 5 7 + 6 3 7 8 + 7 3 8 4 + 8 4 8 6 + 9 5 9 7 + 10 8 11 6 + 11 7 9 10 + 12 7 10 8 + 13 8 10 11 + } + material-ids = { + 0 24 + 1 24 + 2 24 + 3 24 + 4 24 + 5 24 + 6 24 + 7 24 + 8 24 + 9 24 + 10 24 + 11 24 + 12 24 + 13 24 + } + } + vertex-group = { + name = boundary_vertices + count = 8 + indices = { + 0 1 2 5 6 9 10 11 + } + } + face-group = { + name = boundary + count = 8 + indices = { + 0 0 1 + 2 1 2 + 3 0 5 + 4 2 6 + 9 5 9 + 10 6 11 + 11 9 10 + 13 10 11 + } + } + +} diff --git a/tests/pytests/sources/TestMomentTensorForce.py b/tests/pytests/sources/TestMomentTensorForce.py new file mode 100644 index 0000000000..269a1c2d82 --- /dev/null +++ b/tests/pytests/sources/TestMomentTensorForce.py @@ -0,0 +1,41 @@ +#!/usr/bin/env nemesis +# +# ====================================================================== +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University at Buffalo +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2022 University of California, Davis +# +# See LICENSE.md for license information. +# +# ====================================================================== +# +# @file tests/pytests/sources/TestMomentTensorForce.py +# +# @brief Unit testing of Python TestMomentTensorForce object. + +import unittest + +from pylith.testing.UnitTestApp import TestComponent +from pylith.sources.Source import (MomentTensorForce, source) + + +class TestMomentTensorForce(TestComponent): + """Unit testing of MomentTensorForce object. + """ + _class = MomentTensorForce + _factory = source + + +if __name__ == "__main__": + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestMomentTensorForce)) + unittest.TextTestRunner(verbosity=2).run(suite) + + +# End of file diff --git a/tests/pytests/sources/TestSource.py b/tests/pytests/sources/TestSource.py new file mode 100644 index 0000000000..a17a14f0ae --- /dev/null +++ b/tests/pytests/sources/TestSource.py @@ -0,0 +1,40 @@ +#!/usr/bin/env nemesis +# +# ====================================================================== +# +# Brad T. Aagaard, U.S. Geological Survey +# Charles A. Williams, GNS Science +# Matthew G. Knepley, University at Buffalo +# +# This code was developed as part of the Computational Infrastructure +# for Geodynamics (http://geodynamics.org). +# +# Copyright (c) 2010-2022 University of California, Davis +# +# See LICENSE.md for license information. +# +# ====================================================================== +# +# @file tests/pytests/sources/TestSource.py +# +# @brief Unit testing of Python TestSource object. + +import unittest + +from pylith.testing.UnitTestApp import TestAbstractComponent +from pylith.sources.Source import Source + + +class TestSource(TestAbstractComponent): + """Unit testing of Source object. + """ + _class = Source + + +if __name__ == "__main__": + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestSource)) + unittest.TextTestRunner(verbosity=2).run(suite) + + +# End of file diff --git a/tests/pytests/sources/__init__.py b/tests/pytests/sources/__init__.py new file mode 100644 index 0000000000..7911cd671b --- /dev/null +++ b/tests/pytests/sources/__init__.py @@ -0,0 +1,2 @@ +from .TestSource import TestSource +from .TestMomentTensorForce import TestMomentTensorForce