diff --git a/README.md b/README.md index 8f2656b..7cda807 100644 --- a/README.md +++ b/README.md @@ -1 +1,4 @@ +Preprocessing +============= + A collection of useful tools for mesh generation and preprocessing for [SeisSol](http://www.seissol.org). diff --git a/meshing/cube_c/CMakeLists.txt b/meshing/cube_c/CMakeLists.txt new file mode 100644 index 0000000..5478f8a --- /dev/null +++ b/meshing/cube_c/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.10) + +# set the project name +project(cube_c) + +# specify the C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +cmake_policy(SET CMP0074 NEW) + + +add_executable(cubeGenerator src/main.cpp) + +#logging +set(LOG_LEVEL "warning" CACHE STRING "Log level for the code") +set(LOG_LEVEL_OPTIONS "debug" "info" "warning" "error") +set_property(CACHE LOG_LEVEL PROPERTY STRINGS ${LOG_LEVEL_OPTIONS}) +if("${LOG_LEVEL}" STREQUAL "debug") + target_compile_definitions(cubeGenerator PUBLIC LOG_LEVEL=3) +elseif("${LOG_LEVEL}" STREQUAL "info") + target_compile_definitions(cubeGenerator PUBLIC LOG_LEVEL=2) +elseif("${LOG_LEVEL}" STREQUAL "warning") + target_compile_definitions(cubeGenerator PUBLIC LOG_LEVEL=1) +elseif("${LOG_LEVEL}" STREQUAL "error") + target_compile_definitions(cubeGenerator PUBLIC LOG_LEVEL=0) +endif() + +#build and link libraries and executable +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../cmake" ${CMAKE_MODULE_PATH}) +find_package(NetCDF REQUIRED) +target_include_directories(cubeGenerator PUBLIC ${NetCDF_INCLUDE_DIRS}) +target_link_libraries(cubeGenerator PUBLIC ${NetCDF_LIBRARY}) + +find_package(HDF5 REQUIRED + COMPONENTS C HL) +target_include_directories(cubeGenerator PUBLIC ${HDF5_INCLUDE_DIRS}) +target_link_libraries(cubeGenerator PUBLIC ${HDF5_C_HL_LIBRARIES} ${HDF5_C_LIBRARIES}) + +find_package(MPI REQUIRED) +target_link_libraries(cubeGenerator PUBLIC MPI::MPI_C) + +find_package(OpenMP REQUIRED) +target_link_libraries(cubeGenerator PUBLIC OpenMP::OpenMP_CXX) + +#add some compiler specific flags +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # using GCC + target_compile_options(cubeGenerator PUBLIC -fopenmp -pedantic $<$,$>:-Wall -Wextra -Wno-unused-parameter -Wno-unknown-pragmas>) + target_link_libraries(cubeGenerator PUBLIC "-fopenmp") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + target_compile_options(cubeGenerator PUBLIC -qopenmp -pedantic $<$,$>:-Wall -w3 -diag-disable:remark>) + target_link_libraries(cubeGenerator PUBLIC "-qopenmp") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp=libomp -Wall -Wextra -pedantic") +endif() + +target_include_directories(cubeGenerator PUBLIC "${PROJECT_SOURCE_DIR}/../../submodules") diff --git a/meshing/cube_c/src/SConscript b/meshing/cube_c/src/SConscript new file mode 100644 index 0000000..fe69428 --- /dev/null +++ b/meshing/cube_c/src/SConscript @@ -0,0 +1,45 @@ +#! /usr/bin/python +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @author Sebastian Rettenberger (rettenbs AT in.tum.de, http://www5.in.tum.de/wiki/index.php/Sebastian_Rettenberger,_M.Sc.) +# +# @section LICENSE +# Copyright (c) 2013, SeisSol Group +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +Import('env') + +env.sourceFiles.extend( + [env.Object('main.cpp')] + ) + +Export('env') diff --git a/meshing/cube_c/src/main.cpp b/meshing/cube_c/src/main.cpp new file mode 100644 index 0000000..5166fba --- /dev/null +++ b/meshing/cube_c/src/main.cpp @@ -0,0 +1,1291 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Sebastian Rettenberger (sebastian.rettenberger AT tum.de, http://www5.in.tum.de/wiki/index.php/Sebastian_Rettenberger) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "utils/args.h" +#include "utils/logger.h" + +#include + +#include + +#include +#include +#include +#include +#include + +typedef int t_vertex[3]; + +// Index of the vertices of a tetraedra in a cube +// even/odd, index of the tetrahedra, index of vertex, offset of the vertices in x/y/z +static const t_vertex TET_VERTICES[2][5][4] = { + { + {{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, + {{1, 0, 0}, {0, 1, 0}, {1, 1, 1}, {1, 1, 0}}, + {{1, 0, 0}, {1, 1, 1}, {0, 0, 1}, {1, 0, 1}}, + {{0, 1, 0}, {0, 1, 1}, {0, 0, 1}, {1, 1, 1}}, + {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {1, 1, 1}} + }, + { + {{0, 0, 0}, {0, 1, 0}, {0, 1, 1}, {1, 1, 0}}, + {{0, 0, 0}, {1, 1, 0}, {1, 0, 1}, {1, 0, 0}}, + {{0, 0, 0}, {1, 0, 1}, {0, 1, 1}, {0, 0, 1}}, + {{1, 1, 0}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}}, + {{0, 0, 0}, {1, 1, 0}, {0, 1, 1}, {1, 0, 1}} + } +}; + +struct Vertex +{ + t_vertex v; + + bool operator<(const Vertex& other) const { + return (v[0] < other.v[0]) + || ((v[0] == other.v[0]) && (v[1] < other.v[1])) + || ((v[0] == other.v[0]) && (v[1] == other.v[1]) && (v[2] < other.v[2])); + } +}; + +static const int TET_SIDE_NEIGHBORS[2][5*4] = { + {3, 3, 3, 0, + 1, 3, 0, 2, + 2, 2, 2, 1, + 0, 1, 3, 1, + 3, 0, 0, 2}, + {2, 3, 0, 1, + 1, 3, 3, 2, + 2, 1, 1, 0, + 0, 3, 2, 1, + 2, 0, 0, 1} +}; + +static const int TET_SIDE_ORIENTATIONS[2][5*4] = { + {2, 0, 2, 0, + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 1, + 0, 0, 0, 0}, + {0, 1, 0, 0, + 0, 1, 0, 2, + 0, 0, 0, 2, + 0, 0, 0, 0, + 0, 0, 0, 0} +}; + +// Process has done i out of n rounds, +// and we want a bar of width w and resolution r. +// TODO put this i an library +static inline void loadBar(int x, int n, int r = 100, int w = 50) +{ + r = std::min(r, n); + + // Only update r times. + if ( x % (n/r) != 0 ) return; + + // Calculuate the ratio of complete-to-incomplete. + float ratio = x/(float)n; + int c = ratio * w; + + // Show the percentage complete. + std::cout << std::setw(3) << (int)(ratio*100) << "% ["; + + // Show the load bar. + for (int x=0; x +std::pair flip_pair(const std::pair &p) +{ + return std::pair(p.second, p.first); +} + +void checkNcError(int error) +{ + if (error != NC_NOERR) + logError() << "Error while writing netCDF file:" << nc_strerror(error); +} + +int main(int argc, char* argv[]) +{ + // Parse command line arguments + utils::Args args; + args.addOption("boundary", 'b', "boundary condition (default: 1)", utils::Args::Required, false); + args.addOption("minx", 0, "boundary condition at the start of x dimension", utils::Args::Required, false); + args.addOption("maxx", 0, "boundary condition at the end of x dimension", utils::Args::Required, false); + args.addOption("miny", 0, "boundary condition at the start of y dimension", utils::Args::Required, false); + args.addOption("maxy", 0, "boundary condition at the end of y dimension", utils::Args::Required, false); + args.addOption("minz", 0, "boundary condition at the start of z dimension", utils::Args::Required, false); + args.addOption("maxz", 0, "boundary condition at the end of z dimension", utils::Args::Required, false); + args.addOption("netcdf", 'n', "for compatibility with the Python script", utils::Args::No, false); + args.addOption("x", 'x', "number of cubes in x dimension"); + args.addOption("y", 'y', "number of cubes in y dimension"); + args.addOption("z", 'z', "number of cubes in z dimension"); + args.addOption("px", 0, "number of partitions x dimension"); + args.addOption("py", 0, "number of partitions y dimension"); + args.addOption("pz", 0, "number of partitions z dimension"); + args.addOption("output", 'o', "output file for resulting netCDF mesh"); + args.addOption("scale", 's', "size of the domain = [-s/2, s/2]^3 (default: 100)", utils::Args::Required, false); + args.addOption("sx", 0, "scale in x direction (overwrites scale in x direction)", utils::Args::Required, false); + args.addOption("sy", 0, "scale in y direction (overwrites scale in y direction)", utils::Args::Required, false); + args.addOption("sz", 0, "scale in z direction (overwrites scale in z direction)", utils::Args::Required, false); + args.addOption("tx", 0, "mesh translation in x direction (after scaling)", utils::Args::Required, false); + args.addOption("ty", 0, "mesh translation in y direction (after scaling)", utils::Args::Required, false); + args.addOption("tz", 0, "mesh translation in z direction (after scaling)", utils::Args::Required, false); + + unsigned int numCubes[4]; + unsigned int numPartitions[4]; + + // Parse/check command line arguments + if (args.parse(argc, argv) == utils::Args::Success) { + numCubes[0] = args.getArgument("x"); + numCubes[1] = args.getArgument("y"); + numCubes[2] = args.getArgument("z"); + + numPartitions[0] = args.getArgument("px"); + numPartitions[1] = args.getArgument("py"); + numPartitions[2] = args.getArgument("pz"); + + for (int i = 0; i < 3; i++) { + if (numCubes[i] < 2) + logError() << "Number of cubes in" << dim2str(i) << "dimension must be at least 2"; + if (numCubes[i] % numPartitions[i] != 0) + logError() << "Number of cubes in" << dim2str(i) + << "dimension can not be distribute to" << numPartitions[i] << "partitions"; + if ((numCubes[i] / numPartitions[i]) % 2 != 0) + logError() << "Number of cubes per partition in" << dim2str(i) << "dimension must be a multiple of 2"; + } + } else { + return 1; + } + + unsigned int boundary = args.getArgument("boundary", 1u); + if (boundary > 100) + boundary -= 100; + unsigned int boundaryMinx = args.getArgument("minx", boundary); + unsigned int boundaryMaxx = args.getArgument("maxx", boundary); + unsigned int boundaryMiny = args.getArgument("miny", boundary); + unsigned int boundaryMaxy = args.getArgument("maxy", boundary); + unsigned int boundaryMinz = args.getArgument("minz", boundary); + unsigned int boundaryMaxz = args.getArgument("maxz", boundary); + logInfo() << "Boundary condition:" << boundary; + logInfo() << "boundaryMinx condition:" << boundaryMinx; + logInfo() << "boundaryMaxx condition:" << boundaryMaxx; + logInfo() << "boundaryMiny condition:" << boundaryMiny; + logInfo() << "boundaryMaxy condition:" << boundaryMaxy; + logInfo() << "boundaryMinz condition:" << boundaryMinz; + logInfo() << "boundaryMaxz condition:" << boundaryMaxz; + + // Compute additional sizes + numCubes[3] = numCubes[0] * numCubes[1] * numCubes[2]; + numPartitions[3] = numPartitions[0] * numPartitions[1] * numPartitions[2]; + + unsigned int numCubesPerPart[4]; + unsigned long numElemPerPart[4]; + for (int i = 0; i < 4; i++) { + numCubesPerPart[i] = numCubes[i] / numPartitions[i]; + numElemPerPart[i] = numCubesPerPart[i] * 5; + } + + unsigned int numVrtxPerPart[4]; + for (int i = 0; i < 3; i++) + numVrtxPerPart[i] = numCubesPerPart[i] + 1; + numVrtxPerPart[3] = numVrtxPerPart[0] * numVrtxPerPart[1] * numVrtxPerPart[2]; + + unsigned int numBndElements[3]; + numBndElements[0] = 2*numCubesPerPart[1]*numCubesPerPart[2]; + numBndElements[1] = 2*numCubesPerPart[0]*numCubesPerPart[2]; + numBndElements[2] = 2*numCubesPerPart[0]*numCubesPerPart[1]; + + logInfo() << "Total number of cubes:" << numCubes[0] << 'x' << numCubes[1] << 'x' << numCubes[2] << '=' << numCubes[3]; + logInfo() << "Total number of partitions" << numPartitions[0] << 'x' << numPartitions[1] << 'x' << numPartitions[2] + << '=' << numPartitions[3]; + logInfo() << "Total number of cubes per partition:" << numCubesPerPart[0] << 'x' << numCubesPerPart[1] << 'x' + << numCubesPerPart[2] << '=' << numCubesPerPart[3]; + logInfo() << "Total number of elements per partition:" << numElemPerPart[0] << 'x' << numElemPerPart[1] << 'x' + << numElemPerPart[2] << '=' << numElemPerPart[3]; + logInfo() << "Using" << omp_get_max_threads() << "threads"; + + int netcdf_writes = 2 + numPartitions[3]*8; + + // Create the netcdf file + int ncFile; + checkNcError(nc_create(args.getArgument("output").c_str(), NC_NETCDF4, &ncFile)); + + int ncDimDimension; + nc_def_dim(ncFile, "dimension", 3, &ncDimDimension); + + int ncDimPart; + nc_def_dim(ncFile, "partitions", numPartitions[3], &ncDimPart); + + int ncDimElem, ncDimElemSides, ncDimElemVertices; + nc_def_dim(ncFile, "elements", numElemPerPart[3], &ncDimElem); + nc_def_dim(ncFile, "element_sides", 4, &ncDimElemSides); + nc_def_dim(ncFile, "element_vertices_dim", 4, &ncDimElemVertices); + + int ncDimVrtx; + nc_def_dim(ncFile, "vertices", numVrtxPerPart[3], &ncDimVrtx); + + int ncDimBnd, ncDimBndElem; + nc_def_dim(ncFile, "boundaries", 6, &ncDimBnd); + nc_def_dim(ncFile, "boundary_elements", *std::max_element(numBndElements, numBndElements+3), &ncDimBndElem); + + // Create netcdf variables + int ncVarElemSize; + checkNcError(nc_def_var(ncFile, "element_size", NC_INT, 1, &ncDimPart, &ncVarElemSize)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemSize, NC_COLLECTIVE)); + + int ncVarElemVertices; + int dimsElemVertices[] = {ncDimPart, ncDimElem, ncDimElemVertices}; + checkNcError(nc_def_var(ncFile, "element_vertices", NC_INT, 3, dimsElemVertices, &ncVarElemVertices)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemVertices, NC_COLLECTIVE)); + + int ncVarElemNeighbors; + int dimsElemSides[] = {ncDimPart, ncDimElem, ncDimElemSides}; + checkNcError(nc_def_var(ncFile, "element_neighbors", NC_INT, 3, dimsElemSides, &ncVarElemNeighbors)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemNeighbors, NC_COLLECTIVE)); + + int ncVarElemBoundaries; + checkNcError(nc_def_var(ncFile, "element_boundaries", NC_INT, 3, dimsElemSides, &ncVarElemBoundaries)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemBoundaries, NC_COLLECTIVE)); + + int ncVarElemNeighborSides; + checkNcError(nc_def_var(ncFile, "element_neighbor_sides", NC_INT, 3, dimsElemSides, &ncVarElemNeighborSides)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemNeighborSides, NC_COLLECTIVE)); + + int ncVarElemSideOrientations; + checkNcError(nc_def_var(ncFile, "element_side_orientations", NC_INT, 3, dimsElemSides, &ncVarElemSideOrientations)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemSideOrientations, NC_COLLECTIVE)); + + int ncVarElemNeighborRanks; + checkNcError(nc_def_var(ncFile, "element_neighbor_ranks", NC_INT, 3, dimsElemSides, &ncVarElemNeighborRanks)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemNeighborRanks, NC_COLLECTIVE)); + + int ncVarElemMPIIndices; + checkNcError(nc_def_var(ncFile, "element_mpi_indices", NC_INT, 3, dimsElemSides, &ncVarElemMPIIndices)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemMPIIndices, NC_COLLECTIVE)); + + int ncVarElemGroup; + checkNcError(nc_def_var(ncFile, "element_group", NC_INT, 2, dimsElemSides, &ncVarElemGroup)); +// checkNcError(nc_var_par_access(ncFile, ncVarElemGroup, NC_COLLECTIVE)); + + int ncVarVrtxSize; + checkNcError(nc_def_var(ncFile, "vertex_size", NC_INT, 1, &ncDimPart, &ncVarVrtxSize)); +// checkNcError(nc_var_par_access(ncFile, ncVarVrtxSize, NC_COLLECTIVE)); + + int ncVarVrtxCoords; + int dimsVrtxCoords[] = {ncDimPart, ncDimVrtx, ncDimDimension}; + checkNcError(nc_def_var(ncFile, "vertex_coordinates", NC_DOUBLE, 3, dimsVrtxCoords, &ncVarVrtxCoords)); +// checkNcError(nc_var_par_access(ncFile, ncVarVrtxCoords, NC_COLLECTIVE)); + + int ncVarBndSize; + checkNcError(nc_def_var(ncFile, "boundary_size", NC_INT, 1, &ncDimPart, &ncVarBndSize)); +// checkNcError(nc_var_par_access(ncFile, ncVarBndSize, NC_COLLECTIVE)); + + int ncVarBndElemSize; + int dimsBndElemSize[] = {ncDimPart, ncDimBnd}; + checkNcError(nc_def_var(ncFile, "boundary_element_size", NC_INT, 2, dimsBndElemSize, &ncVarBndElemSize)); +// checkNcError(nc_var_par_access(ncFile, ncVarBndElemSize, NC_COLLECTIVE)); + + int ncVarBndElemRank; + checkNcError(nc_def_var(ncFile, "boundary_element_rank", NC_INT, 2, dimsBndElemSize, &ncVarBndElemRank)); +// checkNcError(nc_var_par_access(ncFile, ncVarBndElemRank, NC_COLLECTIVE)); + + int ncVarBndElemLocalIds; + int dimsBndElemLocalIds[] = {ncDimPart, ncDimBnd, ncDimBndElem}; + checkNcError(nc_def_var(ncFile, "boundary_element_localids", NC_INT, 3, dimsBndElemLocalIds, &ncVarBndElemLocalIds)); +// checkNcError(nc_var_par_access(ncFile, ncVarBndElemLocalIds, NC_COLLECTIVE)); + + int writes_done = 0; + loadBar(writes_done, netcdf_writes); + + // Elements + int *elemSize = new int[numPartitions[3]]; + std::fill(elemSize, elemSize+numPartitions[3], numElemPerPart[3]); + checkNcError(nc_put_var_int(ncFile, ncVarElemSize, elemSize)); + delete [] elemSize; + writes_done++; loadBar(writes_done, netcdf_writes); + + std::vector vertices; + vertices.resize(numElemPerPart[3]*4); + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + unsigned int c = ((zz*numCubesPerPart[1] + yy)*numCubesPerPart[0] + xx) * 20; + int odd = (zz+yy+xx) % 2; + + for (unsigned int i = 0; i < 5; i++) { + for (unsigned int j = 0; j < 4; j++) { + Vertex v; + v.v[0] = TET_VERTICES[odd][i][j][0] + xx; + v.v[1] = TET_VERTICES[odd][i][j][1] + yy; + v.v[2] = TET_VERTICES[odd][i][j][2] + zz; + vertices[c] = v; + c++; + } + } + } + } + } + + int *elemVertices = new int[numElemPerPart[3]*4]; + std::map vertexMap; + for (unsigned int i = 0; i < vertices.size(); i++) { + std::map::iterator it = vertexMap.find(vertices[i]); + if (it != vertexMap.end()) { + elemVertices[i] = it->second; + } else { + int n = vertexMap.size(); + vertexMap[vertices[i]] = n; + elemVertices[i] = n; + } + } + + for (unsigned int i = 0; i < numPartitions[3]; i++) { + size_t start[3] = {i, 0, 0}; + size_t count[3] = {1, numElemPerPart[3], 4}; + checkNcError(nc_put_vara_int(ncFile, ncVarElemVertices, start, count, elemVertices)); + writes_done++; loadBar(writes_done, netcdf_writes); + } + delete [] elemVertices; + + int *elemNeighbors = new int[numElemPerPart[3]*4]; + const int TET_NEIGHBORS[2][5*4] = { + {-static_cast(numCubesPerPart[1]*numCubesPerPart[0])*5+2, -static_cast(numCubesPerPart[0])*5, -4, 4, + 4, -static_cast(numCubesPerPart[1]*numCubesPerPart[0])*5+3, 5, static_cast(numCubesPerPart[0])*5+1, + 4, 7, -static_cast(numCubesPerPart[0])*5+3, static_cast(numCubesPerPart[1]*numCubesPerPart[0])*5+1, + -2, static_cast(numCubesPerPart[0])*5+2, 4, static_cast(numCubesPerPart[1]*numCubesPerPart[0])*5, + 0, 1, 2, 3}, + {-4, -static_cast(numCubesPerPart[1]*numCubesPerPart[0])*5+3, 4, static_cast(numCubesPerPart[0])*5, + 4, -static_cast(numCubesPerPart[1]*numCubesPerPart[0])*5+2, -static_cast(numCubesPerPart[0])*5+1, 5, + 4, -static_cast(numCubesPerPart[0])*5+3, -3, static_cast(numCubesPerPart[1]*numCubesPerPart[0])*5, + 8, 4, static_cast(numCubesPerPart[0])*5+2, static_cast(numCubesPerPart[1]*numCubesPerPart[0])*5+1, + 0, 1, 2, 3} + }; + + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + unsigned int c = ((zz*numCubesPerPart[1] + yy)*numCubesPerPart[0] + xx) * 20; + int odd = (zz+yy+xx) % 2; + + memcpy(&elemNeighbors[c], TET_NEIGHBORS[odd], sizeof(int)*20); + int offset = ((zz*numCubesPerPart[1] + yy)*numCubesPerPart[0] + xx)*5; + for (int i = 0; i < 20; i++) + elemNeighbors[c+i] += offset; + + if (xx == 0) { // first cube in a partition in x dimension + if (odd) { + if (boundaryMinx == 6 && numPartitions[0] == 1) { + elemNeighbors[c] += numCubesPerPart[0]*5; + elemNeighbors[c+10] += numCubesPerPart[0]*5; + } else { + elemNeighbors[c] = numElemPerPart[3]; + elemNeighbors[c+10] = numElemPerPart[3]; + } + } else { + if (boundaryMinx == 6 && numPartitions[0] == 1) { + elemNeighbors[c+2] += numCubesPerPart[0]*5; + elemNeighbors[c+12] += numCubesPerPart[0]*5; + } else { + elemNeighbors[c+2] = numElemPerPart[3]; + elemNeighbors[c+12] = numElemPerPart[3]; + } + } + } else if (xx == numCubesPerPart[0]-1) { // last cube in a partition in x dimension + if (odd) { + if (boundaryMaxx == 6 && numPartitions[0] == 1) { + elemNeighbors[c+7] -= numCubesPerPart[0]*5; + elemNeighbors[c+12] -= numCubesPerPart[0]*5; + } else { + elemNeighbors[c+7] = numElemPerPart[3]; + elemNeighbors[c+12] = numElemPerPart[3]; + } + } else { + if (boundaryMaxx == 6 && numPartitions[0] == 1) { + elemNeighbors[c+6] -= numCubesPerPart[0]*5; + elemNeighbors[c+9] -= numCubesPerPart[0]*5; + } else { + elemNeighbors[c+6] = numElemPerPart[3]; + elemNeighbors[c+9] = numElemPerPart[3]; + } + } + } + if (yy == 0) { // first cube in a partition in y dimension + if (odd) { + if (boundaryMiny == 6 && numPartitions[1] == 1) { + elemNeighbors[c+6] += numCubesPerPart[0]*numCubesPerPart[1]*5; + elemNeighbors[c+9] += numCubesPerPart[0]*numCubesPerPart[1]*5; + } else { + elemNeighbors[c+6] = numElemPerPart[3]; + elemNeighbors[c+9] = numElemPerPart[3]; + } + } else { + if (boundaryMiny == 6 && numPartitions[1] == 1) { + elemNeighbors[c+1] += numCubesPerPart[0]*numCubesPerPart[1]*5; + elemNeighbors[c+10] += numCubesPerPart[0]*numCubesPerPart[1]*5; + } else { + elemNeighbors[c+1] = numElemPerPart[3]; + elemNeighbors[c+10] = numElemPerPart[3]; + } + } + } else if (yy == numCubesPerPart[1]-1) { // last cube in a partition in y dimension + if (odd) { + if (boundaryMaxy == 6 && numPartitions[1] == 1) { + elemNeighbors[c+3] -= numCubesPerPart[0]*numCubesPerPart[1]*5; + elemNeighbors[c+14] -= numCubesPerPart[0]*numCubesPerPart[1]*5; + } else { + elemNeighbors[c+3] = numElemPerPart[3]; + elemNeighbors[c+14] = numElemPerPart[3]; + } + } else { + if (boundaryMaxy == 6 && numPartitions[1] == 1) { + elemNeighbors[c+7] -= numCubesPerPart[0]*numCubesPerPart[1]*5; + elemNeighbors[c+13] -= numCubesPerPart[0]*numCubesPerPart[1]*5; + } else { + elemNeighbors[c+7] = numElemPerPart[3]; + elemNeighbors[c+13] = numElemPerPart[3]; + } + } + } + if (zz == 0) { // first cube in a partition in z dimension + if (odd) { + if (boundaryMinz == 6 && numPartitions[2] == 1) { + elemNeighbors[c+1] += numCubesPerPart[0]*numCubesPerPart[1]*numCubesPerPart[2]*5; + elemNeighbors[c+5] += numCubesPerPart[0]*numCubesPerPart[1]*numCubesPerPart[2]*5; + } else { + elemNeighbors[c+1] = numElemPerPart[3]; + elemNeighbors[c+5] = numElemPerPart[3]; + } + } else { + if (boundaryMinz == 6 && numPartitions[2] == 1) { + elemNeighbors[c] += numCubesPerPart[0]*numCubesPerPart[1]*numCubesPerPart[2]*5; + elemNeighbors[c+5] += numCubesPerPart[0]*numCubesPerPart[1]*numCubesPerPart[2]*5; + } else { + elemNeighbors[c] = numElemPerPart[3]; + elemNeighbors[c+5] = numElemPerPart[3]; + } + } + } else if (zz == numCubesPerPart[2]-1) { // last cube in a partition in z dimension + if (odd) { + if (boundaryMaxz == 6 && numPartitions[2] == 1) { + elemNeighbors[c+11] -= numCubesPerPart[0]*numCubesPerPart[1]*numCubesPerPart[2]*5; + elemNeighbors[c+15] -= numCubesPerPart[0]*numCubesPerPart[1]*numCubesPerPart[2]*5; + } else { + elemNeighbors[c+11] = numElemPerPart[3]; + elemNeighbors[c+15] = numElemPerPart[3]; + } + } else { + if (boundaryMaxz == 6 && numPartitions[2] == 1) { + elemNeighbors[c+11] -= numCubesPerPart[0]*numCubesPerPart[1]*numCubesPerPart[2]*5; + elemNeighbors[c+15] -= numCubesPerPart[0]*numCubesPerPart[1]*numCubesPerPart[2]*5; + } else { + elemNeighbors[c+11] = numElemPerPart[3]; + elemNeighbors[c+15] = numElemPerPart[3]; + } + } + } + } + } + } + + for (unsigned int i = 0; i < numPartitions[3]; i++) { + size_t start[3] = {i, 0, 0}; + size_t count[3] = {1, numElemPerPart[3], 4}; + checkNcError(nc_put_vara_int(ncFile, ncVarElemNeighbors, start, count, elemNeighbors)); + writes_done++; loadBar(writes_done, netcdf_writes); + } + delete [] elemNeighbors; + + int *elemBoundaries = new int[numElemPerPart[3]*4]; + for (unsigned int z = 0; z < numPartitions[2]; z++) { + for (unsigned int y = 0; y < numPartitions[1]; y++) { + for (unsigned int x = 0; x < numPartitions[0]; x++) { + memset(elemBoundaries, 0, sizeof(int)*numElemPerPart[3]*4); + + if (x == 0) { // first partition in x dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy) % 2; + if (odd) { + elemBoundaries[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20] = boundaryMinx; + elemBoundaries[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 10] = boundaryMinx; + } else { + elemBoundaries[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 2] = boundaryMinx; + elemBoundaries[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 12] = boundaryMinx; + } + } + } + } + if (x == numPartitions[0]-1) { // last partition in x dimension + + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy+1) % 2; + if (odd) { + elemBoundaries[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 7] = boundaryMaxx; + elemBoundaries[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 12] = boundaryMaxx; + } else { + elemBoundaries[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 6] = boundaryMaxx; + elemBoundaries[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 9] = boundaryMaxx; + } + } + } + } + if (y == 0) { // first partition in y dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+xx) % 2; + if (odd) { + elemBoundaries[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 6] = boundaryMiny; + elemBoundaries[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 9] = boundaryMiny; + } else { + elemBoundaries[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 1] = boundaryMiny; + elemBoundaries[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 10] = boundaryMiny; + } + } + } + } + if (y == numPartitions[1]-1) { // last partition in y dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+xx+1) % 2; + if (odd) { + elemBoundaries[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 3] = boundaryMaxy; + elemBoundaries[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 14] = boundaryMaxy; + } else { + elemBoundaries[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 7] = boundaryMaxy; + elemBoundaries[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 13] = boundaryMaxy; + } + } + } + } + if (z == 0) { // first partition in z dimension + #pragma omp parallel for + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (yy+xx) % 2; + if (odd) { + elemBoundaries[(yy*numCubesPerPart[0]+xx) * 20 + 1] = boundaryMinz; + elemBoundaries[(yy*numCubesPerPart[0]+xx) * 20 + 5] = boundaryMinz; + } else { + elemBoundaries[(yy*numCubesPerPart[0]+xx) * 20] = boundaryMinz; + elemBoundaries[(yy*numCubesPerPart[0]+xx) * 20 + 5] = boundaryMinz; + } + } + } + } + if (z == numPartitions[2]-1) { // last partition in z dimension + #pragma omp parallel for + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { +// int odd = (yy+xx+1) % 2; +// if (odd) { + elemBoundaries[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = boundaryMaxz; + elemBoundaries[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = boundaryMaxz; +// } else { +// elemBoundaries[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = boundaryMaxz; +// elemBoundaries[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = boundaryMaxz; +// } + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, 0, 0}; + size_t count[3] = {1, numElemPerPart[3], 4}; + checkNcError(nc_put_vara_int(ncFile, ncVarElemBoundaries, start, count, elemBoundaries)); + writes_done++; loadBar(writes_done, netcdf_writes); + } + } + } + delete [] elemBoundaries; + + int *elemNeighborSides = new int[numElemPerPart[3]*4]; + int *elemNeighborSidesDef = new int[numElemPerPart[3]*4]; + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+yy+xx) % 2; + unsigned int c = ((zz*numCubesPerPart[1] + yy)*numCubesPerPart[0] + xx) * 20; + memcpy(&elemNeighborSidesDef[c], TET_SIDE_NEIGHBORS[odd], sizeof(int)*20); + } + } + } + + for (unsigned int z = 0; z < numPartitions[2]; z++) { + for (unsigned int y = 0; y < numPartitions[1]; y++) { + for (unsigned int x = 0; x < numPartitions[0]; x++) { + memcpy(elemNeighborSides, elemNeighborSidesDef, sizeof(int)*numElemPerPart[3]*4); + + if (boundaryMinx != 6 && x == 0) { //first partition in x dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy) % 2; + if (odd) { + elemNeighborSides[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20] = 0; + elemNeighborSides[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 10] = 0; + } else { + elemNeighborSides[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 2] = 0; + elemNeighborSides[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 12] = 0; + } + } + } + } + if (boundaryMaxx != 6 && x == numPartitions[0]-1) { // last partition in x dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy+1) % 2; + if (odd) { + elemNeighborSides[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 7] = 0; + elemNeighborSides[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 12] = 0; + } else { + elemNeighborSides[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 6] = 0; + elemNeighborSides[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 9] = 0; + } + } + } + } + if (boundaryMiny != 6 && y == 0) { // first partition in y dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+xx) % 2; + if (odd) { + elemNeighborSides[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 6] = 0; + elemNeighborSides[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 9] = 0; + } else { + elemNeighborSides[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 1] = 0; + elemNeighborSides[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 10] = 0; + } + } + } + } + if (boundaryMaxy != 6 && y == numPartitions[1]-1) { // last partition in y dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+xx+1) % 2; + if (odd) { + elemNeighborSides[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 3] = 0; + elemNeighborSides[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 14] = 0; + } else { + elemNeighborSides[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 7] = 0; + elemNeighborSides[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 13] = 0; + } + } + } + } + if (boundaryMinz != 6 && z == 0) { // first partition in z dimension + #pragma omp parallel for + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (yy+xx) % 2; + if (odd) { + elemNeighborSides[(yy*numCubesPerPart[0]+xx) * 20 + 1] = 0; + elemNeighborSides[(yy*numCubesPerPart[0]+xx) * 20 + 5] = 0; + } else { + elemNeighborSides[(yy*numCubesPerPart[0]+xx) * 20] = 0; + elemNeighborSides[(yy*numCubesPerPart[0]+xx) * 20 + 5] = 0; + } + } + } + } + if (boundaryMaxz != 6 && z == numPartitions[2]-1) { // last partition in z dimension + #pragma omp parallel for + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { +// int odd = (yy+xx+1) % 2; +// if (odd) { + elemNeighborSides[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = 0; + elemNeighborSides[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = 0; +// } else { +// elemSideNeighbors[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = 0; +// elemSideNeighbors[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = 0; +// } + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, 0, 0}; + size_t count[3] = {1, numElemPerPart[3], 4}; + checkNcError(nc_put_vara_int(ncFile, ncVarElemNeighborSides, start, count, elemNeighborSides)); + writes_done++; loadBar(writes_done, netcdf_writes); + } + } + } + delete [] elemNeighborSides; + delete [] elemNeighborSidesDef; + + int *elemSideOrientations = new int[numElemPerPart[3]*4]; + int *elemSideOrientationsDef = new int[numElemPerPart[3]*4]; + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+yy+xx) % 2; + unsigned int c = ((zz*numCubesPerPart[1] + yy)*numCubesPerPart[0] + xx) * 20; + memcpy(&elemSideOrientationsDef[c], TET_SIDE_ORIENTATIONS[odd], sizeof(int)*20); + } + } + } + + for (unsigned int z = 0; z < numPartitions[2]; z++) { + for (unsigned int y = 0; y < numPartitions[1]; y++) { + for (unsigned int x = 0; x < numPartitions[0]; x++) { + memcpy(elemSideOrientations, elemSideOrientationsDef, sizeof(int)*numElemPerPart[3]*4); + + if (boundaryMinx != 6 && x == 0) { // first partition in x dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy) % 2; + if (odd) { + elemSideOrientations[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20] = 0; + elemSideOrientations[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 10] = 0; + } else { + elemSideOrientations[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 2] = 0; + elemSideOrientations[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 12] = 0; + } + } + } + } + if (boundaryMaxx != 6 && x == numPartitions[0]-1) { // last partition in x dimension + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy+1) % 2; + if (odd) { + elemSideOrientations[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 7] = 0; + elemSideOrientations[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 12] = 0; + } else { + elemSideOrientations[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 6] = 0; + elemSideOrientations[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 9] = 0; + } + } + } + } + // There are zero anyway +// if (boundaryMiny != 6 && y == 0) { // first partition in y dimension +// #pragma omp parallel for +// for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { +// for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { +// int odd = (zz+xx) % 2; +// if (odd) { +// elemSideOrientations[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 6] = 0; +// elemSideOrientations[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 9] = 0; +// } else { +// elemSideOrientations[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 1] = 0; +// elemSideOrientations[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 10] = 0; +// } +// } +// } +// } +// if (boundaryMaxy != 6 && y == numPartitions[1]-1) { // last partition in y dimension +// #pragma omp parallel for +// for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { +// for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { +// int odd = (zz+xx+1) % 2; +// if (odd) { +// elemSideOrientations[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 3] = 0; +// elemSideOrientations[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 14] = 0; +// } else { +// elemSideOrientations[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 7] = 0; +// elemSideOrientations[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 13] = 0; +// } +// } +// } +// } + if (boundaryMinz != 6 && z == 0) { // first partition in z dimension + #pragma omp parallel for + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (yy+xx) % 2; + if (odd) { + elemSideOrientations[(yy*numCubesPerPart[0]+xx) * 20 + 1] = 0; + elemSideOrientations[(yy*numCubesPerPart[0]+xx) * 20 + 5] = 0; + } else { + elemSideOrientations[(yy*numCubesPerPart[0]+xx) * 20] = 0; + elemSideOrientations[(yy*numCubesPerPart[0]+xx) * 20 + 5] = 0; + } + } + } + } + if (boundaryMaxz != 6 && z == numPartitions[2]-1) { // last partition in z dimension + #pragma omp parallel for + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { +// int odd = (yy+xx+1) % 2; +// if (odd) { + elemSideOrientations[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = 0; + elemSideOrientations[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = 0; +// } else { +// elemSideOrientations[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = 0; +// elemSideOrientations[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = 0; +// } + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, 0, 0}; + size_t count[3] = {1, numElemPerPart[3], 4}; + checkNcError(nc_put_vara_int(ncFile, ncVarElemSideOrientations, start, count, elemSideOrientations)); + writes_done++; loadBar(writes_done, netcdf_writes); + } + } + } + delete [] elemSideOrientations; + delete [] elemSideOrientationsDef; + + int *elemNeighborRanks = new int[numElemPerPart[3]*4]; + + for (unsigned int z = 0; z < numPartitions[2]; z++) { + for (unsigned int y = 0; y < numPartitions[1]; y++) { + for (unsigned int x = 0; x < numPartitions[0]; x++) { + int myrank = (z*numPartitions[1] + y)*numPartitions[0] + x; + + std::fill(elemNeighborRanks, elemNeighborRanks+numElemPerPart[3]*4, myrank); + + if ((boundaryMinx == 6 && numPartitions[0] > 1) || x != 0) { // first partition in x dimension + int rank = (z*numPartitions[1] + y)*numPartitions[0] + (x-1+numPartitions[0])%numPartitions[0]; + + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy) % 2; + if (odd) { + elemNeighborRanks[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20] = rank; + elemNeighborRanks[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 10] = rank; + } else { + elemNeighborRanks[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 2] = rank; + elemNeighborRanks[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 12] = rank; + } + } + } + } + if ((boundaryMaxx == 6 && numPartitions[0] > 1) || x != numPartitions[0]-1) { // last partition in x dimension + int rank = (z*numPartitions[1] + y)*numPartitions[0] + (x+1)%numPartitions[0]; + + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy+1) % 2; + if (odd) { + elemNeighborRanks[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 7] = rank; + elemNeighborRanks[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 12] = rank; + } else { + elemNeighborRanks[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 6] = rank; + elemNeighborRanks[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 9] = rank; + } + } + } + } + if ((boundaryMiny == 6 && numPartitions[1] > 1) || y != 0) { // first partition in y dimension + int rank = (z*numPartitions[1] + (y-1+numPartitions[1])%numPartitions[1])*numPartitions[0] + x; + + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+xx) % 2; + if (odd) { + elemNeighborRanks[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 6] = rank; + elemNeighborRanks[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 9] = rank; + } else { + elemNeighborRanks[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 1] = rank; + elemNeighborRanks[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 10] = rank; + } + } + } + } + if ((boundaryMaxy == 6 && numPartitions[1] > 1) || y != numPartitions[1]-1) { // last partition in y dimension + int rank = (z*numPartitions[1] + (y+1)%numPartitions[1])*numPartitions[0] + x; + + #pragma omp parallel for + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+xx+1) % 2; + if (odd) { + elemNeighborRanks[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 3] = rank; + elemNeighborRanks[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 14] = rank; + } else { + elemNeighborRanks[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 7] = rank; + elemNeighborRanks[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 13] = rank; + } + } + } + } + if ((boundaryMinz == 6 && numPartitions[2] > 1) || z != 0) { // first partition in z dimension + int rank = (((z-1+numPartitions[2])%numPartitions[2])*numPartitions[1] + y)*numPartitions[0] + x; + + #pragma omp parallel for + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (yy+xx) % 2; + if (odd) { + elemNeighborRanks[(yy*numCubesPerPart[0]+xx) * 20 + 1] = rank; + elemNeighborRanks[(yy*numCubesPerPart[0]+xx) * 20 + 5] = rank; + } else { + elemNeighborRanks[(yy*numCubesPerPart[0]+xx) * 20] = rank; + elemNeighborRanks[(yy*numCubesPerPart[0]+xx) * 20 + 5] = rank; + } + } + } + } + if ((boundaryMaxz == 6 && numPartitions[2] > 1) || z != numPartitions[2]-1) { // last partition in z dimension + int rank = (((z+1)%numPartitions[2])*numPartitions[1] + y)*numPartitions[0] + x; + + #pragma omp parallel for + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { +// int odd = (yy+xx+1) % 2; +// if (odd) { + elemNeighborRanks[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = rank; + elemNeighborRanks[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = rank; +// } else { +// elemNeighborRanks[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = rank; +// elemNeighborRanks[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = rank; +// } + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, 0, 0}; + size_t count[3] = {1, numElemPerPart[3], 4}; + checkNcError(nc_put_vara_int(ncFile, ncVarElemNeighborRanks, start, count, elemNeighborRanks)); + writes_done++; loadBar(writes_done, netcdf_writes); + } + } + } + delete [] elemNeighborRanks; + + int *elemMPIIndices = new int[numElemPerPart[3]*4]; + int *bndLocalIds = new int[*std::max_element(numBndElements, numBndElements+3)]; + + for (unsigned int z = 0; z < numPartitions[2]; z++) { + for (unsigned int y = 0; y < numPartitions[1]; y++) { + for (unsigned int x = 0; x < numPartitions[0]; x++) { + memset(elemMPIIndices, 0, sizeof(int)*numElemPerPart[3]*4); + + unsigned int bndSize = 0; + + if ((boundaryMinz == 6 && numPartitions[2] > 1) || z != 0) { // first partition in z dimension + int nextMPIIndex = 0; + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (yy+xx) % 2; + if (odd) { + bndLocalIds[nextMPIIndex] = (yy*numCubesPerPart[0]+xx) * 5 + 1; + elemMPIIndices[(yy*numCubesPerPart[0]+xx) * 20 + 5] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = (yy*numCubesPerPart[0]+xx) * 5; + elemMPIIndices[(yy*numCubesPerPart[0]+xx) * 20 + 1] = nextMPIIndex++; + } else { + bndLocalIds[nextMPIIndex] = (yy*numCubesPerPart[0]+xx) * 5; + elemMPIIndices[(yy*numCubesPerPart[0]+xx) * 20] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = (yy*numCubesPerPart[0]+xx) * 5 + 1; + elemMPIIndices[(yy*numCubesPerPart[0]+xx) * 20 + 5] = nextMPIIndex++; + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, bndSize, 0u}; + size_t count[3] = {1, 1, static_cast(nextMPIIndex)}; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemSize, start, &nextMPIIndex)); + int rank = (((z-1+numPartitions[2])%numPartitions[2])*numPartitions[1] + y)*numPartitions[0] + x; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemRank, start, &rank)); + checkNcError(nc_put_vara_int(ncFile, ncVarBndElemLocalIds, start, count, bndLocalIds)); + + bndSize++; + } + if ((boundaryMiny == 6 && numPartitions[1] > 1) || y != 0) { // first partition in y dimension + int nextMPIIndex = 0; + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+xx) % 2; + if (odd) { + bndLocalIds[nextMPIIndex] = (zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 5 + 1; + elemMPIIndices[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 6] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = (zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 5 + 2; + elemMPIIndices[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 9] = nextMPIIndex++; + } else { + bndLocalIds[nextMPIIndex] = (zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 5; + elemMPIIndices[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 1] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = (zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 5 + 2; + elemMPIIndices[(zz*numCubesPerPart[1]*numCubesPerPart[0]+xx) * 20 + 10] = nextMPIIndex++; + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, bndSize, 0u}; + size_t count[3] = {1, 1, static_cast(nextMPIIndex)}; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemSize, start, &nextMPIIndex)); + int rank = (z*numPartitions[1] + (y-1+numPartitions[1])%numPartitions[1])*numPartitions[0] + x; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemRank, start, &rank)); + checkNcError(nc_put_vara_int(ncFile, ncVarBndElemLocalIds, start, count, bndLocalIds)); + + bndSize++; + } + if ((boundaryMinx == 6 && numPartitions[0] > 1) || x != 0) { // first partition in x dimension + int nextMPIIndex = 0; + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy) % 2; + if (odd) { + bndLocalIds[nextMPIIndex] = (zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 5; + elemMPIIndices[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = (zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 5 + 2; + elemMPIIndices[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 10] = nextMPIIndex++; + } else { + bndLocalIds[nextMPIIndex] = (zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 5; + elemMPIIndices[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 2] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = (zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 5 + 3; + elemMPIIndices[(zz*numCubesPerPart[1]+yy)*numCubesPerPart[0] * 20 + 12] = nextMPIIndex++; + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, bndSize, 0u}; + size_t count[3] = {1, 1, static_cast(nextMPIIndex)}; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemSize, start, &nextMPIIndex)); + int rank = (z*numPartitions[1] + y)*numPartitions[0] + (x-1+numPartitions[0])%numPartitions[0]; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemRank, start, &rank)); + checkNcError(nc_put_vara_int(ncFile, ncVarBndElemLocalIds, start, count, bndLocalIds)); + + bndSize++; + } + if ((boundaryMaxx == 6 && numPartitions[0] > 1) || x != numPartitions[0]-1) { // last partition in x dimension + int nextMPIIndex = 0; + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + int odd = (zz+yy+1) % 2; + if (odd) { + bndLocalIds[nextMPIIndex] = ((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 5 + 1; + elemMPIIndices[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 7] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = ((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 5 + 3; + elemMPIIndices[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 12] = nextMPIIndex++; + } else { + bndLocalIds[nextMPIIndex] = ((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 5 + 1; + elemMPIIndices[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 6] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = ((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 5 + 2; + elemMPIIndices[((zz*numCubesPerPart[1]+yy)*numCubesPerPart[0]+numCubesPerPart[0]-1) * 20 + 9] = nextMPIIndex++; + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, bndSize, 0}; + size_t count[3] = {1, 1, static_cast(nextMPIIndex)}; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemSize, start, &nextMPIIndex)); + int rank = (z*numPartitions[1] + y)*numPartitions[0] + (x+1)%numPartitions[0]; + rank = (rank + numPartitions[3]) % numPartitions[3]; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemRank, start, &rank)); + checkNcError(nc_put_vara_int(ncFile, ncVarBndElemLocalIds, start, count, bndLocalIds)); + + bndSize++; + } + if ((boundaryMaxy == 6 && numPartitions[1] > 1) || y != numPartitions[1]-1) { // last partition in y dimension + int nextMPIIndex = 0; + for (unsigned int zz = 0; zz < numCubesPerPart[2]; zz++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { + int odd = (zz+xx+1) % 2; + if (odd) { + bndLocalIds[nextMPIIndex] = ((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 5; + elemMPIIndices[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 3] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = ((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 5 + 3; + elemMPIIndices[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 14] = nextMPIIndex++; + } else { + bndLocalIds[nextMPIIndex] = ((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 5 + 1; + elemMPIIndices[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 7] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = ((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 5 + 3; + elemMPIIndices[((zz*numCubesPerPart[1]+numCubesPerPart[1]-1)*numCubesPerPart[0]+xx) * 20 + 13] = nextMPIIndex++; + } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, bndSize, 0}; + size_t count[3] = {1, 1, static_cast(nextMPIIndex)}; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemSize, start, &nextMPIIndex)); + int rank = (z*numPartitions[1] + (y+1)%numPartitions[1])*numPartitions[0] + x; + rank = (rank + numPartitions[3]) % numPartitions[3]; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemRank, start, &rank)); + checkNcError(nc_put_vara_int(ncFile, ncVarBndElemLocalIds, start, count, bndLocalIds)); + + bndSize++; + } + if ((boundaryMaxz == 6 && numPartitions[2] > 1) || z != numPartitions[2]-1) { // last partition in z dimension + int nextMPIIndex = 0; + for (unsigned int yy = 0; yy < numCubesPerPart[1]; yy++) { + for (unsigned int xx = 0; xx < numCubesPerPart[0]; xx++) { +// int odd = (yy+xx+1) % 2; +// if (odd) { + bndLocalIds[nextMPIIndex] = (((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 5 + 2; + elemMPIIndices[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = nextMPIIndex++; + bndLocalIds[nextMPIIndex] = (((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 5 + 3; + elemMPIIndices[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = nextMPIIndex++; +// } else { +// bndLocalIds[nextMPIIndex] = (((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 5 + 2; +// elemMPIIndices[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 11] = nextMPIIndex++; +// bndLocalIds[nextMPIIndex] = (((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 5 + 3; +// elemMPIIndices[(((numCubesPerPart[2]-1)*numCubesPerPart[1]+yy)*numCubesPerPart[0]+xx) * 20 + 15] = nextMPIIndex++; +// } + } + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, bndSize, 0u}; + size_t count[3] = {1, 1, static_cast(nextMPIIndex)}; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemSize, start, &nextMPIIndex)); + int rank = (((z+1)%numPartitions[2])*numPartitions[1] + y)*numPartitions[0] + x; + rank = (rank + numPartitions[3]) % numPartitions[3]; + checkNcError(nc_put_var1_int(ncFile, ncVarBndElemRank, start, &rank)); + checkNcError(nc_put_vara_int(ncFile, ncVarBndElemLocalIds, start, count, bndLocalIds)); + + bndSize++; + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, 0, 0}; + size_t count[3] = {1, numElemPerPart[3], 4}; + checkNcError(nc_put_vara_int(ncFile, ncVarElemMPIIndices, start, count, elemMPIIndices)); + + checkNcError(nc_put_var1_uint(ncFile, ncVarBndSize, &start[0], &bndSize)); + writes_done++; loadBar(writes_done, netcdf_writes); + } + } + } + delete [] elemMPIIndices; + delete [] bndLocalIds; + + // Set material zone to 1 + int *elemGroup = new int[numElemPerPart[3]]; + std::fill(elemGroup, elemGroup + numElemPerPart[3], 1); + for (unsigned int x = 0; x < numPartitions[3]; x++) { + size_t start[2] = {x, 0}; + size_t count[2] = {1, numElemPerPart[3]}; + checkNcError(nc_put_vara_int(ncFile, ncVarElemGroup, start, count, elemGroup)); + } + delete[] elemGroup; + + // Vertices + std::map uniqueVertices; + transform(vertexMap.begin(), vertexMap.end(), + inserter(uniqueVertices, uniqueVertices.begin()), + flip_pair); + + int *vrtxSize = new int[numPartitions[3]]; + std::fill(vrtxSize, vrtxSize+numPartitions[3], uniqueVertices.size()); + checkNcError(nc_put_var_int(ncFile, ncVarVrtxSize, vrtxSize)); + delete [] vrtxSize; + writes_done++; loadBar(writes_done, netcdf_writes); + + double *vrtxCoords = new double[uniqueVertices.size()*3]; + + + double scale = args.getArgument("scale", 100.0); + double scaleX = args.getArgument("sx", scale); + double scaleY = args.getArgument("sy", scale); + double scaleZ = args.getArgument("sz", scale); + double halfWidthX = scaleX / 2.0; + double halfWidthY = scaleY / 2.0; + double halfWidthZ = scaleZ / 2.0; + + double tx = args.getArgument("tx", 0.0); + double ty = args.getArgument("ty", 0.0); + double tz = args.getArgument("tz", 0.0); + + for (unsigned int z = 0; z < numPartitions[2]; z++) { + for (unsigned int y = 0; y < numPartitions[1]; y++) { + for (unsigned int x = 0; x < numPartitions[0]; x++) { + + #pragma omp parallel for + for (unsigned int i = 0; i < uniqueVertices.size(); i++) { + vrtxCoords[i*3] = static_cast(uniqueVertices.at(i).v[0] + x*numCubesPerPart[0])/static_cast(numCubes[0])*scaleX - halfWidthX + tx; + vrtxCoords[i*3+1] = static_cast(uniqueVertices.at(i).v[1] + y*numCubesPerPart[1])/static_cast(numCubes[1])*scaleY - halfWidthY + ty; + vrtxCoords[i*3+2] = static_cast(uniqueVertices.at(i).v[2] + z*numCubesPerPart[2])/static_cast(numCubes[2])*scaleZ - halfWidthZ + tz; + } + + size_t start[3] = {(z*numPartitions[1] + y)*numPartitions[0] + x, 0, 0}; + size_t count[3] = {1, uniqueVertices.size(), 3}; + checkNcError(nc_put_vara_double(ncFile, ncVarVrtxCoords, start, count, vrtxCoords)); + writes_done++; loadBar(writes_done, netcdf_writes); + } + } + } + + delete [] vrtxCoords; + + checkNcError(nc_close(ncFile)); + + logInfo() << "Finished"; +} diff --git a/meshing/cube_c/src/utils/args.h b/meshing/cube_c/src/utils/args.h new file mode 100644 index 0000000..4b91490 --- /dev/null +++ b/meshing/cube_c/src/utils/args.h @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Sebastian Rettenberger (rettenbs AT in.tum.de, http://www5.in.tum.de/wiki/index.php/Sebastian_Rettenberger,_M.Sc.) + * + * @section LICENSE + * Copyright (c) SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + * TODO place this in the submodule folder + */ + +#ifndef UTILS_ARGS_H +#define UTILS_ARGS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace utils +{ + +/** + * Parses command line arguments + * @todo comment functions + */ +class Args +{ +private: + struct optionInfo { + std::string longOption; // We need a copy here to get the const char* correct + /** Name of the value in the help command */ + std::string value; + std::string description; + bool required; + }; + + struct additionalOptionInfo { + std::string name; + std::string description; + bool required; + }; + + /** + * Convert a long option into an "argument" that is shown in the help message + */ + struct valueConvert { + void operator()(char& c) + { + c = toupper(static_cast(c)); + switch (c) { + case '-': + c = '_'; + break; + } + } + }; + + /** Program description (can be empty) */ + const std::string m_description; + /** Automatically add help option */ + const bool m_addHelp; + + /** The command line arguments */ + std::vector m_options; + /** + * Additional information for the command line arguments + * required to generate help information + */ + std::vector m_optionInfo; + + std::vector m_additionalOptionInfo; + + /** Maps from short option to index in m_options */ + std::map m_short2option; + + /** Contains the arguments after parse was called */ + std::map m_arguments; + + /** + * Contains additional arguments after parse was called + * @todo Find a better name + */ + std::map m_additionalArguments; + +public: + enum Argument + { + Required = required_argument, + No = no_argument, + Optional = optional_argument + }; + + enum Result + { + Success = 0, + Error, + /** Help message printed */ + Help + }; + +public: + Args(const std::string &description = "", bool addHelp = true) + : m_description(description), + m_addHelp(addHelp) + { + } + + void addOption(const std::string &longOption, + char shortOption = 0, + const std::string &description = "", + Argument argument = Required, + bool required = true) + { + std::string value; + + if (shortOption) + m_short2option[shortOption] = m_options.size(); + + if (argument != No) { + value = longOption; + for_each(value.begin(), value.end(), valueConvert()); + } + + struct optionInfo i = {longOption, value, description, required}; + m_optionInfo.push_back(i); + + struct option o = {m_optionInfo.back().longOption.c_str(), argument, 0, shortOption}; + m_options.push_back(o); + } + + void addAdditionalOption(const std::string &name, + const std::string &description = "", + bool required = true) + { + if (!m_additionalOptionInfo.empty()) { + if (required && !m_additionalOptionInfo.back().required) + // After one optional argument there can only be more optional arguments + return; + } + + struct additionalOptionInfo i = {name, description, required}; + m_additionalOptionInfo.push_back(i); + } + + /** + * @return True of options are successfully parsed, false otherwise + */ + Result parse(int argc, char* const* argv, bool printHelp = true) + { + if (m_addHelp) + addOption("help", 'h', "Show this help message", No, false); + + std::ostringstream shortOptions; + for (std::vector::const_iterator i = m_options.begin(); + i != m_options.end(); i++) { + if (i->val != 0) { + shortOptions << static_cast(i->val); + switch (i->has_arg) + { + case required_argument: + shortOptions << ':'; + break; + case optional_argument: + shortOptions << "::"; + break; + } + } + } + + // Add null option + struct option o = {0, 0, 0, 0}; + m_options.push_back(o); + + // Update const char* in m_options + for (size_t i = 0; i < m_optionInfo.size(); i++) + m_options[i].name = m_optionInfo[i].longOption.c_str(); + + while (true) { + int optionIndex = 0; + + int c = getopt_long(argc, argv, shortOptions.str().c_str(), + &m_options[0], &optionIndex); + + if (c < 0) + break; + + switch (c) { + case '?': + if (printHelp) + helpMessage(argv[0], std::cerr); + return Error; + case 0: + // Nothing to do + break; + default: + optionIndex = m_short2option.at(c); + } + + if (optarg == 0L) + m_arguments[m_options[optionIndex].name] = ""; + else + m_arguments[m_options[optionIndex].name] = optarg; + } + + if (m_addHelp && isSet("help")) { + if (printHelp) + helpMessage(argv[0]); + return Help; + } + + for (std::vector::const_iterator i = m_optionInfo.begin(); + i != m_optionInfo.end(); i++) { + if (i->required && !isSet(i->longOption)) { + if (printHelp) { + std::cerr << argv[0] << ": option --" << i->longOption << " is required" << std::endl; + helpMessage(argv[0], std::cerr); + } + return Error; + } + } + + // Parse additional options and check if all required options are set + int i; + for (i = 0; i < argc-optind; i++) + m_additionalArguments[m_additionalOptionInfo[i].name] = argv[i+optind]; + if (static_cast(i) < m_additionalOptionInfo.size()) { + if (m_additionalOptionInfo[i].required) { + if (printHelp) { + std::cerr << argv[0] << ": option <" << m_additionalOptionInfo[i].name << "> is required" << std::endl; + helpMessage(argv[0], std::cerr); + } + return Error; + } + } + + return Success; + } + + bool isSet(const std::string &option) const + { + return m_arguments.find(option) != m_arguments.end(); + } + + bool isSetAdditional(const std::string &option) const + { + return m_additionalArguments.find(option) != m_additionalArguments.end(); + } + + template + T getArgument(const std::string &option) + { + std::istringstream ss(m_arguments.at(option)); + + T result; + ss >> result; + + return result; + } + + template + T getArgument(const std::string &option, T defaultArgument) + { + if (!isSet(option)) + return defaultArgument; + + return getArgument(option); + } + + + template + T getAdditionalArgument(const std::string &option) + { + std::istringstream ss(m_additionalArguments.at(option)); + + T result; + ss >> result; + + return result; + } + + template + T getAdditionalArgument(const std::string &option, T defaultArgument) + { + if (!isSetAdditional(option)) + return defaultArgument; + + return getAdditionalArgument(option); + } + + void helpMessage(const char* prog, std::ostream &out = std::cout) + { + // First line with all short options + out << "Usage: " << prog; + for (size_t i = 0; i < m_options.size()-1; i++) { + out << ' '; + + if (!m_optionInfo[i].required) + out << '['; + + if (m_options[i].val != 0) + out << '-' << static_cast(m_options[i].val); + else + out << "--" << m_options[i].name; + + argumentInfo(i, out); + + if (!m_optionInfo[i].required) + out << ']'; + } + for (size_t i = 0; i < m_additionalOptionInfo.size(); i++) { + out << ' '; + + if (!m_additionalOptionInfo[i].required) + out << '['; + + out << '<' << m_additionalOptionInfo[i].name << '>'; + + if (!m_additionalOptionInfo[i].required) + out << ']'; + + } + out << std::endl; + + // General program description + if (!m_description.empty()) + out << std::endl << m_description << std::endl; + + // Arguments + out << std::endl << "arguments:" << std::endl; + for (size_t i = 0; i < m_additionalOptionInfo.size(); i++) { + out << " <" << m_additionalOptionInfo[i].name << '>'; + + // Number of characters used for the option + size_t length = 4 + m_additionalOptionInfo[i].name.size(); + + if (length >= 30) { + out << std::endl; + out << std::setw(30) << ' '; + } else + out << std::setw(30-length) << ' '; + + out << m_additionalOptionInfo[i].description << std::endl; + } + + // Optional arguments + out << std::endl << "optional arguments:" << std::endl; + for (size_t i = 0; i < m_options.size()-1; i++) { + out << " "; + + // Number of characters used for the option + size_t length = 2; + + if (m_options[i].val != 0) { + out << '-' << static_cast(m_options[i].val); + out << ", "; + length += 4; + } + + out << "--" << m_options[i].name; + length += m_optionInfo[i].longOption.size() + 2; + length += argumentInfo(i, out); + + if (length >= 30) { + out << std::endl; + out << std::setw(30) << ' '; + } else + out << std::setw(30-length) << ' '; + + out << m_optionInfo[i].description << std::endl; + } + } + +private: + /** + * Writes the argument information to out + * + * @param i The index of the option for which the argument should be generated + * @return The number if characters written + */ + size_t argumentInfo(size_t i, std::ostream &out) + { + switch (m_options[i].has_arg) { + case required_argument: + out << ' ' << m_optionInfo[i].value; + return m_optionInfo[i].value.size() + 1; + case optional_argument: + out << " [" << m_optionInfo[i].value << ']'; + return m_optionInfo[i].value.size() + 3; + } + + return 0; + } +}; + +template<> inline +std::string utils::Args::getArgument(const std::string &option) +{ + return m_arguments.at(option); +} + +template<> inline +std::string utils::Args::getAdditionalArgument(const std::string &option) +{ + return m_additionalArguments.at(option); +} + +} + +#endif // UTILS_ARGS_H diff --git a/meshing/gmsh2gambit/README.md b/meshing/gmsh2gambit/README.md new file mode 100644 index 0000000..fa51fd9 --- /dev/null +++ b/meshing/gmsh2gambit/README.md @@ -0,0 +1,19 @@ +gmsh2gambit +=========== + +Transform msh file (gmsh msh 2.0 mesh file) to neu file (neutral mesh file) +From gmsh 4.0, the option '-format neu' of gmsh should be used instead. + +Build +----- + +```bash +export CC=gcc (or icpc with intel) +export CXX=g++ (or icc with intel) +scons +``` + +Use +--- + +gmsh2gambit -i test.msh -o test.neu diff --git a/meshing/gmsh2gambit/SConstruct b/meshing/gmsh2gambit/SConstruct new file mode 100644 index 0000000..05b6c99 --- /dev/null +++ b/meshing/gmsh2gambit/SConstruct @@ -0,0 +1,97 @@ +#! /usr/bin/python +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) +# +# @section LICENSE +# Copyright (c) 2015, SeisSol Group +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# @section DESCRIPTION +# + +import os + +# +# set possible variables +# +vars = Variables() + +vars.AddVariables( + PathVariable( 'buildDir', 'where to build the code', 'build', PathVariable.PathIsDirCreate ), + + EnumVariable( 'compileMode', 'mode of the compilation', 'release', + allowed_values=('debug', 'release') + ) +) + +# set environment +env = Environment(variables=vars, CC=os.environ['CC'], CXX=os.environ['CXX']) +env['ENV'] = os.environ + +# generate help text +Help(vars.GenerateHelpText(env)) + +# handle unknown, maybe misspelled variables +unknownVariables = vars.UnknownVariables() + +# exit in the case of unknown variables +if unknownVariables: + raise EnvironmentError("*** The following build variables are unknown: " + str(unknownVariables.keys())) + + +# +# precompiler, compiler and linker flags +# +env.Append(CXXFLAGS=['--std=c++11']) +if env['compileMode'] == 'debug': + env.Append(CXXFLAGS=['-O0','-g']) +elif env['compileMode'] == 'release': + env.Append(CPPDEFINES=['NDEBUG']) + env.Append(CXXFLAGS=['-O2']) + +# add pathname to the list of directories which are search for include +env.Append(CPPPATH=['#/src', '#../../submodules']) + +# build directory +env['execDir'] = env['buildDir']+'/bin' +env['buildDir'] = env['buildDir'] + +# get the source files +env.sourceFiles = [] + +Export('env') +SConscript('src/SConscript', variant_dir='#/'+env['buildDir'], src_dir='#/', duplicate=0) +Import('env') + +# build executable +env.Program('#/'+env['execDir']+'/gmsh2gambit', env.sourceFiles) diff --git a/meshing/gmsh2gambit/src/GAMBITWriter.cpp b/meshing/gmsh2gambit/src/GAMBITWriter.cpp new file mode 100644 index 0000000..fc613d6 --- /dev/null +++ b/meshing/gmsh2gambit/src/GAMBITWriter.cpp @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "GAMBITWriter.h" + +template<> unsigned const GambitInfo<2>::Type = 3; +template<> unsigned const GambitInfo<3>::Type = 6; diff --git a/meshing/gmsh2gambit/src/GAMBITWriter.h b/meshing/gmsh2gambit/src/GAMBITWriter.h new file mode 100644 index 0000000..985d3d2 --- /dev/null +++ b/meshing/gmsh2gambit/src/GAMBITWriter.h @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ +#ifndef GAMBITWRITER_H_ +#define GAMBITWRITER_H_ +#include +#include + +#include "GMSH.h" + +template +struct GambitInfo { + static unsigned const Type; +}; + +template +void writeNEU(char const* filename, GMSH const& msh) { + FILE* file; + file = fopen(filename, "w"); + fprintf(file, " CONTROL INFO 2.0.0\n"); + fprintf(file, "** GAMBIT NEUTRAL FILE\n"); + fprintf(file, "Gmsh mesh in GAMBIT neutral file format\n"); + fprintf(file, "PROGRAM: Gambit VERSION: 2.0.0\n"); + time_t rawtime; + struct tm* timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + char datestring[256]; + strftime(datestring, sizeof(datestring), "%c", timeinfo); + fprintf(file, "%s\n", datestring); + fprintf(file, " NUMNP NELEM NGRPS NBSETS NDFCD NDFVL\n"); + fprintf(file, " %9d %9d %9d %9d %9d %9d\n", msh.numVertices, msh.numElements, msh.materialGroups.size(), msh.boundaryConditions.size(), DIM, DIM); + fprintf(file, "ENDOFSECTION\n"); + + // Vertices + fprintf(file, " NODAL COORDINATES 2.0.0\n"); + for (unsigned vertex = 0; vertex < msh.numVertices; ++vertex) { + fprintf(file, "%10d", vertex+1); + for (unsigned c = 0; c < DIM; ++c) { + fprintf(file, "%20.11e", msh.vertices[vertex][c]); + } + fprintf(file, "\n"); + } + fprintf(file, "ENDOFSECTION\n"); + + // Elements + fprintf(file, " ELEMENTS/CELLS 2.0.0\n"); + for (unsigned element = 0; element < msh.numElements; ++element) { + fprintf(file, "%8d %2d %2d ", element+1, GambitInfo::Type, GMSH::Element::NumNodes); + for (unsigned n = 0; n < GMSH::Element::NumNodes; ++n) { + fprintf(file, "%8d", msh.elements[element].nodes[n]+1); + } + fprintf(file, "\n"); + } + fprintf(file, "ENDOFSECTION\n"); + + // Material groups + for (auto group = msh.materialGroups.cbegin(); group != msh.materialGroups.cend(); ++group) { + fprintf(file, " ELEMENT GROUP 2.0.0\n"); + fprintf(file, "GROUP: %10d ELEMENTS: %10d MATERIAL: %10d NFLAGS: %10d\n", group->first, group->second.size(), 2, 1); + fprintf(file, "Material group %d\n", group->first); + fprintf(file, " 0"); + for (unsigned gm = 0; gm < group->second.size(); ++gm) { + if (gm % 10 == 0) { + fprintf(file, "\n"); + } + fprintf(file, "%8d", group->second[gm]+1); + } + fprintf(file, "\n"); + fprintf(file, "ENDOFSECTION\n"); + } + + // Boundary conditions + for (auto boundaryCondition = msh.boundaryConditions.cbegin(); boundaryCondition != msh.boundaryConditions.cend(); ++boundaryCondition) { + fprintf(file, " BOUNDARY CONDITIONS 2.0.0\n"); + // collect members in group + fprintf(file, "%32d%8d%8d%8d%8d\n", boundaryCondition->first, 1, boundaryCondition->second.size(), 0, 6); + for (auto boundary = boundaryCondition->second.begin(); boundary < boundaryCondition->second.end(); ++boundary) { + fprintf(file, "%10d %5d %5d\n", boundary->element+1, GambitInfo::Type, boundary->side+1); + } + fprintf(file, "ENDOFSECTION\n"); + } + + fclose(file); +} + + + +#endif diff --git a/meshing/gmsh2gambit/src/GMSH.cpp b/meshing/gmsh2gambit/src/GMSH.cpp new file mode 100644 index 0000000..085a9f7 --- /dev/null +++ b/meshing/gmsh2gambit/src/GMSH.cpp @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "GMSH.h" + +#include +#include + +void error(std::string const& errMessage) +{ + std::cerr << "MSH parse error: " << errMessage << std::endl; + exit(-1); +} + +// Uses GAMBIT neu conventions. See GAMBIT NEUTRAL FILE FORMAT Appendix C.2. +template<> unsigned const Simplex<2>::Face2Nodes[][2] = {{0, 1}, {1, 2}, {2, 0}}; +template<> unsigned const Simplex<3>::Face2Nodes[][3] = {{1, 0, 2}, {0, 1, 3}, {1, 2, 3}, {2, 0, 3}}; diff --git a/meshing/gmsh2gambit/src/GMSH.h b/meshing/gmsh2gambit/src/GMSH.h new file mode 100644 index 0000000..dfa3c14 --- /dev/null +++ b/meshing/gmsh2gambit/src/GMSH.h @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ +#ifndef GMSH_H_ +#define GMSH_H_ + +#include +#include +#include +#include + +#define MAX_NUMBER_OF_TAGS 16 + +template +struct Simplex { + /* According to MSH mesh format documentation: + * 1 = 2-node line. + * 2 = 3-node triangle. + * 4 = 4-node tetrahedron. + * Will not work for other types (e.g. 11 = 10-node second order tetrahedron). + */ + static unsigned const Type = 1 << (N-1); + static unsigned const NumNodes = N+1; + static unsigned const NumFaces = N+1; + /* Each N-simplex includes N+1 (N-1)-simplices where each has DIM nodes + * E.g. Triangle (N=2): 3 lines with 2 nodes each + * Tetrahedron (N=3): 4 triangles with 3 nodes each */ + static unsigned const Face2Nodes[N+1][N]; + + unsigned nodes[NumNodes]; + unsigned group; +}; + +struct Boundary { + unsigned element; + unsigned side; +}; + +template +struct GMSH { + typedef Simplex Element; + typedef Simplex Face; + + double (*vertices)[3]; + Element* elements; + unsigned numVertices; + unsigned numElements; + std::unordered_map< unsigned, std::vector > materialGroups; + std::unordered_map< unsigned, std::vector > boundaryConditions; + + explicit GMSH(char const* filename); + + ~GMSH() { + delete[] vertices; + delete[] elements; + } +}; + +void error(std::string const& errMessage); + +template +GMSH::GMSH(char const* filename) +{ + numVertices = 0; + numElements = 0; + + Face* faces = NULL; + unsigned numFaces = 0; + + std::ifstream in(filename, std::ifstream::in); + + unsigned tags[MAX_NUMBER_OF_TAGS]; + + // Parse MSH + while (in.good()) { + std::string block; + in >> block; + if (block.compare("$Nodes") == 0) { + in >> numVertices; + vertices = new double[numVertices][3]; + for (unsigned vertex = 0; vertex < numVertices; ++vertex) { + unsigned id; + double x, y, z; + in >> id >> x >> y >> z; + if (id-1 != vertex) { + error("Ids are not contiguous."); + } + vertices[vertex][0] = x; + vertices[vertex][1] = y; + vertices[vertex][2] = z; + } + } else if (block.compare("$Elements") == 0) { + unsigned numGeoShapes; + in >> numGeoShapes; + faces = new Face[numGeoShapes]; + elements = new Element[numGeoShapes]; + + for (unsigned geoShape = 0; geoShape < numGeoShapes; ++geoShape) { + unsigned id, type, numTags; + in >> id >> type >> numTags; + if (type != Face::Type && type != Element::Type) { + error("Unsuported type. Must be 1 (line, 2D), 2 (triangle, 2D and 3D), or 4 (tetrahedron, 3D)."); + } + if (numTags > MAX_NUMBER_OF_TAGS) { + error("Too many tags. Increase MAX_NUMBER_OF_TAGS."); + } + for (unsigned tag = 0; tag < numTags; ++tag) { + in >> tags[tag]; + } + if (type == Face::Type) { + Face& face = faces[numFaces++]; + for (unsigned node = 0; node < Face::NumNodes; ++node) { + in >> face.nodes[node]; + --face.nodes[node]; + } + face.group = tags[0]; + } else if (type == Element::Type) { + Element& element = elements[numElements]; + for (unsigned node = 0; node < Element::NumNodes; ++node) { + in >> element.nodes[node]; + --element.nodes[node]; + } + element.group = tags[0]; + materialGroups[element.group].push_back(numElements); + ++numElements; + } + } + } + } + + in.close(); + + // vertex to triangle map + std::vector* vertex2face = vertex2face = new std::vector[numVertices]; + for (unsigned face = 0; face < numFaces; ++face) { + for (unsigned node = 0; node < Face::NumNodes; ++node) { + vertex2face[faces[face].nodes[node]].push_back(face); + } + } + for (unsigned vertex = 0; vertex < numVertices; ++vertex) { + std::sort(vertex2face[vertex].begin(), vertex2face[vertex].end()); + } + + for (unsigned element = 0; element < numElements; ++element) { + for (unsigned elmtFace = 0; elmtFace < Element::NumFaces; ++elmtFace) { + unsigned nodes[Face::NumNodes]; + for (unsigned node = 0; node < Face::NumNodes; ++node) { + nodes[node] = elements[element].nodes[ Element::Face2Nodes[elmtFace][node] ]; + } + std::vector intersect[Face::NumNodes-1]; + std::set_intersection( vertex2face[ nodes[0] ].begin(), vertex2face[ nodes[0] ].end(), + vertex2face[ nodes[1] ].begin(), vertex2face[ nodes[1] ].end(), + std::back_inserter(intersect[0]) ); + for (unsigned node = 2; node < Face::NumNodes; ++node) { + std::set_intersection( intersect[node-2].begin(), intersect[node-2].end(), + vertex2face[ nodes[node] ].begin(), vertex2face[ nodes[node] ].end(), + std::back_inserter(intersect[node-1]) ); + } + if (!intersect[Face::NumNodes-2].empty()) { + if (intersect[Face::NumNodes-2].size() > 1) { + error("A face of an element exists multiple times in the surface mesh."); + } + Face& face = faces[ intersect[Face::NumNodes-2][0] ]; + Boundary bnd; + bnd.element = element; + bnd.side = elmtFace; + boundaryConditions[face.group].push_back(bnd); + } + } + } + + delete[] vertex2face; + delete[] faces; +} + +#endif diff --git a/meshing/gmsh2gambit/src/SConscript b/meshing/gmsh2gambit/src/SConscript new file mode 100644 index 0000000..da01fa3 --- /dev/null +++ b/meshing/gmsh2gambit/src/SConscript @@ -0,0 +1,50 @@ +#! /usr/bin/python +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) +# +# @section LICENSE +# Copyright (c) 2015, SeisSol Group +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# @section DESCRIPTION +# + +Import('env') + +env.sourceFiles.extend([ + env.Object('main.cpp'), + env.Object('GMSH.cpp'), + env.Object('GAMBITWriter.cpp') +]) + +Export('env') diff --git a/meshing/gmsh2gambit/src/main.cpp b/meshing/gmsh2gambit/src/main.cpp new file mode 100644 index 0000000..a2f4a2a --- /dev/null +++ b/meshing/gmsh2gambit/src/main.cpp @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "GMSH.h" +#include "GAMBITWriter.h" + +#include +#include + +template +void convert(std::string const& in, std::string const& out) { + std::cout << "Reading MSH..." << std::flush; + GMSH msh(in.c_str()); + std::cout << "finished." << std::endl; + std::cout << "Writing NEU..." << std::flush; + writeNEU(out.c_str(), msh); + std::cout << "finished." << std::endl; +} + +int main(int argc, char** argv) +{ + utils::Args args; + args.addOption("dim", 'd', "Dimension (Defaults to 3, put 2 here for SeisSol 2D)", utils::Args::Required, false); + args.addOption("input", 'i', "Input file (.msh)"); + args.addOption("output", 'o', "Output file (.neu)"); + + if (args.parse(argc, argv) == utils::Args::Success) { + unsigned dim = args.getArgument("dim", 3); + std::string in = args.getArgument("input"); + std::string out = args.getArgument("output"); + + std::cout << "Reading MSH..." << std::flush; + switch (dim) { + case 3: + convert<3>(in, out); + break; + case 2: + std::cerr << "Warning: The z-coordinate will be ignored. If your mesh is not parallel to the z=0 plane, you will be in trouble." << std::endl; + convert<2>(in, out); + break; + default: + std::cerr << "Error: Only dim=2 and dim=3 are supported." << std::endl; + break; + } + } else { + return -1; + } + + return 0; +} diff --git a/meshing/gmsh_example/planar-anydip.geo b/meshing/gmsh_example/planar-anydip.geo new file mode 100644 index 0000000..4d011a1 --- /dev/null +++ b/meshing/gmsh_example/planar-anydip.geo @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* +/** + * @file + * This file is part of SeisSol. + * + * @author Thomas Ulrich + * + * @section LICENSE + * Copyright (c) 2014-2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + +19.02.2016 +Create a planar fault of given dimension and dip angle, the nucleation is also included in the geometry +To use obtain the mesh: +gmsh planar-anydip.geo -3 -optimize +To convert the mesh: +gmsh2gambit -i planar-anydip.msh -o planar-anydip.neu + + */ + + +lc = 25e3; +lc_fault = 300; + +Fault_length = 40e3; +Fault_width = 20e3; +Fault_dip = 60*Pi/180.; + +//Nucleation in X,Z local coordinates +X_nucl = 0e3; +Width_nucl = 0.5*Fault_width; +R_nucl = 2e3; +lc_nucl = 100; + +Xmax = 60e3; +Xmin = -Xmax; +Ymin = -Xmax + 0.5 * Fault_width *Cos(Fault_dip); +Ymax = Xmax + 0.5 * Fault_width *Cos(Fault_dip); +Zmin = -Xmax; + + +//Create the Volume +Point(1) = {Xmin, Ymin, 0, lc}; +Point(2) = {Xmin, Ymax, 0, lc}; +Point(3) = {Xmax, Ymax, 0, lc}; +Point(4) = {Xmax, Ymin, 0, lc}; +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 1}; +Line Loop(5) = {1,2,3,4}; +Plane Surface(1) = {5}; +Extrude {0,0, Zmin} { Surface{1}; } + +//Create the fault +Point(100) = {-0.5*Fault_length, Fault_width *Cos(Fault_dip), -Fault_width *Sin(Fault_dip), lc}; +Point(101) = {-0.5*Fault_length, 0, 0e3, lc}; +Point(102) = {0.5*Fault_length, 0, 0e3, lc}; +Point(103) = {0.5*Fault_length, Fault_width *Cos(Fault_dip), -Fault_width *Sin(Fault_dip), lc}; +Line(100) = {100, 101}; +Line(101) = {101, 102}; +Line{101} In Surface{1}; +Line(102) = {102, 103}; +Line(103) = {103, 100}; + +//create nucleation patch +Point(200) = {X_nucl, Width_nucl*Cos(Fault_dip), -Width_nucl *Sin(Fault_dip), lc_nucl}; +Point(201) = {X_nucl, (Width_nucl + R_nucl) * Cos(Fault_dip), -(Width_nucl+R_nucl) *Sin(Fault_dip), lc_nucl}; +Point(202) = {X_nucl + R_nucl, Width_nucl*Cos(Fault_dip), -Width_nucl *Sin(Fault_dip), lc_nucl}; +Point(203) = {X_nucl, (Width_nucl - R_nucl) * Cos(Fault_dip), -(Width_nucl-R_nucl) *Sin(Fault_dip), lc_nucl}; +Point(204) = {X_nucl - R_nucl, Width_nucl*Cos(Fault_dip), -Width_nucl *Sin(Fault_dip), lc_nucl}; +Circle(200) = {201,200,202}; +Circle(201) = {202,200,203}; +Circle(202) = {203,200,204}; +Circle(203) = {204,200,201}; +Line Loop(204) = {200,201,202,203}; +Plane Surface(200) = {204}; + +Line Loop(105) = {100,101,102,103,200,201,202,203}; +Plane Surface(100) = {105}; + +//There is a bug in "Attractor", we need to define a Ruled surface in FaceList +Line Loop(106) = {100,101,102,103}; +Ruled Surface(101) = {106}; +Ruled Surface(201) = {204}; + +Surface{100,200} In Volume{1}; + + +//1.2 Managing coarsening away from the fault +// Attractor field returns the distance to the curve (actually, the +// distance to 100 equidistant points on the curve) +Field[1] = Attractor; +Field[1].FacesList = {101}; + +// Matheval field returns "distance squared + lc/20" +Field[2] = MathEval; +//Field[2].F = Sprintf("0.02*F1 + 0.00001*F1^2 + %g", lc_fault); +//Field[2].F = Sprintf("0.02*F1 +(F1/2e3)^2 + %g", lc_fault); +Field[2].F = Sprintf("0.05*F1 +(F1/2.5e3)^2 + %g", lc_fault); + +//3.4.5 Managing coarsening around the nucleation Patch +Field[3] = Attractor; +Field[3].FacesList = {201}; + +Field[4] = Threshold; +Field[4].IField = 3; +Field[4].LcMin = lc_nucl; +Field[4].LcMax = lc_fault; +Field[4].DistMin = R_nucl; +Field[4].DistMax = 3*R_nucl; + +Field[5] = Restrict; +Field[5].IField = 4; +Field[5].FacesList = {100,200} ; + +//equivalent of propagation size on element +Field[6] = Threshold; +Field[6].IField = 1; +Field[6].LcMin = lc_fault; +Field[6].LcMax = lc; +Field[6].DistMin = 2*lc_fault; +Field[6].DistMax = 2*lc_fault+0.001; + + +Field[7] = Min; +Field[7].FieldsList = {2,5,6}; + + +Background Field = 7; + +Physical Surface(101) = {1}; +Physical Surface(103) = {100,200}; +//This ones are read in the gui +Physical Surface(105) = {14,18,22,26,27}; + +Physical Volume(1) = {1}; diff --git a/meshing/gmsh_example/tpv33_half.geo b/meshing/gmsh_example/tpv33_half.geo new file mode 100644 index 0000000..28b5d12 --- /dev/null +++ b/meshing/gmsh_example/tpv33_half.geo @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: BSD-3-Clause + +lc= 5000; +lc_fault = 100; + +Point(1) = {-50000, 0, -50000, lc}; +Point(2) = {-50000, 0, 0, lc}; +Point(3) = {50000, 0, 0, lc}; +Point(4) = {50000, 0, -50000, lc}; +Point(100) = {-12000, 0, -10000, lc}; +Point(101) = {4000, 0, -10000, lc}; +Point(102) = {4000, 0, 0, lc}; +Point(103) = {-12000, 0, 0, lc}; +Point(200) = {-6000, 0, -6000, lc_fault}; +Point(201) = {-6000, 0, -5450, lc_fault}; +Point(202) = {-5450, 0, -6000, lc_fault}; +Point(203) = {-6000, 0, -6550, lc_fault}; +Point(204) = {-6550, 0, -6000, lc_fault}; +Point(211) = {-6000, 0, -5200, lc_fault}; +Point(212) = {-5200, 0, -6000, lc_fault}; +Point(213) = {-6000, 0, -6800, lc_fault}; +Point(214) = {-6800, 0, -6000, lc_fault}; +Point(1001) = {-50000, 800, -50000, lc}; +Point(1002) = {-50000, 800, 0, lc}; +Point(1003) = {50000, 800, 0, lc}; +Point(1004) = {50000, 800, -50000, lc}; +Point(1011) = {-50000, 50000, -50000, lc}; +Point(1012) = {-50000, 50000, 0, lc}; +Point(1013) = {50000, 50000, 0, lc}; +Point(1014) = {50000, 50000, -50000, lc}; +Point(1100) = {-12000, 800, -10000, lc}; +Point(1101) = {4000, 800, -10000, lc}; +Point(1102) = {4000, 800, 0, lc}; +Point(1103) = {-12000, 800, 0, lc}; +Line(1) = {1, 2}; +Line(2) = {2, 103}; +Line(3) = {103, 100}; +Line(4) = {100, 101}; +Line(5) = {101, 102}; +Line(6) = {102, 3}; +Line(7) = {3, 4}; +Line(8) = {4, 1}; +Line(9) = {103, 102}; +Circle(200) = {201, 200, 202}; +Circle(201) = {202, 200, 203}; +Circle(202) = {203, 200, 204}; +Circle(203) = {204, 200, 201}; +Circle(210) = {211, 200, 212}; +Circle(211) = {212, 200, 213}; +Circle(212) = {213, 200, 214}; +Circle(213) = {214, 200, 211}; +Line(216) = {2, 1002}; +Line(217) = {1002, 1012}; +Line(218) = {3, 1003}; +Line(219) = {1003, 1013}; +Line(220) = {4, 1004}; +Line(221) = {1004, 1014}; +Line(222) = {1014, 1013}; +Line(223) = {1004, 1003}; +Line(224) = {1003, 1102}; +Line(225) = {1103, 1102}; +Line(226) = {1102, 1101}; +Line(227) = {1101, 1100}; +Line(228) = {1100, 1103}; +Line(229) = {101, 1101}; +Line(230) = {102, 1102}; +Line(231) = {103, 1103}; +Line(232) = {1103, 1002}; +Line(233) = {1001, 1}; +Line(234) = {1004, 1001}; +Line(235) = {1011, 1012}; +Line(236) = {1013, 1012}; +Line(237) = {1011, 1014}; +Line(238) = {1011, 1001}; +Line(239) = {100, 1100}; +Line(240) = {1001, 1002}; +Line Loop(1) = {1, 2, 3, 4, 5, 6, 7, 8}; +Plane Surface(1) = {1}; +Line Loop(2) = {3, 4, 5, -9, 210, 211, 212, 213}; +Plane Surface(2) = {2}; +Line Loop(3) = {210, 211, 212, 213, 200, 201, 202, 203}; +Plane Surface(3) = {3}; +Line Loop(4) = {200, 201, 202, 203}; +Plane Surface(4) = {4}; +Line Loop(242) = {1, 216, -240, 233}; +Plane Surface(242) = {242}; +Line Loop(244) = {238, 240, 217, -235}; +Plane Surface(244) = {244}; +Line Loop(246) = {238, -234, 221, -237}; +Plane Surface(246) = {246}; +Line Loop(248) = {234, 233, -8, 220}; +Plane Surface(248) = {248}; +Line Loop(250) = {237, 222, 236, -235}; +Plane Surface(250) = {250}; +Line Loop(252) = {217, -236, -219, 224, -225, 232}; +Plane Surface(252) = {252}; +Line Loop(254) = {221, 222, -219, -223}; +Plane Surface(254) = {254}; +Line Loop(256) = {220, 223, -218, 7}; +Plane Surface(256) = {256}; +Line Loop(258) = {6, 218, 224, -230}; +Plane Surface(258) = {258}; +Line Loop(260) = {9, 230, -225, -231}; +Plane Surface(260) = {260}; +Line Loop(262) = {216, -232, -231, -2}; +Plane Surface(262) = {262}; +Line Loop(264) = {228, -231, 3, 239}; +Plane Surface(264) = {264}; +Line Loop(266) = {227, -239, 4, 229}; +Plane Surface(266) = {266}; +Line Loop(268) = {229, -226, -230, -5}; +Plane Surface(268) = {268}; +Line Loop(270) = {234, 240, -232, -228, -227, -226, -224, -223}; +Plane Surface(270) = {270}; +Line Loop(272) = {228, 225, 226, 227}; +Plane Surface(272) = {272}; +Line Loop(10000) = {3, 4, 5, -9}; +Ruled Surface(10000) = {10000}; +Surface Loop(274) = {244, 246, 254, 250, 252, 270, 272}; +Volume(274) = {274}; +Surface Loop(276) = {272, 268, 266, 264, 2, 260, 3, 4}; +Volume(276) = {276}; +Surface Loop(278) = {1, 242, 262, 248, 256, 258, 270, 268, 266, 264}; +Volume(278) = {278}; +Field[1] = Attractor; +Field[1].FacesList = {10000}; +Field[1].FieldX = -1; +Field[1].FieldY = -1; +Field[1].FieldZ = -1; +Field[1].NNodesByEdge = 20; +Field[2] = MathEval; +//Field[2].F = Sprintf("0.05*F1 +(F1/2.5e3)^2 + %g", lc_fault); +Field[2].F = Sprintf("0.1*F1 +(F1/5.0e3)^2 + %g", lc_fault); +Background Field = 2; + +Physical Surface(101) = {252, 258, 260, 262}; +Physical Surface(105) = {242, 244, 246, 248, 250, 254, 256}; +Physical Surface(103) = {2, 3, 4}; +Physical Volume(2) = {276,278}; +Physical Volume(3) = {274}; diff --git a/science/Create_Matterhorn.m b/science/Create_Matterhorn.m new file mode 100644 index 0000000..f7de6cd --- /dev/null +++ b/science/Create_Matterhorn.m @@ -0,0 +1,139 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% +% @section LICENSE +% Copyright (c) 2005, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +clear, close all, home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% create Matterhorn %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') + +% Parameters to Edit + +nx =41; +ny =41; +load mmma50.xyz +a = mmma50; +fid = fopen('matterhorn50.jou','w'); + +x = reshape(a(:,1),nx,ny); +y = reshape(a(:,2),nx,ny); y = fliplr(y); +z = reshape(a(:,3),nx,ny); z = fliplr(z); + +disp(sprintf('Minimum elevation: %g',min(min(a(:,3))))); +disp(sprintf('Maximum elevation: %g',max(max(a(:,3))))); +d = input('Give bottom elevation: '); + +% Verschiebe die linke untere Ecke in den Koordinatenursprung + +x0 = min(min(x(:,:))); +y0 = min(min(y(:,:))); + +x(:,:) = x(:,:) - x0; +y(:,:) = y(:,:) - y0; + +dx = abs(x(1)-x(2))*1; + +fprintf(fid,'/ File opened for write %s.\n',datestr(now)); +fprintf(fid,'identifier name "matterhorn" new nosaveprevious \n'); + +%Create surface vertices +counter = 0; +for j = 1:ny + for i = 1:nx + counter = counter + 1; + fprintf(fid,'vertex create coordinates %g %g %g\n',x(i,j),y(i,j),z(i,j)); + vertices(i,j) = counter; + end +end +%Create bottom vertices +fprintf(fid,'vertex create coordinates %g %g %g\n',x(1,1),y(1,1),d); +fprintf(fid,'vertex create coordinates %g %g %g\n',x(nx,1),y(nx,1),d); +fprintf(fid,'vertex create coordinates %g %g %g\n',x(nx,ny),y(nx,ny),d); +fprintf(fid,'vertex create coordinates %g %g %g\n',x(1,ny),y(1,ny),d); + +num_surf_edges = (nx-1)*2 + (ny-1)*2; + +%Create bottom edges +fprintf(fid,'edge create straight "vertex.%i" "vertex.%i" real\n',nx*ny+1,nx*ny+2); +fprintf(fid,'edge create straight "vertex.%i" "vertex.%i" real\n',nx*ny+2,nx*ny+3); +fprintf(fid,'edge create straight "vertex.%i" "vertex.%i" real\n',nx*ny+3,nx*ny+4); +fprintf(fid,'edge create straight "vertex.%i" "vertex.%i" real\n',nx*ny+4,nx*ny+1); + +%Create vertical edges +fprintf(fid,'edge create straight "vertex.%i" "vertex.%i" real\n',nx*ny+1,vertices(1,1)); +fprintf(fid,'edge create straight "vertex.%i" "vertex.%i" real\n',nx*ny+2,vertices(nx,1)); +fprintf(fid,'edge create straight "vertex.%i" "vertex.%i" real\n',nx*ny+3,vertices(nx,ny)); +fprintf(fid,'edge create straight "vertex.%i" "vertex.%i" real\n',nx*ny+4,vertices(1,ny)); + +%Create surface face +counter = 3; +fprintf(fid,'face create vertices'); +for j = 1:ny + for i = 1:nx + counter = counter+1; + fprintf(fid,' "vertex.%i"',vertices(i,j)); + if counter>=6 + fprintf(fid,' \\ \n'); + counter = 0; + end + end +end +fprintf(fid,'rowdimension %i tolerance 0 \n',nx); + +%Create side faces +fprintf(fid,'face create wireframe "edge.%i" "edge.%i" "edge.%i" "edge.%i" real\n',9,1,5,6); +fprintf(fid,'face create wireframe "edge.%i" "edge.%i" "edge.%i" "edge.%i" real\n',10,2,6,7); +fprintf(fid,'face create wireframe "edge.%i" "edge.%i" "edge.%i" "edge.%i" real\n',11,3,7,8); +fprintf(fid,'face create wireframe "edge.%i" "edge.%i" "edge.%i" "edge.%i" real\n',12,4,8,5); + +%Create bottom faces +fprintf(fid,'face create wireframe "edge.%i" "edge.%i" "edge.%i" "edge.%i" real\n',1,2,3,4); + +%Create Volume +fprintf(fid,'volume create stitch "face.1" "face.2" "face.3" "face.4" "face.5" "face.6" real\n'); +fprintf(fid,'volume mesh "volume.1" tetrahedral size %g\n',dx/1); + +%Create free surface boundary +fprintf(fid,'physics create "101" btype "ELEMENT_SIDE" face "face.1"\n'); + +%Create outflow boundary +fprintf(fid,'physics create "105" btype "ELEMENT_SIDE" face "face.2" "face.3" "face.4" "face.5" "face.6"\n'); + +fclose(fid); diff --git a/science/Delaunay.py b/science/Delaunay.py new file mode 100644 index 0000000..b50b753 --- /dev/null +++ b/science/Delaunay.py @@ -0,0 +1,349 @@ +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @section LICENSE +# Copyright (c) SeisSol Group +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import numpy as np +from scipy.spatial import Delaunay +import os +import timeit + + +class CheckStationsMesh(object): + + def __init__( + self, filename_mesh='/home/msimon/svn/repos/verce/All/JRA/JRA1/python/test_ressources/inputfiles/eucrust_small_new.neu', + station_coordinates=str()): + """ + Checks if stations given by station_coordinates are inside the mesh. + If not, the function "move_points_to_mesh" will move the points + into the mesh and return a numpy ndarray of the coordinates of + all the stations that were successfully placed into the mesh + + :type filename: class:'~str' + :param: Fullpath, or relative path of the mesh + :type station_coordinates: class: '~str' + :param: String containing station coordinats as in Input.par + e.g.: + '3.9463538e+06 1.9802029e+06 4.5486094e+06 \n + 1.9542831e+06 9.9590736e+05 5.9475798e+06 \n + 4.1565145e+06 1.4021579e+06 4.5762539e+06 + . + . + .' + + """ + + self.filename_mesh = filename_mesh + try: + self.station_coordinates = self.__read_station_coordinates( + station_coordinates) + except: + print 'cannot load station coordinates' + raise Exception, ('cannot load station coordinates %s' % + station_coordinates) + try: + self.vertices, self.elements, self.boundary_elements = \ + self.__read_mesh(filename_mesh=self.filename_mesh) + except: + print 'cannot load mesh' + raise Exception, ('cannot load mesh %s' % self.filename_mesh) + try: + self.surface_volume = self.__construct_surface_volume( + self.vertices, self.elements, self.boundary_elements, + surface_volume_thickness=0.97) + except: + print 'cannot load construct surface volume' + raise Exception('cannot construct surface volume') + + def __read_station_coordinates(self, station_coordinates): + """ + Converts a String of station coordinates as given in Seissol-Input.par + Input-file into a numpy array. + + :type station_coordinates: class:'str()' + :param: Converts + :rtype points: class:'numpy.ndarray()' + :param: 3xN-dim array containing X,Y,Z coordinates of N stations + """ + + station_coordinates = station_coordinates.split('\n') + points = [] + for station in station_coordinates: + if station in '': + break + points.append([float(coord) for coord in station.split()]) + points = np.asanyarray(points) + return points + + def __read_mesh(self, filename_mesh='/home/msimon/svn/repos/verce/All/JRA/JRA1/python/test_ressources/inputfiles/eucrust_small_new.neu'): + """ + From mesh-file read vertices, elements and boundary elements + + :type: filename_mesh: 'str' + :param: filename of the mesh. Full path or relative path + :rtype: vertices: '~numpy.ndarray' + :param: 4xN-dim array (N=Number of vertices). 1st-dim=Index; + 2nd-dim= x-coordinate; 3rd-dim = y-coordinate; + 4th-dim = z-coordinate + :rtype: elements: '~numpy.dnarray' + :param: 7xN-dim array (N=Number of elements). 1st-dim=Index; + 2nd-dim= irrelevant; 3rd-dim = irrelevant; + 4th-7th-dim = Indices of vertices constructing the element + :rtype: boundary_elements: 'dict(boundary_condition: numpy.array)' + :param: Dictionary Refering to the Indices of Elements adhering \ + to boundary conditions. Keys are Boundary conditions type + identifiers + Identifier of boundary element type: + 101 = free surface boundary + 102 = non-conforming boundary + 103 = dynamic rupture boundary + 104 = inflow boundary + 105 = absorbing boundary + 106 = periodic boundary + """ + + filename = filename_mesh + if filename[-4:] not in '.neu': + print 'filename not in *.neu format!!' + filename = filename[:-4] + t = timeit.time.time() + #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + #% Read Gambit Data + #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + f = open(filename + '.neu') + print '\n' + print '--------------------------------------------------------',\ + '---------------------------' + print ' Reading data from: %s' % filename + '.neu' + for i in range(6): + junk = f.readline() + tmp = f.readline() + tmp = [int(s) for s in tmp.split() if s.isdigit()] + NUMNP = tmp[0] # %Number of Vertices + NELEM = tmp[1] # %Number of Elements + NGRPS = tmp[2] # %Number of Element Groups + NBSETS = tmp[3] # %Number of Boundary Condition Sets + NDFCD = tmp[4] # %Number of Dimensions (2 or 3) + if 3 == NDFCD: + + # Vertices + f.readline() + f.readline() + vertices = np.fromfile(file=f, count=NUMNP * 4, sep=" ") + vertices = vertices.reshape(NUMNP, 4) + vertices = vertices.transpose() + + # Elements + f.readline() + f.readline() + position = f.tell() + first_line = f.readline() + first_line = [int(s) for s in first_line.split() if s.isdigit()] + n = 7 + f.seek(position, 0) + elements = np.fromfile(file=f, count=NELEM * n, sep=" ", + dtype=int).reshape(NELEM, n).transpose() + + # loop over element groups. irrelevant for this routine, but i\ + # left it in in case someone wants to work with it + for group in range(NGRPS): + f.readline() + f.readline() + first_line = f.readline() + first_line = [int(s) for s in first_line.split() if + s.isdigit()] + nelem = first_line[1] + f.readline() + f.readline() + tmp = np.fromfile(file=f, count=nelem, sep=" ") + position = f.tell() + + # Boundary Elements + f.seek(position, 0) + boundary_elements = {} + for boundaries in range(NBSETS): + f.readline() + f.readline() + first_line = f.readline() + first_line = [int(s) for s in first_line.split() if + s.isdigit()] + nelem = first_line[2] + boundary_elements[str( + first_line[0])] = np.fromfile( + file=f, count=nelem * 3, sep=" ", dtype=int).reshape(3, + nelem)[0] + position = f.tell() + else: + print 'only 3d tetrahedral meshes' + self.vertices = vertices + self.elements = elements + self.boundary_elements = boundary_elements + return vertices, elements, boundary_elements + + def __construct_surface_volume(self, vertices, elements, + boundary_elements, surface_volume_thickness=0.05): + """ + From Free surface boundary construct convex hull of + surface volume + + :type vertices: class:'~numpy.ndarray' + :param: 4xN-dim array (N=Number of vertices). 1st-dim=Index; + 2nd-dim= x-coordinate; 3rd-dim = y-coordinate; + 4th-dim = z-coordinate + :type elements: class:'~numpy.dnarray' + :param: 7xN-dim array (N=Number of elements). 1st-dim=Index; + 2nd-dim= irrelevant; 3rd-dim = irrelevant; + 4th-7th-dim = Indices of vertices constructing the element + :type boundary_elements: class:'dict(boundary_condition: numpy.array)' + :param: Dictionary Refering to the Indices of Elements adhering \ + to boundary conditions. + :type surface_volume_thickness: class:'~float' + :param: Given in percent. Defines the volume for which to + calculate the convex hull below the surface. + :rtype surface_volume: class:'~numpy.ndarray' + :param: Collection of point coordinates of surface element-vertices + and the same points shifted towards coordinate system origin by + some percent defined in surface_volume_thickness + """ + + # select elements for boundary condition '101' = free surface + boundary_vertices = elements[3:].transpose().take( + boundary_elements['101']-1, axis=0) + # extract coordinates of vertices + boundary_points_coordinates = vertices[1:].transpose().take( + boundary_vertices.flatten()-1, axis=0) + # create a surface volume by adding the same points, just moved + # slightly towards the coordinate system origin + lower_bound_boundary_points = boundary_points_coordinates *\ + (1.0 - surface_volume_thickness) + surface_volume = np.concatenate((boundary_points_coordinates, + lower_bound_boundary_points), axis=0) + return surface_volume + + def __in_hull(self, points, hull): + """ + hull is Delaunay of scipy.spatial + + :type points: class:'~numpy.ndarray' + :params: 3xN-dim numpy array containing the X,Y,Z coordinates of the + N stations. + :type hull: class:'~scipy.spatial.Delaunay' + :params: convex hull around mesh surface + :rtype: 1d-Boolean array stating if Point is inside the convex + hull or not + """ + + return hull.find_simplex(points) >= 0 + + def move_points_to_mesh(self, steplength=1.01): + """ + Checks if the stations are located within the mesh. + + The stations outside the mesh will be moved incrementally towards + the coordinate system origin, until they are in the mesh again. + The initial position of each station is moved away from the origin + by a factor of "steplength" + Then moving back towards the origin, is done in 10ths of steplength + + If some coordinates could not be moved into the mesh, they will + be ignored. + + :type steplength: class:'~float' + :param: sets the inital offset of the station coordinates away + from the origin + :rtype points_in_mesh: class:'~numpy.ndarray' + :param: 3xN-dim numpy array containing all coordinates that could + successfully be moved into the mesh. + """ + + + + try: + self.hull = Delaunay(self.surface_volume) + except: + raise Exception, "Cant create convex hull for mesh" + + # set inital values: + finalstation_coordinates = np.copy(self.station_coordinates * + steplength) + inhull = self.__in_hull(finalstation_coordinates, self.hull) + min_radius_finalstation_coordinates = 1.0 + min_radius_surface_volume = 0.0 + + # move stations into the convex hull of the surface volume. stop, + # in case their distance to the origin is smaller then the the + # bottom layer of the surface volume + while min_radius_finalstation_coordinates > \ + min_radius_surface_volume and \ + sum(inhull) != len(self.station_coordinates): + inhull = self.__in_hull(finalstation_coordinates, self.hull) + inv_in3d = np.column_stack((inhull, inhull, inhull)) + finalstation_coordinates = np.where(inv_in3d, + finalstation_coordinates, finalstation_coordinates * + (1 - steplength / 10)) + min_radius_finalstation_coordinates = min([np.sqrt(x * x + y * y + z * z) + for x, y, z + in finalstation_coordinates]) + min_radius_surface_volume = min([np.sqrt(x * x + y * y + z * z) for + x, y, z + in self.surface_volume]) + + # only keep the points that could be moved into the mesh + points_in_mesh = np.compress(inv_in3d.flatten(), + finalstation_coordinates. + flatten( + )).reshape( + len(np.compress(inv_in3d.flatten(), + finalstation_coordinates.flatten())) / 3, 3) + + return points_in_mesh + + +if __name__ == '__main__': + + f=open('/home/msimon/svn/repos/verce/All/JRA/JRA1/python/'+\ + 'test_ressources/inputfiles/input.par') + strin=f.read() + station_coordinates='\n'.join(strin.split('\n')[88:-21]) + #csm = CheckStationsMesh(filename_mesh='/home/msimon/svn/repos/verce/All/JRA/JRA1/python/\ + #test_ressources/inputfiles/eucrust_small_new.neu', \ + csm = CheckStationsMesh(filename_mesh='/home/msimon/git/'+\ + 'wfs_input_generator_msimon00/wfs_input_generator/tests/data/'+\ + 'seissol_example/most_simple_tet.neu', \ + station_coordinates=station_coordinates) + + f.close() + points_in_mesh = csm.move_points_to_mesh() + + print points_in_mesh diff --git a/science/Generate_Eigenvectors.m b/science/Generate_Eigenvectors.m new file mode 100644 index 0000000..599c168 --- /dev/null +++ b/science/Generate_Eigenvectors.m @@ -0,0 +1,614 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Josep de la Puente Alvarez (josep.delapuente AT bsc.es, http://www.geophysik.uni-muenchen.de/Members/jdelapuente) +% +% @section LICENSE +% Copyright (c) 2007, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% @section DESCRIPTION +% MATLAB script for obtaning the eigenvalues and eigenvectors of elastic, +% viscoelastic, anisotropic or poroelastic materials +% +% The elastic and viscoelastic cases read the parameters directly from the +% script, whereas the anisotropic and poroelastic cases read the parameters +% from an external SeisSol material definition file (*.def). Notice that +% only the first material in the file is read. +% +% The resulting *.dat file can be read by SeisSol when using the initial +% conditions of type 'Planewave_Ricker_Puls' or 'Planewave_Gauss_Puls'. +% In this case, a plane wave will be generated using one chosen eigenvector +% from those listed in the *.dat file. +% +% The eigenvalues and eigenvectors are ordered in a descending way, to be +% as close as possible to the standard ordering in the literature. However, +% some ambiguity remains in the case of waves with identical wave speed +% of propagation. In this case, the ordering of the eigenvalues is +% arbitrary and visual inspection of the eigenvector matrix is recommended. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% Generates eigenvectors ans eigenvalues for a specified %%') +disp(' %% material and propagation direction. %%') +disp(' %% %%') +disp(' %% The material can be either elastic, viscoelastic, aniso- %%') +disp(' %% tropic or poroelastic. %%') +disp(' %% %%') +disp(' %% The output is a file that can be read by SeisSol with the %%') +disp(' %% initial condition types "Planewave_Ricker_Puls" or %%') +disp(' %% "Planewave_Gauss_Puls". %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' '),disp(' ') +clear, close all; + +rheo=input(' Choose rheology type (1:ela., 2:viscoela., 3:aniso., 4:poro.):'); +disp(' Write unitary vector of propagation direction:') +kx=input(' nx='); +ky=input(' ny='); +kz=input(' nz='); +fname_out=input(' Enter name of output file (*.dat): ','s'); + + +if(rheo==1) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%% PARAMETER INPUT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + rho = 1; %density + lambda = 1; %Lame constant + mu = 1; %Lame constant + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + disp('-----------------------------------------------------------------') + disp(' Chosen parameters are:'); + disp(sprintf(' Density rho = %g',rho)); + disp(sprintf(' Lame constant (lambda) = %g',lambda)); + disp(sprintf(' Lame constant (mu) = %g',mu)); + + %% Build Jacobian matrix A + A = [0 0 0 0 0 0 -(lambda+2*mu) 0 0; + 0 0 0 0 0 0 -lambda 0 0; + 0 0 0 0 0 0 -lambda 0 0; + 0 0 0 0 0 0 0 -mu 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 -mu; + -1/rho 0 0 0 0 0 0 0 0; + 0 0 0 -1/rho 0 0 0 0 0; + 0 0 0 0 0 -1/rho 0 0 0 ]; + + + %% Build Jacobian matrix B + B = [0 0 0 0 0 0 0 -lambda 0; + 0 0 0 0 0 0 0 -(lambda+2*mu) 0; + 0 0 0 0 0 0 0 -lambda 0; + 0 0 0 0 0 0 -mu 0 0; + 0 0 0 0 0 0 0 0 -mu; + 0 0 0 0 0 0 0 0 0; + 0 0 0 -1/rho 0 0 0 0 0; + 0 -1/rho 0 0 0 0 0 0 0; + 0 0 0 0 -1/rho 0 0 0 0 ]; + + %% Build Jacobian matrix C + C = [0 0 0 0 0 0 0 0 -lambda; + 0 0 0 0 0 0 0 0 -lambda; + 0 0 0 0 0 0 0 0 -(lambda+2*mu); + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 -mu 0; + 0 0 0 0 0 0 -mu 0 0; + 0 0 0 0 0 -1/rho 0 0 0; + 0 0 0 0 -1/rho 0 0 0 0; + 0 0 -1/rho 0 0 0 0 0 0 ]; + +elseif(rheo==2) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%% PARAMETER INPUT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + rho = 1; %density + lambda = 1; %Lame constant + mu = 1; %Lame constant + QPval = 20; %Q-factor for P-waves + QSval = 10; %Q-factor for S-waves + n = 3; %Number of mechanisms, i.e. Maxwell bodies + freq = 1; %Central frequency of the absorption band (in Hertz) + f_ratio = 100; %The ratio between the maximum and minimum frequencies of our bandwidth + %Usually 10^4 is taken as good (Day 2003) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + %%%%%%%%%%%%%%%% Output chosen parameters on screen %%%%%%%%%%%%%%%%%%%%% + disp('-----------------------------------------------------------------') + disp(' Chosen parameters are:'); + disp(sprintf(' Density rho = %g',rho)); + disp(sprintf(' Lame constant (lambda) = %g',lambda)); + disp(sprintf(' Lame constant (mu) = %g',mu)); + disp(sprintf(' Q for P-wave = %g',QPval)); + disp(sprintf(' Q for S-wave = %g',QSval)); + + % Selection of the logarithmically equispaced frequencies + % i.e.: log(w) = log(wmin) + (i-1)*log(f_ratio)/(2*(n-1)) + w0 = 2*pi*freq; + wmin = w0/sqrt(f_ratio); + kmax = 2*n-1; + + if n>1 + for i=1:kmax + w(i) = exp(log(wmin)+(i-1)/(2*(n-1))*log(f_ratio)); + end + else + w = w0; + end + + + %% Build Jacobian matrix A + A = [0 0 0 0 0 0 -(lambda+2*mu) 0 0; + 0 0 0 0 0 0 -lambda 0 0; + 0 0 0 0 0 0 -lambda 0 0; + 0 0 0 0 0 0 0 -mu 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 -mu; + -1/rho 0 0 0 0 0 0 0 0; + 0 0 0 -1/rho 0 0 0 0 0; + 0 0 0 0 0 -1/rho 0 0 0 ]; + + %% extend by n mechanisms + for i = 1:n + A = [A; + [0 0 0 0 0 0 -w(i) 0 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 -w(i)/2 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 -w(i)/2]; + ]; + end + A = [A,zeros(9+n*6,n*6)]; + + %% Build Jacobian matrix B + B = [0 0 0 0 0 0 0 -lambda 0; + 0 0 0 0 0 0 0 -(lambda+2*mu) 0; + 0 0 0 0 0 0 0 -lambda 0; + 0 0 0 0 0 0 -mu 0 0; + 0 0 0 0 0 0 0 0 -mu; + 0 0 0 0 0 0 0 0 0; + 0 0 0 -1/rho 0 0 0 0 0; + 0 -1/rho 0 0 0 0 0 0 0; + 0 0 0 0 -1/rho 0 0 0 0 ]; + %% extend by n mechanisms + for i = 1:n + B = [B; + [0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 -w(i) 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 -w(i)/2 0 0 ; + 0 0 0 0 0 0 0 0 -w(i)/2 ; + 0 0 0 0 0 0 0 0 0]; + ]; + end + B = [B,zeros(9+n*6,n*6)]; + + %% Build Jacobian matrix C + C = [0 0 0 0 0 0 0 0 -lambda; + 0 0 0 0 0 0 0 0 -lambda; + 0 0 0 0 0 0 0 0 -(lambda+2*mu); + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 -mu 0; + 0 0 0 0 0 0 -mu 0 0; + 0 0 0 0 0 -1/rho 0 0 0; + 0 0 0 0 -1/rho 0 0 0 0; + 0 0 -1/rho 0 0 0 0 0 0 ]; + %% extend by n mechanisms + for i = 1:n + C = [C; + [0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 -w(i) ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 -w(i)/2 0 ; + 0 0 0 0 0 0 -w(i)/2 0 0]; + ]; + end + C = [C,zeros(9+n*6,n*6)]; + + +elseif(rheo==3) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%% PARAMETER INPUT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + fname=input(' Enter the file name of the anisotropic properties (*.def):','s') + fid = fopen([fname,'.def']); + junk = fgetl(fid); + data = fscanf(fid,'%g',[1,32]); + fclose(fid); + disp([' Successfully read parameters from file: ',fname,'.def!']) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + %coefficients given in N/m^2 + ce(1,1) = data(3); + ce(1,2) = data(4); + ce(1,3) = data(5); + ce(1,4) = data(6); + ce(1,5) = data(7); + ce(1,6) = data(8); + ce(2,2) = data(9); + ce(2,3) = data(10); + ce(2,4) = data(11); + ce(2,5) = data(12); + ce(2,6) = data(13); + ce(3,3) = data(14); + ce(3,4) = data(15); + ce(3,5) = data(16); + ce(3,6) = data(17); + ce(4,4) = data(18); + ce(4,5) = data(19); + ce(4,6) = data(20); + ce(5,5) = data(21); + ce(5,6) = data(22); + ce(6,6) = data(23); + rho = data(2); + + % direction of material symmetry axes + nx = data(24); + ny = data(25); + nz = data(26); + sx = data(27); + sy = data(28); + sz = data(29); + tx = data(30); + ty = data(31); + tz = data(32); + + for i = 1:6 + for j = 1:i-1 + ce(i,j) = ce(j,i); + end + end + + % Transformation matrix TO the rotated system + T(1,1) = nx^2; + T(1,2) = ny^2; + T(1,3) = nz^2; + T(1,4) = 2*nz*ny; + T(1,5) = 2*nz*nx; + T(1,6) = 2*ny*nx; + T(2,1) = sx^2; + T(2,2) = sy^2; + T(2,3) = sz^2; + T(2,4) = 2*sz*sy; + T(2,5) = 2*sz*sx; + T(2,6) = 2*sy*sx; + T(3,1) = tx^2; + T(3,2) = ty^2; + T(3,3) = tz^2; + T(3,4) = 2*tz*ty; + T(3,5) = 2*tz*tx; + T(3,6) = 2*ty*tx; + T(4,1) = sx*tx; + T(4,2) = sy*ty; + T(4,3) = sz*tz; + T(4,4) = sz*ty+sy*tz; + T(4,5) = sz*tx+sx*tz; + T(4,6) = sy*tx+sx*ty; + T(5,1) = nx*tx; + T(5,2) = ny*ty; + T(5,3) = nz*tz; + T(5,4) = nz*ty+ny*tz; + T(5,5) = nz*tx+nx*tz; + T(5,6) = ny*tx+nx*ty; + T(6,1) = nx*sx; + T(6,2) = ny*sy; + T(6,3) = nz*sz; + T(6,4) = nz*sy+ny*sz; + T(6,5) = nz*sx+nx*sz; + T(6,6) = ny*sx+nx*sy; + for i = 1:6 + for j = 1:6 + TT(i,j) = T(j,i); + end + end + + % Initialize lower half of Voigt matrix using the symmetry property + + for i = 1:6 + for j = 1:i-1 + ce(i,j) = ce(j,i); + end + end + % + % % Initialize and rotate Voigt matrix to get local material properties + + Voigt_rot(:,:) = T(:,:)*(ce(:,:)*TT(:,:)); + + ce(:,:) = Voigt_rot(:,:); + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + A = [0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 0 ; + 0 0 0 0 0 0 0 0 0 ; + -1/rho 0 0 0 0 0 0 0 0 ; + 0 0 0 -1/rho 0 0 0 0 0 ; + 0 0 0 0 0 -1/rho 0 0 0 ]; + + A(1,7:9) = [ -ce(1,1), -ce(1,6), -ce(1,5) ]; + A(2,7:9) = [ -ce(1,2), -ce(2,6), -ce(2,5) ]; + A(3,7:9) = [ -ce(1,3), -ce(3,6), -ce(3,5) ]; + A(4,7:9) = [ -ce(1,6), -ce(6,6), -ce(5,6) ]; + A(5,7:9) = [ -ce(1,4), -ce(4,6), -ce(4,5) ]; + A(6,7:9) = [ -ce(1,5), -ce(5,6), -ce(5,5) ]; + + %% Build Jacobian matrix B + B = [0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 -1/rho 0 0 0 0 0; + 0 -1/rho 0 0 0 0 0 0 0; + 0 0 0 0 -1/rho 0 0 0 0 ]; + + B(1,7:9) = [ -ce(1,6), -ce(1,2), -ce(1,4) ]; + B(2,7:9) = [ -ce(2,6), -ce(2,2), -ce(2,4) ]; + B(3,7:9) = [ -ce(3,6), -ce(2,3), -ce(3,4) ]; + B(4,7:9) = [ -ce(6,6), -ce(2,6), -ce(4,6) ]; + B(5,7:9) = [ -ce(4,6), -ce(2,4), -ce(4,4) ]; + B(6,7:9) = [ -ce(5,6), -ce(2,5), -ce(4,5) ]; + + %% Build Jacobian matrix C + C = [0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 -1/rho 0 0 0; + 0 0 0 0 -1/rho 0 0 0 0; + 0 0 -1/rho 0 0 0 0 0 0 ]; + + C(1,7:9) = [ -ce(1,5), -ce(1,4), -ce(1,3) ]; + C(2,7:9) = [ -ce(2,5), -ce(2,4), -ce(2,3) ]; + C(3,7:9) = [ -ce(3,5), -ce(3,4), -ce(3,3) ]; + C(4,7:9) = [ -ce(5,6), -ce(4,6), -ce(3,6) ]; + C(5,7:9) = [ -ce(4,5), -ce(4,4), -ce(3,4) ]; + C(6,7:9) = [ -ce(5,5), -ce(4,5), -ce(3,5) ]; + +elseif(rheo==4) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%% PARAMETER INPUT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + fname=input(' Enter the file name of the poroelastic properties (*.def):','s') + fid = fopen([fname,'.def']); + junk = fgetl(fid); + data = fscanf(fid,'%g',[1,43]); + fclose(fid); + disp([' Successfully read parameters from file: ',fname,'.def!']) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + %coefficients given in N/m^2 + c(1,1) = data(3); + c(1,2) = data(4); + c(1,3) = data(5); + c(1,4) = data(6); + c(1,5) = data(7); + c(1,6) = data(8); + c(2,2) = data(9); + c(2,3) = data(10); + c(2,4) = data(11); + c(2,5) = data(12); + c(2,6) = data(13); + c(3,3) = data(14); + c(3,4) = data(15); + c(3,5) = data(16); + c(3,6) = data(17); + c(4,4) = data(18); + c(4,5) = data(19); + c(4,6) = data(20); + c(5,5) = data(21); + c(5,6) = data(22); + c(6,6) = data(23); + rho_S = data(2); + rho_F = data(24); + K_F = data(25); + nu = data(26); + K_S = data(27); + Poro = data(28); + Kappa(1) = data(29); + Kappa(2) = data(30); + Kappa(3) = data(31); + Tor(1) = data(32); + Tor(2) = data(33); + Tor(3) = data(34); + rho = rho_S * (1-Poro)+Poro*rho_F; + K_Mean = 1/9*(c(1,1)+c(2,2)+c(3,3)+2*(c(1,2)+c(1,3)+c(2,3))); + MM = K_S/((1-K_Mean/K_S)-Poro*(1-K_S/K_F)); + Alpha(1) = 1 - (c(1,1)+c(1,2)+c(1,3))/(3*K_S); + Alpha(2) = 1 - (c(1,2)+c(2,2)+c(2,3))/(3*K_S); + Alpha(3) = 1 - (c(1,3)+c(2,3)+c(3,3))/(3*K_S); + Alpha(4) = -(c(1,4)+c(2,4)+c(3,4))/(3*K_S); + Alpha(5) = -(c(1,5)+c(2,5)+c(3,5))/(3*K_S); + Alpha(6) = -(c(1,6)+c(2,6)+c(3,6))/(3*K_S); + Rho1(1:3) = rho-(rho_F^2 ./ (rho_F * Tor(1:3) /Poro )); + Rho2(1:3) = rho_F - (rho_F * Tor(1:3) / Poro) * rho / rho_F; + Beta1(1:3) = rho_F ./ (rho_F * Tor(1:3) / Poro) ; + Beta2(1:3) = rho / rho_F; + + %initialize lower triangular matrix symmetrically + for i=1:5 + for j=i+1:6 + c(j,i) = c(i,j); + end + end + + % direction of material symmetry axes + nx = data(35); + ny = data(36); + nz = data(37); + sx = data(38); + sy = data(39); + sz = data(40); + tx = data(41); + ty = data(42); + tz = data(43); + + % normalization of coordinate vectors + len = sqrt(nx*nx+ny*ny+nz*nz); nx=nx/len; ny=ny/len; nz=nz/len; + len = sqrt(sx*sx+sy*sy+sz*sz); sx=sx/len; sy=sy/len; sz=sz/len; + len = sqrt(tx*tx+ty*ty+tz*tz); tx=tx/len; ty=ty/len; tz=tz/len; + + % rotation matrix of anisotropic coefficients (Bond matrix) + BM(1,1) = nx^2; + BM(1,2) = sx^2; + BM(1,3) = tx^2; + BM(1,4) = 2*sx*tx; + BM(1,5) = 2*nx*tx; + BM(1,6) = 2*nx*sx; + BM(2,1) = ny^2; + BM(2,2) = sy^2; + BM(2,3) = ty^2; + BM(2,4) = 2*sy*ty; + BM(2,5) = 2*ny*ty; + BM(2,6) = 2*ny*sy; + BM(3,1) = nz^2; + BM(3,2) = sz^2; + BM(3,3) = tz^2; + BM(3,4) = 2*sz*tz; + BM(3,5) = 2*nz*tz; + BM(3,6) = 2*nz*sz; + BM(4,1) = nz*ny; + BM(4,2) = sz*sy; + BM(4,3) = tz*ty; + BM(4,4) = sz*ty+sy*tz; + BM(4,5) = nz*ty+ny*tz; + BM(4,6) = nz*sy+ny*sz; + BM(5,1) = nz*nx; + BM(5,2) = sz*sx; + BM(5,3) = tz*tx; + BM(5,4) = sz*tx+sx*tz; + BM(5,5) = nz*tx+nx*tz; + BM(5,6) = nz*sx+nx*sz; + BM(6,1) = ny*nx; + BM(6,2) = sy*sx; + BM(6,3) = ty*tx; + BM(6,4) = sy*tx+sx*ty; + BM(6,5) = ny*tx+nx*ty; + BM(6,6) = ny*sx+nx*sy; + + %rotation of anisotropic coefficient c into symmetry axes system + c = BM*c*BM'; + + %computation of undrained c(i,j) coefficients + for i=1:6 + for j=1:6 + c(i,j)=c(i,j)+MM*Alpha(i)*Alpha(j); + end + end + + + + %% Build Jacobian matrix A + A = [ 0 0 0 0 0 0 -c(1,1) -c(1,6) -c(1,5) 0 -Alpha(1)*MM 0 0; + 0 0 0 0 0 0 -c(1,2) -c(2,6) -c(2,5) 0 -Alpha(2)*MM 0 0; + 0 0 0 0 0 0 -c(1,3) -c(3,6) -c(3,5) 0 -Alpha(3)*MM 0 0; + 0 0 0 0 0 0 -c(1,6) -c(6,6) -c(5,6) 0 -Alpha(6)*MM 0 0; + 0 0 0 0 0 0 -c(1,4) -c(4,6) -c(4,5) 0 -Alpha(4)*MM 0 0; + 0 0 0 0 0 0 -c(1,5) -c(5,6) -c(5,5) 0 -Alpha(5)*MM 0 0; + -1/Rho1(1) 0 0 0 0 0 0 0 0 -Beta1(1)/Rho1(1) 0 0 0; + 0 0 0 -1/Rho1(1) 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 -1/Rho1(1) 0 0 0 0 0 0 0; + 0 0 0 0 0 0 Alpha(1)*MM Alpha(6)*MM Alpha(5)*MM 0 MM 0 0 ; + -1/Rho2(1) 0 0 0 0 0 0 0 0 -Beta2(1)/Rho2(1) 0 0 0; + 0 0 0 -1/Rho2(1) 0 0 0 0 0 0 0 0 0; + 0 0 0 0 0 -1/Rho2(1) 0 0 0 0 0 0 0]; + + + %% Build Jacobian matrix B + B = [ 0 0 0 0 0 0 -c(1,6) -c(1,2) -c(1,4) 0 0 -Alpha(1)*MM 0; + 0 0 0 0 0 0 -c(2,6) -c(2,2) -c(2,4) 0 0 -Alpha(2)*MM 0; + 0 0 0 0 0 0 -c(3,6) -c(2,3) -c(3,4) 0 0 -Alpha(3)*MM 0; + 0 0 0 0 0 0 -c(6,6) -c(2,6) -c(4,6) 0 0 -Alpha(6)*MM 0; + 0 0 0 0 0 0 -c(4,6) -c(2,4) -c(4,4) 0 0 -Alpha(4)*MM 0; + 0 0 0 0 0 0 -c(5,6) -c(2,5) -c(4,5) 0 0 -Alpha(5)*MM 0; + 0 0 0 -1/Rho1(2) 0 0 0 0 0 0 0 0 0; + 0 -1/Rho1(2) 0 0 0 0 0 0 0 -Beta1(2)/Rho1(2) 0 0 0; + 0 0 0 0 -1/Rho1(2) 0 0 0 0 0 0 0 0; + 0 0 0 0 0 0 Alpha(6)*MM Alpha(2)*MM Alpha(4)*MM 0 0 MM 0; + 0 0 0 -1/Rho2(2) 0 0 0 0 0 0 0 0 0; + 0 -1/Rho2(2) 0 0 0 0 0 0 0 -Beta2(2)/Rho2(2) 0 0 0; + 0 0 0 0 -1/Rho2(2) 0 0 0 0 0 0 0 0]; + + %% Build Jacobian matrix C + C = [0 0 0 0 0 0 -c(1,5) -c(1,4) -c(1,3) 0 0 0 -Alpha(1)*MM; + 0 0 0 0 0 0 -c(2,5) -c(2,4) -c(2,3) 0 0 0 -Alpha(2)*MM; + 0 0 0 0 0 0 -c(3,5) -c(3,4) -c(3,3) 0 0 0 -Alpha(3)*MM; + 0 0 0 0 0 0 -c(5,6) -c(4,6) -c(3,6) 0 0 0 -Alpha(6)*MM; + 0 0 0 0 0 0 -c(4,5) -c(4,4) -c(3,4) 0 0 0 -Alpha(4)*MM; + 0 0 0 0 0 0 -c(5,5) -c(4,5) -c(3,5) 0 0 0 -Alpha(5)*MM; + 0 0 0 0 0 -1/Rho1(3) 0 0 0 0 0 0 0; + 0 0 0 0 -1/Rho1(3) 0 0 0 0 0 0 0 0; + 0 0 -1/Rho1(3) 0 0 0 0 0 0 -Beta1(3)/Rho1(3) 0 0 0; + 0 0 0 0 0 0 Alpha(5)*MM Alpha(4)*MM Alpha(3)*MM 0 0 0 MM; + 0 0 0 0 0 -1/Rho2(3) 0 0 0 0 0 0 0; + 0 0 0 0 -1/Rho2(3) 0 0 0 0 0 0 0 0; + 0 0 -1/Rho2(3) 0 0 0 0 0 0 -Beta2(3)/Rho2(3) 0 0 0]; + +end +%%%%%%%%%%%%%%%%%%%%%%% Compute analytic solution %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Formulate and solve Eigenvalue problem +clear i %to make sure to have i as the imaginary i + +M1 = -(A*kx + B*ky + C*kz); + +[R1,r1] = eig(M1); % R1 = matrix of eigenvectors +omega1 = diag(r1); % omega1 = vector of eigenvalues + +[omega,Y] = sort(real(omega1),'descend'); +R=R1*0; +for j=1:length(omega) + R(:,j)=real(R1(:,Y(j))); +end +%% Writing output data +disp(' '); +disp(sprintf('Writing data into file...')); +fid_out = fopen([fname_out,'.dat'],'w'); + fprintf(fid_out,'Number of eigenvalues\n'); + fprintf(fid_out,'%d\n',length(omega)); + fprintf(fid_out,'Eigenvalues\n'); + fprintf(fid_out,'%25.14f\n',[real(omega)]'); + fprintf(fid_out,'Eigenvectors\n'); + fprintf(fid_out,'%25.14f\n',[real(reshape(R,length(omega)^2,1))]'); +fclose(fid_out); + +disp(sprintf('Finished! ')); diff --git a/science/ViscoelasticModComp.m b/science/ViscoelasticModComp.m new file mode 100644 index 0000000..ca247de --- /dev/null +++ b/science/ViscoelasticModComp.m @@ -0,0 +1,307 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Josep de la Puente Alvarez (josep.delapuente AT bsc.es, http://www.geophysik.uni-muenchen.de/Members/jdelapuente) +% +% @section LICENSE +% Copyright (c) 2007, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% @section DESCRIPTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% BRIEF INTRODUCTION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% In viscoelastic materials there exists phase velocity dispersion, +%% meaning that the velocities of the waves vary with the frequency. In the +%% viscoelastic model used in SeisSol (Generalized Maxwell Body, GMB), the +%% velocities are maximum for infinity frequency and get lower at lower +%% frequencies, but other models behave differently. The shape of this +%% curves depends on the attenuation chosen (quality factor QP and QS) as +%% well as the bandwidth and central frequency of the attenuating +%% mechanisms. +%% For most practical applications, we know QP and QS as well as the +%% seismic wave velocities at some particular frequency, often the source's +%% peak frequency. The input of SeisSol, however, is QP and QS and the +%% seismic wave velocities at infinite frequency. In order to transform +%% from one value set to the other we just need to run this script. +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% USAGE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The script's input is the following: +%% QPval,QSval: quality factor of the P and S waves +%% n: number of attenuating mechanisms +%% freq: frequency at which the phase velocities are defined +%% f_ratio: frequency bandwidth of attenuating mechanisms +%% rho: the material's density, which is frequency independent +%% vp_t, vs_t: target wave velocities at frequency "freq" +%% vp_0, vs_0: wave velocities at infinite frequency (unrelaxed +%% velocities) +%% In a first run, vp_0 and vs_0 are unknown so we can set them at the same +%% value as vp_t and vs_t. The program will then output in the screen the +%% recommended values for vp_0 and vs_0 given the proposed setup. For +%% double-checking one can then re-run the script now assigning the +%% previously obtained vp_0 and vs_0 values so that we are certain that the +%% values computed are correct. +home +clear all; +close all; +clc +disp('======================================') +disp('COMPUTATION OF PHASE VELOCITIES AT PEAK') +disp(' FREQUENCY FOR VISCOELASTIC MODELLING ') +disp('======================================') +disp(' ((c) Josep de la Puente Alvarez ') +disp(' LMU Geophysics 2007)') +disp('======================================') + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%% PARAMETERS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Attenuation Q-Solver parameters: +QPval=20.0; % Desired QP constant value +QSval=10.0; % Desired QS constant value +n=5; % Number of mechanisms we want to have + +%Frequency parameters: +freq=1; % Central frequency of the absorption band (in Hertz). Good to center it + % at the source's central frequency +f_ratio=100; % The ratio between the maximum and minimum frequencies of our bandwidth + % (Usually between 10^2 and 10^4) + +%Desired P and S wave velocities at peak frequency: +vp_t=2; % P-wave velocity +vs_t=1; % S-wave velocity + +%Material parameters at infinity frequency (unrelaxed moduli): +rho=1; % Density +vp_0=2.120858074089156; % P-wave velocity +vs_0=1.122397868862394; % S_wave velocity + +disp('--------------------------------------') +disp(' MATERIAL VALUES AT INFINTE FREQUENCY:'); +disp('--------------------------------------') +disp(strcat('Density= ',num2str(rho), 'Kg/m^3')); +disp(strcat('VP= ',num2str(vp_0), 'm/s')); +disp(strcat('VS= ',num2str(vs_0), 'm/s')); +% disp(strcat('mu= ',num2str(vs_0^2*rho), 'Pa')); +% disp(strcat('lambda= ',num2str(vp_0^2*rho-2*vs_0^2*rho), 'Pa')); +disp(' '); + +disp('--------------------------------------') +disp(' ATTENUATION SETTINGS:'); +disp('--------------------------------------') +disp(strcat('Number of mechanisms= ',num2str(n))); +disp(strcat('Q for P-wave= ',num2str(QPval))); +disp(strcat('Q for S-wave= ',num2str(QSval))); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%% PROBLEM SETUP %%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Derived quantities initialization +w_max=10001; % Maximum frequency (minimum freq = -w_max). Is better to keep an odd number +w_inc=0.1; % Increment in frequency +w0=freq*(2*pi); % Conversion to angular velocity +w=[0:w_inc:w_max]; +w=2*w-w_max; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%% GMB-EK COMPLEX M SOLUTION %%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Equation system initialization %% +kmax=2*n-1; %Number of equations to solve (the system is overdetermined) +AP=zeros(kmax,n); %Initialization of system matrix (P wave) +AS=zeros(kmax,n); %Initialization of system matrix (S wave) +QP=ones(kmax,1)/QPval; %Desired values of Q for each mechanism inverted (P wave) +QS=ones(kmax,1)/QSval; % " " (S wave) +YP=zeros(n,1); +YS=zeros(n,1); + +%% Selection of the logarithmically equispaced frequencies +wmean=2*pi*freq; +wmin_disc=wmean/sqrt(f_ratio); + +if n==1 + w_disc=w0; +else + for j=1:kmax + w_disc(j)=exp(log(wmin_disc)+(j-1)/(kmax-1)*log(f_ratio)); + end +end + +%% Filling of the linear system matrix %% +for m=1:kmax + for j=1:n + AP(m,j)=(w_disc(2*j-1).*w_disc(m)+w_disc(2*j-1).^2/QPval)./(w_disc(2*j-1).^2+w_disc(m).^2); + end +end + +for m=1:kmax + for j=1:n + AS(m,j)=(w_disc(2*j-1).*w_disc(m)+w_disc(2*j-1).^2/QSval)./(w_disc(2*j-1).^2+w_disc(m).^2); + end +end + +%% Solving of the system %% +YP=AP\QP; +YS=AS\QS; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%% VISUALIZATION OF Q IN FREQUENCY %%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Getting values for the continuous representation of Q %% +wmin=wmean/sqrt(f_ratio); +wmax=wmean*sqrt(f_ratio); +xfrq=[wmin:(wmax-wmin)/(10000-1):wmax]; + +%% P-wave Q continuous values +numP=0; +denP=1; +for j=1:n + numP=numP+(YP(j)*w_disc(2*j-1)*xfrq(:))./(w_disc(2*j-1)^2+xfrq(:).^2); + denP=denP-(YP(j)*w_disc(2*j-1).^2)./(w_disc(2*j-1)^2+xfrq(:).^2); +end +Q_contP=denP./numP; + +%% S-wave Q continuous values +numS=0; +denS=1; +for j=1:n + numS=numS+(YS(j)*w_disc(2*j-1)*xfrq(:))./(w_disc(2*j-1)^2+xfrq(:).^2); + denS=denS-(YS(j)*w_disc(2*j-1).^2)./(w_disc(2*j-1)^2+xfrq(:).^2); +end +Q_contS=denS./numS; + +%% Computing fitting quality (RMS and maximum difference) +maxPdif=0; +maxSdif=0; + +for j=1:length(Q_contP) + tempP=abs(Q_contP(j)-QPval); + if tempP >= maxPdif + maxPdif=tempP; + end + tempS=abs(Q_contS(j)-QSval); + if tempS >= maxSdif + maxSdif=tempS; + end +end + +subplot(1,2,1), +semilogx(xfrq/(2*pi),Q_contP,xfrq/(2*pi),QPval*ones(length(xfrq),1)), +title('Q for the P-wave'),legend('computed','desired') +xlabel('frequency (Hz)'),ylabel('Q'),axis([wmin/(2*pi) wmax/(2*pi) 0 QPval*1.25]) +subplot(1,2,2), +semilogx(xfrq/(2*pi),Q_contS,xfrq/(2*pi),QSval*ones(length(xfrq),1)), +title('Q for the S-wave'),legend('computed','desired'), +xlabel('frequency (Hz)'),ylabel('Q'),axis([wmin/(2*pi) wmax/(2*pi) 0 QSval*1.25]) + +disp(strcat('Attenuation bandwidth= [',num2str(wmin/(2*pi)),',',num2str(wmax/(2*pi)),'] Hz')); +disp(''); +disp(strcat('Maximum QP fitting error= ',num2str(maxPdif/QPval*100),' %')); +disp(''); +disp(strcat('Maximum QS fitting error= ',num2str(maxSdif/QSval*100),' %')); +disp(' '); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%% VELOCITIES COMPUTATION %%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Complex modulus +MUP=vp_0^2*rho; % Elastic P modulus +MUS=vs_0^2*rho; % Elastic S modulus + +MP=MUP*ones(length(w),1); +MS=MUS*ones(length(w),1); +vp=zeros(length(w),1); +vs=zeros(length(w),1); + +for j=1:n + MP(:)=MP(:)-MUP*(YP(j)*(w_disc(2*j-1)./(w_disc(2*j-1)+i*w(:)))); + MS(:)=MS(:)-MUS*(YS(j)*(w_disc(2*j-1)./(w_disc(2*j-1)+i*w(:)))); +end + +% Complex wave velocities (NOTE: Substitute by vp_0 and vs_0 to get the +% elastic solution) +vp(:)=sqrt(MP(:)/rho); +vs(:)=sqrt(MS(:)/rho); + +%Computing which Munrelaxed values we need to get desired attenuation at +%frequency peak +PSI1P=1; +PSI2P=0; +for j=1:n + PSI1P(:)=PSI1P(:)-YP(j)./(1+(w0/w_disc(2*j-1))^2); + PSI2P(:)=PSI2P(:)+YP(j).*w0/w_disc(2*j-1)./(1+(w0/w_disc(2*j-1))^2); +end +R=sqrt(PSI1P.^2+PSI2P.^2); +PINF=rho*vp_t^2*(R+PSI1P)./(2*R.^2); + +PSI1S=1; +PSI2S=0; +for j=1:n + PSI1S(:)=PSI1S(:)-YS(j)./(1+(w0/w_disc(2*j-1))^2); + PSI2S(:)=PSI2S(:)+YS(j).*w0/w_disc(2*j-1)./(1+(w0/w_disc(2*j-1))^2); +end +R=sqrt(PSI1S.^2+PSI2S.^2); +SINF=rho*vs_t^2*(R+PSI1S)./(2*R.^2); + +LINF=PINF-2*SINF; +VPINF=sqrt(PINF/rho); +VSINF=sqrt(SINF/rho); + +limw=w_max; +for j=1:length(w) + if (w(j)-w0)^2<=limw + wj=j; + limw=(w(j)-w0)^2; + end +end + +disp('--------------------------------------') +disp(' RESULTING PHASE VELOCITIES AT PEAK FREQ:'); +disp('--------------------------------------') +disp(strcat('Approx peak freq= ',num2str(w(wj)/2/pi),' Hz')); +disp(strcat('P velocity at peak freq= ',num2str(1./real(1./vp(wj))),' m/s')); +disp(strcat('S velocity at peak freq= ',num2str(1./real(1./vs(wj))),' m/s')); +disp(' '); +disp('--------------------------------------') +disp(' RECOMMENDED UNRELAXED MODULI:'); +disp('--------------------------------------') +disp(strcat('mu= ',num2str(SINF),' Pa')); +disp(strcat('lambda= ',num2str(LINF),' Pa')); +disp(strcat('VP associated= ',num2str(VPINF),' m/s')); +disp(strcat('VS associated= ',num2str(VSINF),' m/s')); + +disp(' '); + +figure,semilogx(w((end+1)/2:end)/2/pi,1./real(1./vp((end+1)/2:end))),ylabel('P-wave velocity (m/s)'),xlabel('Frequency (Hz)'),title('P-wave dispersion') +figure,semilogx(w((end+1)/2:end)/2/pi,1./real(1./vs((end+1)/2:end))),ylabel('S-wave velocity (m/s)'),xlabel('Frequency (Hz)'),title('S-wave dispersion') diff --git a/science/XYinElement.m b/science/XYinElement.m new file mode 100644 index 0000000..f9c95a2 --- /dev/null +++ b/science/XYinElement.m @@ -0,0 +1,60 @@ +function inside = XYinElement(x,y,xS,yS) +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @section LICENSE +% Copyright (c) SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% @section DESCRIPTION +% XYinElement +% XYInElement returns 1 if the point (xS/yS) is inside the +% element defined by XY, else it returns 0 +% adapted from SeisSol2Ds XYinElement function + +epsilon = 0.00001; % tolerance + +refFactor = 0.5; +VOL = volume(x,y); + +xi = refFactor/VOL*( ( x(3)*y(1) - x(1)*y(3) ) + xS*(y(3)-y(1)) + yS*(x(1)-x(3)) ); +eta = refFactor/VOL*( ( x(1)*y(2) - x(2)*y(1) ) + xS*(y(1)-y(2)) + yS*(x(2)-x(1)) ); + + +if (xi <(0.0-epsilon)) || (eta <(0.0-epsilon)) || (eta > (1.0-xi+epsilon)) + inside = 0; +else + inside = 1; +end + +function VOL = volume(x,y) +% Sarrus +VOL = 0.5*( (x(2)-x(1))*(y(3)-y(1))-(x(3)-x(1))*(y(2)-y(1)) ); diff --git a/science/asagiconv/SConstruct b/science/asagiconv/SConstruct new file mode 100644 index 0000000..2c14002 --- /dev/null +++ b/science/asagiconv/SConstruct @@ -0,0 +1,216 @@ +#! /usr/bin/python +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @author Sebastian Rettenberger (sebastian.rettenberger AT tum.de, http://www5.in.tum.de/wiki/index.php/Sebastian_Rettenberger) +# +# @section LICENSE +# Copyright (c) 2015-2016, SeisSol Group +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import sys + +# +# set possible variables +# +vars = Variables() + +# read parameters from a file if given +vars.AddVariables( + PathVariable( 'buildVariablesFile', 'location of the python file, which contains the build variables', None, PathVariable.PathIsFile ) +) +env = Environment(variables=vars) +if 'buildVariablesFile' in env: + vars = Variables(env['buildVariablesFile']) + +# PUML specific variables +vars.AddVariables( + PathVariable( 'buildDir', 'where to build the code', 'build', PathVariable.PathIsDirCreate ), + + EnumVariable( 'compileMode', 'mode of the compilation', 'release', + allowed_values=('debug', 'release') + ), + +# EnumVariable( 'parallelization', 'level of parallelization', 'none', +# allowed_values=('none', 'mpi') +# ), + +# BoolVariable( 'unitTests', 'builds additional unit tests', +# False +# ), + + EnumVariable( 'logLevel', + 'logging level. \'debug\' prints all information available, \'info\' prints information at runtime (time step, plot number), \'warning\' prints warnings during runtime, \'error\' is most basic and prints errors only', + 'info', + allowed_values=('debug', 'info', 'warning', 'error') + ) +) + +env.Tool('PrefixPathTool') + +# external variables +vars.AddVariables( + env['PREFIX_PATH_VARIABLE'], + + PathVariable( 'cc', + 'C compiler (default: gcc (serial), mpicc (parallel))', + None, + PathVariable.PathAccept ), + + PathVariable( 'cxx', + 'C++ compiler (default: g++ (serial), mpiCC (parallel))', + None, + PathVariable.PathAccept ), + + BoolVariable( 'useExecutionEnvironment', + 'set variables set in the execution environment', + True ) +) + +# generate help text +Help(vars.GenerateHelpText(env)) +if '-h' in sys.argv or '--help' in sys.argv: + import SCons + print SCons.Script.help_text + env.Exit() + +# handle unknown, maybe misspelled variables +unknownVariables = vars.UnknownVariables() + +# remove the buildVariablesFile from the list of unknown variables (used before) +if 'buildVariablesFile' in unknownVariables: + unknownVariables.pop('buildVariablesFile') + +# exit in the case of unknown variables +if unknownVariables: + print "*** The following build variables are unknown: " + str(unknownVariables.keys()) + env.Exit(1) + +# set environment +env = Environment(variables=vars) + +# Not parallelization currently supported +env['parallelization'] = 'none' + +# Set environment +if env['useExecutionEnvironment']: + env['ENV'] = os.environ + +# +# precompiler, compiler and linker flags +# + +# set compiler +if 'cc' in env: + env['CC'] = env['cxx'] +else: + if env['parallelization'] in ['mpi']: + env['CC'] = 'mpicc' + else: + env['CC'] = 'gcc' + +if 'cxx' in env: + env['CXX'] = env['cxx'] +else: + if env['parallelization'] in ['mpi']: + env['CXX'] = 'mpiCC' + else: + env['CXX'] = 'g++' + +# add parallel flag for mpi +if env['parallelization'] in ['mpi']: + env.Append(CPPDEFINES=['PARALLEL']) + +# set level of logger +if env['logLevel'] == 'debug': + env.Append(CPPDEFINES=['LOG_LEVEL=3']) +elif env['logLevel'] == 'info': + env.Append(CPPDEFINES=['LOG_LEVEL=2']) +elif env['logLevel'] == 'warning': + env.Append(CPPDEFINES=['LOG_LEVEL=1']) +elif env['logLevel'] == 'error': + env.Append(CPPDEFINES=['LOG_LEVEL=0']) +else: + assert(false) + +# Use openmp +#env.Append(CXXFLAGS = ['-fopenmp']) +#env.Append(LINKFLAGS= ['-fopenmp']) + +# compiler flags for generated kernels +env.Append(CXXFLAGS = ['-Wall', '-ansi', '-std=c++11']) +if env['compileMode'] == 'debug': + env.Append(CXXFLAGS=['-O0','-g']) +elif env['compileMode'] == 'release': + env.Append(CPPDEFINES=['NDEBUG']) + env.Append(CXXFLAGS=['-O2']) + +# add pathname to the list of directories which are search for include +env.Append(CPPPATH=['#/src']) +env.Append(CPPPATH=['#/../../submodules']) + +# Add prefix path +env.Tool('PrefixPathTool') + +# +# add libraries +# +# PStreams +env.Append(CPPPATH=['#/submodules/pstreams']) + +# eigen3 +env.Append(CPPPATH=['#/submodules/eigen3']) + +# netCDF +env.Tool('NetcdfTool', parallel=(env['parallelization'] in ['mpi']), required=True) + +# Proj4 +env.Tool('ProjTool', required=True) + +# PThread +env.Append(LIBS=['pthread']) + +build_dir = 'build' + +# build directory +env['execDir'] = env['buildDir']+'/bin' +env['buildDir'] = env['buildDir']+'/'+build_dir + +# get the source files +env.sourceFiles = [] + +Export('env') +SConscript('src/SConscript', variant_dir='#/'+env['buildDir'], src_dir='#/', duplicate=0) +Import('env') + +# build executable +env.Program('#/'+env['execDir']+'/asagiconv', env.sourceFiles) diff --git a/science/asagiconv/scripts/vx_lite_wrapper b/science/asagiconv/scripts/vx_lite_wrapper new file mode 100755 index 0000000..3fc45fc --- /dev/null +++ b/science/asagiconv/scripts/vx_lite_wrapper @@ -0,0 +1,11 @@ +#!/bin/bash + +VX_LITE=`which vx_lite` +VX_DIR=`dirname $VX_LITE` +VX_DIR=`dirname $VX_DIR` +MODEL_DIR=$VX_DIR/model + +# Number of elements (not important for vx_lite) +read line + +vx_lite -m $MODEL_DIR -z elev | awk '{print $1, $2, $3, $17, $18, $19}' diff --git a/science/asagiconv/src/SConscript b/science/asagiconv/src/SConscript new file mode 100644 index 0000000..fe69428 --- /dev/null +++ b/science/asagiconv/src/SConscript @@ -0,0 +1,45 @@ +#! /usr/bin/python +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @author Sebastian Rettenberger (rettenbs AT in.tum.de, http://www5.in.tum.de/wiki/index.php/Sebastian_Rettenberger,_M.Sc.) +# +# @section LICENSE +# Copyright (c) 2013, SeisSol Group +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +Import('env') + +env.sourceFiles.extend( + [env.Object('main.cpp')] + ) + +Export('env') diff --git a/science/asagiconv/src/main.cpp b/science/asagiconv/src/main.cpp new file mode 100644 index 0000000..01c762f --- /dev/null +++ b/science/asagiconv/src/main.cpp @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Sebastian Rettenberger (sebastian.rettenberger AT tum.de, http://www5.in.tum.de/wiki/index.php/Sebastian_Rettenberger) + * + * @section LICENSE + * Copyright (c) 2015-2016, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include +#include +#include + +#include + +#include + +#include + +#include + +#include + +#include "utils/args.h" +#include "utils/logger.h" +#include "utils/stringutils.h" + +const static float MIN_VALID = -10000; + +typedef Eigen::Array ularr3; +typedef Eigen::Array ularr2; + +struct inputData_t +{ + Eigen::Array3d minVert; + ularr3 gridSize; + Eigen::Array3d gridDist; + + const char* meshProj; + bool meshIsGeo; + const char* queryProj; + bool queryIsGeo; + + redi::rpstream& query; +}; + +/** + * Check netCDF return value for errors + */ +static void checkNcIError(int error) +{ + if (error != NC_NOERR) + logError() << "Error while reading netCDF file:" << nc_strerror(error); +} + +/** + * Check netCDF return value for errors + */ +static void checkNcOError(int error) +{ + if (error != NC_NOERR) + logError() << "Error while writing netCDF file:" << nc_strerror(error); +} + +/** + * The input thread for the query program + */ +static void* runInput(void* p) +{ + inputData_t* i = reinterpret_cast(p); + + // Project from mesh to sample code + unsigned long totalArea = i->gridSize(0) * i->gridSize(1); + double* projX = new double[totalArea]; + double* projY = new double[totalArea]; + + const bool meshIsGeo = i->meshIsGeo; + + for (unsigned long y = 0; y < i->gridSize(1); y++) { + for (unsigned long x = 0; x < i->gridSize(0); x++) { + ularr2 pos(x, y); + Eigen::Array2d coord = i->minVert.block<2,1>(0,0) + pos.cast() * i->gridDist.block<2,1>(0,0); + if (meshIsGeo) + coord *= Eigen::Array2d(DEG_TO_RAD, DEG_TO_RAD); + + projX[y*i->gridSize(0) + x] = coord(0); + projY[y*i->gridSize(0) + x] = coord(1); + } + } + + // Project coordinates + projPJ pjMesh = pj_init_plus(i->meshProj); + projPJ pjQuery = pj_init_plus(i->queryProj); + if (pj_transform(pjMesh, pjQuery, totalArea, 1, projX, projY, 0L) != 0) + logError() << "Coordinate transformation failed"; + + // Convert to degree + if (i->queryIsGeo) { + for (unsigned long x = 0; x < totalArea; x++) { + projX[x] *= RAD_TO_DEG; + projY[x] *= RAD_TO_DEG; + } + } + + // Send the input data + i->query << (totalArea * i->gridSize(2)) << std::endl; + for (unsigned long z = 0; z < i->gridSize(2); z++) { + double depth = i->minVert(2) + z * i->gridDist(2); + for (unsigned long x = 0; x < totalArea; x++) + i->query << projX[x] << ' ' << projY[x] << ' ' << depth << std::endl; + } + + // Send eof + i->query << redi::peof; + + delete [] projX; + delete [] projY; + + return 0L; +} + +static float vs2mu(float vs, float rho) +{ + return vs*vs * rho; +} + +static float vp2lambda(float vp, float rho, float mu) +{ + return vp*vp * rho - 2*mu; +} + +int main(int argc, char* argv[]) +{ + // Parse command line arguments + utils::Args args; + args.addOption("mesh", 'm', "The mesh for which the data should be collected"); + args.addOption("border", 'b', "Border around the mesh for which data should be included", + utils::Args::Required, false); + args.addOption("size", 's', "Size of the out grid (Format x:y:z)"); + args.addOption("query", 'q', "Path to the query program (Default: ./scripts/vx_lite_wrapper)", + utils::Args::Required, false); +// args.addOption("elevation", 'e', "Path to x_SRTM3, y_SRTM3, z_SRTM3 containing an elevation map\n" +// " If empty, elevation instead of elevation offset is used for querying.", +// utils::Args::Required, false); + // See http://spatialreference.org/ + args.addOption("mesh-proj", 0, "Mesh coordinate projection (Default: UTM11)", + utils::Args::Required, false); + args.addOption("mesh-proj-geo", 0, "Mesh coordinates are geographic locations (Default: No)", + utils::Args::Required, false); + args.addOption("query-proj", 0, "Query coordinate projection (Default: WGS84)", + utils::Args::Required, false); + args.addOption("query-proj-geo", 0, "Query coordinates are geographic locations (Default: Yes)", + utils::Args::Required, false); + args.addOption("paraview", 'p', "Viewable by Paraview", utils::Args::No, false); + args.addOption("chunk-size", 'c', "Chunk size for the netCDF file", + utils::Args::Required, false); + args.addAdditionalOption("output", "netCDF output file"); + + // Parse/check command line arguments + if (!args.parse(argc, argv) == utils::Args::Success) + return 1; + + // Get the grid size + std::vector sizeVec = utils::StringUtils::split(args.getArgument("size"), ':'); + if (sizeVec.size() != 3) + logError() << "Size format must be \"x:y:z\""; + ularr3 gridSize(utils::StringUtils::parse(sizeVec[0]), + utils::StringUtils::parse(sizeVec[1]), + utils::StringUtils::parse(sizeVec[2])); + + logInfo() << "Grid size:" << utils::nospace + << "[" << gridSize(0) << ", " << gridSize(1) << ", " << gridSize(2) << "]"; + + // Read the coordinates from the mesh + const char* mesh = args.getArgument("mesh"); + + int ncFile; + checkNcIError(nc_open(mesh, NC_NOWRITE, &ncFile)); + + // Get the number of partitions + int ncDimPart; + checkNcIError(nc_inq_dimid(ncFile, "partitions", &ncDimPart)); + size_t partitions; + checkNcIError(nc_inq_dimlen(ncFile, ncDimPart, &partitions)); + + // Get max number of vertices + int ncDimVertices; + checkNcIError(nc_inq_dimid(ncFile, "vertices", &ncDimVertices)); + size_t maxVertices; + checkNcIError(nc_inq_dimlen(ncFile, ncDimVertices, &maxVertices)); + + // Get min/max vertices + Eigen::Array3d minVert( + std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity()); + Eigen::Array3d maxVert( + -std::numeric_limits::infinity(), + -std::numeric_limits::infinity(), + -std::numeric_limits::infinity()); + + double* vertices = new double[maxVertices*3]; + + int ncVarVrtxSize; + checkNcIError(nc_inq_varid(ncFile, "vertex_size", &ncVarVrtxSize)); + int ncVarVrtxCoords; + checkNcIError(nc_inq_varid(ncFile, "vertex_coordinates", &ncVarVrtxCoords)); + for (size_t i = 0; i < partitions; i++) { + size_t start[3] = {i, 0, 0}; + int size; + checkNcIError(nc_get_var1_int(ncFile, ncVarVrtxSize, start, &size)); + + size_t count[3] = {1, static_cast(size), 3}; + checkNcIError(nc_get_vara_double(ncFile, ncVarVrtxCoords, start, count, vertices)); + + for (int j = 0; j < size; j++) { + Eigen::Array3d v = Eigen::Map(&vertices[j*3]); + + minVert = minVert.min(v); + maxVert = maxVert.max(v); + } + } + + checkNcIError(nc_close(ncFile)); + + delete [] vertices; + + // Add borders + double border = args.getArgument("border", 0.); + minVert -= Eigen::Array3d(border, border, border); + maxVert += Eigen::Array3d(border, border, border); + + logInfo() << "Grid dimension (incl. border):" << utils::nospace + << "[" << minVert(0) << ", " << minVert(1) << ", " << minVert(2) << "] x [" + << maxVert(0) << ", " << maxVert(1) << ", " << maxVert(2) << "]"; + + // Distance between grid points + Eigen::Vector3d gridDist = (maxVert - minVert) + * (gridSize - ularr3(1, 1, 1)).cast().inverse(); + + logInfo() << "Grid interval:" << utils::nospace + << "[" << gridDist(0) << ", " << gridDist(1) << ", " << gridDist(2) << "]"; + + // Create query process + redi::rpstream pstream(args.getArgument("query", "./scripts/vx_lite_wrapper"), + redi::pstreambuf::pstdin | redi::pstreambuf::pstdout); + + // Start the input and error thread + inputData_t inputData { + minVert, + gridSize, + gridDist, + args.getArgument("mesh-proj", "+proj=utm +zone=11 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"), + args.getArgument("mesh-proj-geo", false), + args.getArgument("query-proj", "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"), + args.getArgument("query-proj-geo", true), + pstream + }; + + pthread_t inputThread; + pthread_create(&inputThread, 0L, runInput, &inputData); + + // Viewable by Paraview? + bool paraview = args.getArgument("paraview", false); + + // Open the netCDF file + const char* outputName = args.getAdditionalArgument("output"); + checkNcOError(nc_create(outputName, NC_NETCDF4, &ncFile)); + + // Create dimensions + int ncDims[3]; + checkNcOError(nc_def_dim(ncFile, "x", gridSize(0), &ncDims[2])); + checkNcOError(nc_def_dim(ncFile, "y", gridSize(1), &ncDims[1])); + checkNcOError(nc_def_dim(ncFile, "z", gridSize(2), &ncDims[0])); + + // Create dimension variables + int ncX, ncY, ncZ; + checkNcOError(nc_def_var(ncFile, "x", NC_FLOAT, 1, &ncDims[2], &ncX)); + checkNcOError(nc_def_var(ncFile, "y", NC_FLOAT, 1, &ncDims[1], &ncY)); + checkNcOError(nc_def_var(ncFile, "z", NC_FLOAT, 1, &ncDims[0], &ncZ)); + + // Create variables + int ncData, ncRho, ncMu, ncLambda; + if (paraview) { + checkNcOError(nc_def_var(ncFile, "rho", NC_FLOAT, 3, ncDims, &ncRho)); + checkNcOError(nc_def_var(ncFile, "mu", NC_FLOAT, 3, ncDims, &ncMu)); + checkNcOError(nc_def_var(ncFile, "lambda", NC_FLOAT, 3, ncDims, &ncLambda)); + } else { + // Create compound type + int ncType; + checkNcOError(nc_def_compound(ncFile, 3*sizeof(float), "material", &ncType)); + checkNcOError(nc_insert_compound(ncFile, ncType, "rho", 0, NC_FLOAT)); + checkNcOError(nc_insert_compound(ncFile, ncType, "mu", sizeof(float), NC_FLOAT)); + checkNcOError(nc_insert_compound(ncFile, ncType, "lambda", 2*sizeof(float), NC_FLOAT)); + + checkNcOError(nc_def_var(ncFile, "data", ncType, 3, ncDims, &ncData)); + + if (args.isSet("chunk-size")) { + unsigned int chunkSize = args.getArgument("chunk-size"); + + size_t chunks[3] = {chunkSize, chunkSize, chunkSize}; + checkNcOError(nc_def_var_chunking(ncFile, ncData, NC_CHUNKED, chunks)); + } + } + + checkNcOError(nc_enddef(ncFile)); + + // Fill dimension variables + float* x = new float[gridSize(0)]; + for (unsigned int i = 0; i < gridSize(0); i++) { + x[i] = minVert(0) + gridDist(0) * i; + } + checkNcOError(nc_put_var_float(ncFile, ncX, x)); + delete [] x; + + float* y = new float[gridSize(1)]; + for (unsigned int i = 0; i < gridSize(1); i++) { + y[i] = minVert(1) + gridDist(1) * i; + } + checkNcOError(nc_put_var_float(ncFile, ncY, y)); + delete [] y; + + float* z = new float[gridSize(2)]; + for (unsigned int i = 0; i < gridSize(2); i++) { + z[i] = minVert(2) + gridDist(2) * i; + } + checkNcOError(nc_put_var_float(ncFile, ncZ, z)); + delete [] z; + + // Read the data from the query tool + unsigned long totalArea = gridSize(0) * gridSize(1); + float* data = new float[totalArea*3]; + + // Initialize data with invalid values + for (unsigned long i = 0; i < totalArea*3; i++) + data[i] = std::numeric_limits::infinity(); + + for (unsigned long z = 0; z < gridSize(2); z++) { + for (unsigned long i = 0; i < totalArea; i++) { + // Ignore the coordinates + float x, y, z; + pstream.out() >> x >> y >> z; + + float vp, vs, rho; + pstream.out() >> vp >> vs >> rho; + + float mu, lambda; + if (vp >= MIN_VALID && vs >= MIN_VALID && rho >= MIN_VALID) { + mu = vs2mu(vs, rho); + lambda = vp2lambda(vp, rho, mu); + + if (paraview) { + data[i] = rho; + data[i + totalArea] = mu; + data[i + totalArea*2] = lambda; + } else { + data[i*3] = rho; + data[i*3 + 1] = mu; + data[i*3 + 2] = lambda; + } + } else { + if (z == 0) + logError() << "Invalid value in deepest level."; + } + } + + size_t start[3] = {z, 0, 0}; + size_t count[3] = {1, gridSize(1), gridSize(0)}; + + if (paraview) { + checkNcOError(nc_put_vara_float(ncFile, ncRho, start, count, data)); + checkNcOError(nc_put_vara_float(ncFile, ncMu, start, count, &data[totalArea])); + checkNcOError(nc_put_vara_float(ncFile, ncLambda, start, count, &data[totalArea*2])); + } else { + checkNcOError(nc_put_vara(ncFile, ncData, start, count, data)); + } + } + + pthread_join(inputThread, 0L); + + // Cleanup + checkNcOError(nc_close(ncFile)); + + delete [] data; + + logInfo() << "Finished"; +} diff --git a/science/convert_faultreceivers.m b/science/convert_faultreceivers.m new file mode 100644 index 0000000..c694cdb --- /dev/null +++ b/science/convert_faultreceivers.m @@ -0,0 +1,85 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Alice Gabriel (gabriel AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/gabriel) +% +% @section LICENSE +% Copyright (c) 2013, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% CONVERT_FAULTRECEIVERS %%') +disp(' %% from fault COS to absolute COSIONS %%') +disp(' %% %%') +disp(' %% addition to place_faultreceivers.m %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Transform (along dip, along strike) 2D receiver coordinates ') +disp(' along arbitrary shaped faults into xyz coordinates ') +disp(' input: receiver dip and strike coordinates, fault dip and strike ') +disp(' output: receiver xyz coordinates') +disp(' '),disp(' ') +% +clear, close all; +format long +%read in receiver file +dip = input(' Dip of fault plane (angle between the fault and a horizontal plane, 0° to 90): ','s'); +dip = str2double(dip); +strike = input(' Strike of fault plane (direction of a line created by the intersection of a fault plane and a horizontal surface, 0° to 360°, relative to North: ','s'); +strike=str2double(strike); +rec_filename = input(' Filename of 2D receiver locations (along dip, along strike) on the fault (suffix ".dat" is appended): ','s'); +% +% load receiver stations +% +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); +% +%convert dip +% +recs(:,3)=st(:,1).*sin(degtorad(dip)); +recs(:,2)=st(:,1).*cos(degtorad(dip)); +% +%convert strike +% +recs(:,1)=st(:,2).*cos(degtorad(strike)); +disp(' Receiver coordinates:'); disp(' ') +disp(recs); +% +%write recs to file +% +fid_out = fopen([rec_filename ,'_coordinates.dat'],'w'); +fprintf(fid_out,'%20.12f%20.12f%20.12f\n',receivers'); +fclose(fid_out); +disp(' Receiver coordinates saved!'); +% diff --git a/science/distances.py b/science/distances.py new file mode 100644 index 0000000..cb56358 --- /dev/null +++ b/science/distances.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @author Martin van Driel (driel@geophysik.uni-muenchen.de) +# +# @section LICENSE +# Copyright (c) 2011, Martin van Driel +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +#--------------------------------------------------------------------- +# Purpose: compute distance to faces and nodes in the reference +# tetrahedron +#--------------------------------------------------------------------- +# +# usage: +# python distances.py +# +# input: +# assumes to find a file 'xi_eta_zeta.txt' in the working directory +# containing the reference coordinates of the stations +# +# output: +# produces to files 'dist_to_nodes.txt' and 'dist_to_faces.txt' containg the +# distance to the closest node an face of each station. Thresholds for +# warnings on the command line can be defined below. + +import numpy as np + +# define warning threshold: +# for nodes: +en = 1e-2 +# for faces: +ef = 1e-5 + +m = np.loadtxt('stations_xi_eta_zeta.txt') +dnodes = np.empty((m.shape[0], 4)) +dfaces = np.empty((m.shape[0], 4)) + +# compute distance to closest node +for i in np.arange(m.shape[0]): + dist1 = (m[i,0]**2 + m[i,1]**2 + m[i,2]**2)**.5 + dist2 = ((m[i,0]-1)**2 + m[i,1]**2 + m[i,2]**2)**.5 + dist3 = (m[i,0]**2 + (m[i,1]-1)**2 + m[i,2]**2)**.5 + dist4 = (m[i,0]**2 + m[i,1]**2 + (m[i,2]-1)**2)**.5 + dnodes[i] = np.sort((dist1, dist2, dist3, dist4)) + if dnodes[i,0] < en: + print 'station %d is close to a node, distance is: %1.2e' % (i,dnodes[i,0]) + +# write to file +np.savetxt('dist_to_nodes.txt', dnodes) + +nv4 = np.matrix([1.,1.,1.]) / np.sqrt(3) + +# compute distance to closest face +for i in np.arange(m.shape[0]): + vec = np.matrix([m[i,0]-1,m[i,1],m[i,2]]) + dist4 = (nv4 * vec.T)[0,0] + dfaces[i] = np.sort((m[i,0], m[i,1], m[i,2], np.abs(dist4))) + if dfaces[i,0] < en: + print 'station %d is close to a face, distance is: %1.2e' % (i,dfaces[i,0]) + +# write to file +np.savetxt('dist_to_faces.txt', dfaces) diff --git a/science/gambit_receivers.m b/science/gambit_receivers.m new file mode 100644 index 0000000..6c51d45 --- /dev/null +++ b/science/gambit_receivers.m @@ -0,0 +1,179 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% +% @section LICENSE +% Copyright (c) 2005, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% GAMBIT_RECEIVERS %%') +disp(' %% TO COMPUTE STATION ELEVATIONS %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Give Gambit mesh-file and station coordinates in order to compute') +disp(' the exact elevation of the stations on the particular Gambit mesh,') +disp(' which approximates the topography with piecewise linear polynomials') +disp(' in the surface triangulation!') +disp(' '),disp(' ') +clear, close all; + +filename = input(' Filename of mesh(suffix ".neu" is appended): ','s'); +fid = fopen([filename ,'.neu']); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +param = fscanf(fid,'%i',[6,1]); NX = param(1); NT = param(2); NG = param(3); NB = param(4); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +X = fscanf(fid,'%g',[4,NX]); X = X'; X(:,1) = []; X(:,3)=X(:,3)+rand(size(X(:,3)))*0.0000001; +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +tetra = fscanf(fid,'%g',[7,NT]); tetra = tetra'; tetra(:,1:3) = []; +junk = fgetl(fid); +for i = 1:NG + junk = fgetl(fid); + junk = fgetl(fid); + junk = fgetl(fid); + n = str2num(junk(30:39)); + junk = fgetl(fid); + junk = fgetl(fid); + ju = fscanf(fid,'%g',[10,ceil(n/10)]); +end +junk = fgetl(fid); +if(length(junk)==0) + junk = fgetl(fid); +end +for i = 1:NB + junk = fgetl(fid); + param = fscanf(fid,'%i',[5,1]); NS = param(3); + if (param(1)~=101) + junk = fgetl(fid); + TS = fscanf(fid,'%g',[3,NS]); LocalFace = TS(3,:)'; TS = TS(1,:)'; + junk = fgetl(fid); junk = fgetl(fid); + else + junk = fgetl(fid); + TS = fscanf(fid,'%g',[3,NS]); LocalFace = TS(3,:)'; TS = TS(1,:)'; + junk = fgetl(fid); break + end +end +fclose(fid); + +rec_filename = input(' Filename of receiver locations(suffix ".dat" is appended): ','s'); +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PLOT SURFACE TRIANGULATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +s_vert(1,:) = [1,3,2]; s_vert(2,:) = [1,2,4]; s_vert(3,:) = [2,3,4]; s_vert(4,:) = [1,4,3]; + +Y = []; tri = []; +j = 0; + +Y = X(tetra(TS(1),s_vert(LocalFace(1),:))',:); +tri = [1,2,3]; +for i = 2:NS + tmp = X(tetra(TS(i),s_vert(LocalFace(i),:))',:); + mem = ismember(Y,tmp); + mloc = ismember(tmp,Y); + a = find(sum(mem,2)==3); + b = find(sum(mloc,2)==3); + if length(b)>0 + tmp(b,:) = []; + end + Y = [Y;tmp]; + + trinew = [length(Y):-1:length(Y)-2]; + trinew = [a',trinew]; + tri = [tri;trinew(1:3)]; +% fill3(tmp(:,1),tmp(:,2),tmp(:,3),'r'); + if(mod(i,round(NS/10))==0) + j = j+1; + disp(sprintf(' %g percent done!',j*10)) + end +end + +%Print mesh information on screen +disp(sprintf('\n\tFound %g surface triangles',NS)); +disp(sprintf('\tFound %g surface stations with xyz-coordinates:',size(st,1))); +figure; hold on +trisurf(tri,Y(:,1),Y(:,2),Y(:,3),Y(:,3)); axis equal,xlabel('x'),ylabel('y'),zlabel('z') +%save surface triangulation for use by gambit_receivers_fast +X = Y; +disp(' Surface triangulation with vertices saved!'); disp(' ') +eval(['save ',filename,'_tri.mat tri']) +eval(['save ',filename,'_vert.mat X']) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% COMPUTE STATION ELEVATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +t = tsearch(Y(:,1),Y(:,2),tri,st(:,1),st(:,2)); +for i = 1:size(st,1) + %t(i) = tsearch(Y(:,1),Y(:,2),tri,st(i,1),st(i,2)); + v0 = Y(tri(t(i),1),:); + v1 = Y(tri(t(i),2),:); + v2 = Y(tri(t(i),3),:); + A = [1, v0(1), v0(2);1, v1(1), v1(2);1, v2(1), v2(2)]; + f = [v0(3);v1(3);v2(3)]; + c = A\f; + est(i) = c(1)+c(2)*st(i,1)+c(3)*st(i,2); +end +depth = input(' Specify depth to burry the receivers under the surface (in meters): '); +receivers = [st(:,1),st(:,2),est'-depth]; +plot3(st(:,1),st(:,2),est'-depth,'r*','MarkerSize',8) + +disp(' Receiver coordinates under topography:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +choice = input([' Save receiver coordinates as ',filename,'_receivers.dat ? (y/n)'], 's'); +if choice=='y' + dlmwrite([filename ,'_receivers.dat'], receivers, ... + 'delimiter','\t','newline','unix','precision','%16.4f') + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + +disp(' FINISHED'); diff --git a/science/gambit_receivers_fast.m b/science/gambit_receivers_fast.m new file mode 100644 index 0000000..d80c020 --- /dev/null +++ b/science/gambit_receivers_fast.m @@ -0,0 +1,104 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% +% @section LICENSE +% Copyright (c) 2005, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% GAMBIT_RECEIVERS_FAST %%') +disp(' %% TO COMPUTE STATION ELEVATIONS %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Uses a precomputed surface triangulation of a mesh-file and station ,') +disp(' coordinates in order to compute') +disp(' the exact elevation of the stations on the particular Gambit mesh,') +disp(' which approximates the topography with piecewise linear polynomials') +disp(' in the surface triangulation!') +disp(' '),disp(' ') +clear, close all; + +filename = input(' Filename of mesh(suffix "_tri.mat" and "_vert.mat" are appended): ','s'); + +disp(' Surface triangulation with vertices loaded!'); disp(' ') +eval(['load ',filename,'_tri.mat']); +eval(['load ',filename,'_vert.mat']); + +rec_filename = input(' Filename of receiver locations(suffix ".dat" is appended): ','s'); +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); + +%Print mesh information on screen +disp(sprintf('\n\tFound %g surface triangles',size(tri,1))); +disp(sprintf('\tFound %g surface stations with xyz-coordinates:',size(st,1))); +figure; hold on +trisurf(tri,X(:,1),X(:,2),X(:,3),X(:,3)); axis equal,xlabel('x'),ylabel('y'),zlabel('z') + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% COMPUTE STATION ELEVATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +t = tsearch(X(:,1),X(:,2),tri,st(:,1),st(:,2)); +for i = 1:size(st,1) + %t(i) = tsearch(X(:,1),X(:,2),tri,st(i,1),st(i,2)); + v0 = X(tri(t(i),1),:); + v1 = X(tri(t(i),2),:); + v2 = X(tri(t(i),3),:); + A = [1, v0(1), v0(2);1, v1(1), v1(2);1, v2(1), v2(2)]; + f = [v0(3);v1(3);v2(3)]; + c = A\f; + est(i) = c(1)+c(2)*st(i,1)+c(3)*st(i,2); +end +depth = input(' Specify depth to burry the receivers under the surface (in meters): '); +receivers = [st(:,1),st(:,2),est'-depth]; +plot3(st(:,1),st(:,2),est'-depth,'r*','MarkerSize',8) + +disp(' Receiver coordinates under topography:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +choice = input([' Save receiver coordinates as ',filename,'_receivers.dat ? (y/n)'], 's'); +if choice=='y' + dlmwrite([filename ,'_receivers.dat'], receivers, ... + 'delimiter','\t','newline','unix','precision','%16.4f') + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + +disp(' FINISHED'); diff --git a/science/gambit_receivers_fast_updated.m b/science/gambit_receivers_fast_updated.m new file mode 100644 index 0000000..ab2ca10 --- /dev/null +++ b/science/gambit_receivers_fast_updated.m @@ -0,0 +1,116 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% @author Alice Gabriel (gabriel AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/gabriel) +% +% @section LICENSE +% Copyright (c) 2005-2013, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% GAMBIT_RECEIVERS_FAST %%') +disp(' %% TO COMPUTE STATION ELEVATIONS %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Uses a precomputed surface triangulation of a mesh-file and station ,') +disp(' coordinates in order to compute') +disp(' the exact elevation of the stations on the particular Gambit mesh,') +disp(' which approximates the topography with piecewise linear polynomials') +disp(' in the surface triangulation!') +disp(' '),disp(' ') +clear, close all; + +filename = input(' Filename of mesh(suffix "_tri.mat" and "_vert.mat" are appended): ','s'); + +disp(' Surface triangulation with vertices loaded!'); disp(' ') +eval(['load ',filename,'_tri.mat']); +eval(['load ',filename,'_vert.mat']); + +rec_filename = input(' Filename of receiver locations(suffix ".dat" is appended): ','s'); +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); + +%Print mesh information on screen +disp(sprintf('\n\tFound %g surface triangles',size(tri,1))); +disp(sprintf('\tFound %g surface stations with xyz-coordinates:',size(st,1))); +figure; hold on +trisurf(tri,X(:,1),X(:,2),X(:,3),X(:,3)); axis equal,xlabel('x'),ylabel('y'),zlabel('z') + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% COMPUTE STATION ELEVATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +tr=triangulation(tri,X(:,1),X(:,2)); +Cedges = edges(tr); +dt = delaunayTriangulation(X(:,1),X(:,2), Cedges); +dtTotrIndex = nan(size(dt,1),1); +ic = incenter(tr); +dtid = pointLocation(dt,ic); +dtTotrIndex(dtid) = 1:size(tr,1); +t = pointLocation(dt,st(:,1),st(:,2)); +if isfinite(t) + t = dtTotrIndex(t); +end +%t = tsearch(X(:,1),X(:,2),tri,st(:,1),st(:,2)); !OBSOLETE +for i = 1:size(st,1) + %t(i) = tsearch(X(:,1),X(:,2),tri,st(i,1),st(i,2)); !OBSOLETE + v0 = X(tri(t(i),1),:); + v1 = X(tri(t(i),2),:); + v2 = X(tri(t(i),3),:); + A = [1, v0(1), v0(2);1, v1(1), v1(2);1, v2(1), v2(2)]; + f = [v0(3);v1(3);v2(3)]; + c = A\f; + est(i) = c(1)+c(2)*st(i,1)+c(3)*st(i,2); +end +depth = input(' Specify depth to burry the receivers under the surface (in mesh units): '); +receivers = [st(:,1),st(:,2),est'-depth]; +plot3(st(:,1),st(:,2),est'-depth,'r*','MarkerSize',8) + +disp(' Receiver coordinates under topography:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +choice = input([' Save receiver coordinates as ',filename,'_receivers.dat ? (y/n)'], 's'); +if choice=='y' + dlmwrite([filename ,'_receivers.dat'], receivers, ... + 'delimiter','\t','newline','unix','precision','%16.4f') + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + +disp(' FINISHED'); diff --git a/science/gambit_receivers_updated.m b/science/gambit_receivers_updated.m new file mode 100644 index 0000000..fae91b2 --- /dev/null +++ b/science/gambit_receivers_updated.m @@ -0,0 +1,191 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% @author Alice Gabriel (gabriel AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/gabriel) +% +% @section LICENSE +% Copyright (c) 2005-2013, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% GAMBIT_RECEIVERS %%') +disp(' %% TO COMPUTE STATION ELEVATIONS %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Give Gambit mesh-file and station coordinates in order to compute') +disp(' the exact elevation of the stations on the particular Gambit mesh,') +disp(' which approximates the topography with piecewise linear polynomials') +disp(' in the surface triangulation!') +disp(' '),disp(' ') +clear, close all; + +filename = input(' Filename of mesh(suffix ".neu" is appended): ','s'); +fid = fopen([filename ,'.neu']); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +param = fscanf(fid,'%i',[6,1]); NX = param(1); NT = param(2); NG = param(3); NB = param(4); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +X = fscanf(fid,'%g',[4,NX]); X = X'; X(:,1) = []; X(:,3)=X(:,3)+rand(size(X(:,3)))*0.0000001; +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +tetra = fscanf(fid,'%g',[7,NT]); tetra = tetra'; tetra(:,1:3) = []; +junk = fgetl(fid); +for i = 1:NG + junk = fgetl(fid); + junk = fgetl(fid); + junk = fgetl(fid); + n = str2num(junk(30:38)); + junk = fgetl(fid); + junk = fgetl(fid); + ju = fscanf(fid,'%g',[10,ceil(n/10)]); +end +junk = fgetl(fid); +if(length(junk)==0) + junk = fgetl(fid); +end +for i = 1:NB + junk = fgetl(fid); + param = fscanf(fid,'%i',[5,1]); NS = param(3); + if (param(1)~=101) + junk = fgetl(fid); + TS = fscanf(fid,'%g',[3,NS]); LocalFace = TS(3,:)'; TS = TS(1,:)'; + junk = fgetl(fid); junk = fgetl(fid); + else + junk = fgetl(fid); + TS = fscanf(fid,'%g',[3,NS]); LocalFace = TS(3,:)'; TS = TS(1,:)'; + junk = fgetl(fid); break + end +end +fclose(fid); + +rec_filename = input(' Filename of receiver locations(suffix ".dat" is appended): ','s'); +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PLOT SURFACE TRIANGULATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +s_vert(1,:) = [1,3,2]; s_vert(2,:) = [1,2,4]; s_vert(3,:) = [2,3,4]; s_vert(4,:) = [1,4,3]; + +Y = []; tri = []; +j = 0; + +Y = X(tetra(TS(1),s_vert(LocalFace(1),:))',:); +tri = [1,2,3]; +for i = 2:NS + tmp = X(tetra(TS(i),s_vert(LocalFace(i),:))',:); + mem = ismember(Y,tmp); + mloc = ismember(tmp,Y); + a = find(sum(mem,2)==3); + b = find(sum(mloc,2)==3); + if length(b)>0 + tmp(b,:) = []; + end + Y = [Y;tmp]; + + trinew = [length(Y):-1:length(Y)-2]; + trinew = [a',trinew]; + tri = [tri;trinew(1:3)]; +% fill3(tmp(:,1),tmp(:,2),tmp(:,3),'r'); + if(mod(i,round(NS/10))==0) + j = j+1; + disp(sprintf(' %g percent done!',j*10)) + end +end + +%Print mesh information on screen +disp(sprintf('\n\tFound %g surface triangles',NS)); +disp(sprintf('\tFound %g surface stations with xyz-coordinates:',size(st,1))); +figure; hold on +trisurf(tri,Y(:,1),Y(:,2),Y(:,3),Y(:,3)); axis equal,xlabel('x'),ylabel('y'),zlabel('z') +%save surface triangulation for use by gambit_receivers_fast +X = Y; +disp(' Surface triangulation with vertices saved!'); disp(' ') +eval(['save ',filename,'_tri.mat tri']) +eval(['save ',filename,'_vert.mat X']) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% COMPUTE STATION ELEVATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +tr=triangulation(tri,Y(:,1),Y(:,2)); +Cedges = edges(tr); +dt = delaunayTriangulation(Y(:,1),Y(:,2), Cedges); +dtTotrIndex = nan(size(dt,1),1); +ic = incenter(tr); +dtid = pointLocation(dt,ic); +dtTotrIndex(dtid) = 1:size(tr,1); +t = pointLocation(dt,st(:,1),st(:,2)); +if isfinite(t) + t = dtTotrIndex(t); +end +%t = tsearch(Y(:,1),Y(:,2),tri,st(:,1),st(:,2)); !OBSOLETE +for i = 1:size(st,1) + %t(i) = tsearch(Y(:,1),Y(:,2),tri,st(i,1),st(i,2)); !OBSOLETE + v0 = Y(tri(t(i),1),:); + v1 = Y(tri(t(i),2),:); + v2 = Y(tri(t(i),3),:); + A = [1, v0(1), v0(2);1, v1(1), v1(2);1, v2(1), v2(2)]; + f = [v0(3);v1(3);v2(3)]; + c = A\f; + est(i) = c(1)+c(2)*st(i,1)+c(3)*st(i,2); +end +depth = input(' Specify depth to burry the receivers under the surface (in mesh units): '); +receivers = [st(:,1),st(:,2),est'-depth]; +plot3(st(:,1),st(:,2),est'-depth,'r*','MarkerSize',8) + +disp(' Receiver coordinates under topography:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +choice = input([' Save receiver coordinates as ',filename,'_receivers.dat ? (y/n)'], 's'); +if choice=='y' + dlmwrite([filename ,'_receivers.dat'], receivers, ... + 'delimiter','\t','newline','unix','precision','%16.4f') + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + +disp(' FINISHED'); diff --git a/science/generating_ASAGI_file.py b/science/generating_ASAGI_file.py new file mode 100644 index 0000000..c746cb3 --- /dev/null +++ b/science/generating_ASAGI_file.py @@ -0,0 +1,83 @@ +import numpy as np +from netCDF4 import Dataset + + +def writeNetcdf4Paraview(sname, x, y, aName, aData): + "create a netcdf file readable by paraview (but not by ASAGI)" + fname = sname + "_paraview.nc" + print("writing " + fname) + ####Creating the netcdf file + nx = x.shape[0] + ny = y.shape[0] + rootgrp = Dataset(fname, "w", format="NETCDF4") + rootgrp.createDimension("u", nx) + rootgrp.createDimension("v", ny) + + vx = rootgrp.createVariable("u", "f4", ("u",)) + vx[:] = x + vy = rootgrp.createVariable("v", "f4", ("v",)) + vy[:] = y + for i in range(len(aName)): + vTd = rootgrp.createVariable(aName[i], "f4", ("v", "u")) + vTd[:, :] = aData[i][:, :] + rootgrp.close() + + +def writeNetcdf4SeisSol(sname, x, y, aName, aData): + "create a netcdf file readable by ASAGI (but not by paraview)" + ########## creating the file for SeisSol + fname = sname + "_ASAGI.nc" + print("writing " + fname) + ####Creating the netcdf file + nx = x.shape[0] + ny = y.shape[0] + + rootgrp = Dataset(fname, "w", format="NETCDF4") + + rootgrp.createDimension("u", nx) + rootgrp.createDimension("v", ny) + + vx = rootgrp.createVariable("u", "f4", ("u",)) + vx[:] = x + vy = rootgrp.createVariable("v", "f4", ("v",)) + vy[:] = y + ldata4 = [(name, "f4") for name in aName] + ldata8 = [(name, "f8") for name in aName] + mattype4 = np.dtype(ldata4) + mattype8 = np.dtype(ldata8) + mat_t = rootgrp.createCompoundType(mattype4, "material") + + # this transform the 4 D array into an array of tuples + arr = np.stack([aData[i] for i in range(len(aName))], axis=2) + newarr = arr.view(dtype=mattype8) + newarr = newarr.reshape(newarr.shape[:-1]) + mat = rootgrp.createVariable("data", mat_t, ("v", "u")) + mat[:] = newarr + rootgrp.close() + + +dx = 200.0 +nx = 40 +ny = 20 +x = np.linspace(0, nx - 1, nx) * dx +y = np.linspace(0, ny - 1, ny) * dx + +# Generate a Gaussian shaped slip distribution for illustration purposes +x0, y0 = 3000.0, 1500.0 +xg, yg = np.meshgrid(x, y) +d = np.sqrt((xg - x0) ** 2 + (yg - y0) ** 2) +mu = np.sqrt(x0 ** 2 + y0 ** 2) +sigma = 500.0 +slip = np.exp(-(d ** 2 / (2.0 * sigma ** 2))) +rake = 40 * np.ones((ny, nx)) * np.pi / 180.0 + + +strike_slip = slip * np.cos(rake) +dip_slip = slip * np.sin(rake) + +prefix = "test" +ldataName = ["strike_slip", "dip_slip"] +lgridded_myData = [strike_slip, dip_slip] + +writeNetcdf4Paraview(prefix, x, y, ldataName, lgridded_myData) +writeNetcdf4SeisSol(prefix, x, y, ldataName, lgridded_myData) diff --git a/science/icem_receivers.m b/science/icem_receivers.m new file mode 100644 index 0000000..d8aad48 --- /dev/null +++ b/science/icem_receivers.m @@ -0,0 +1,144 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% +% @section LICENSE +% Copyright (c) 2009, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% ICEM_RECEIVERS %%') +disp(' %% TO COMPUTE STATION ELEVATIONS %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Give ICEM mesh-file and station coordinates in order to compute') +disp(' the exact elevation of the stations on the particular ICEM mesh,') +disp(' which approximates the topography with piecewise linear polynomials') +disp(' in the surface triangulation!') +disp(' '),disp(' ') +clear, close all; + +filename = input(' Filename of mesh(suffix ".neu" is appended): ','s'); +fid = fopen([filename ,'.neu']); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +param = fscanf(fid,'%i',[5,1]); NX = param(1); NT = param(2); NG = param(3); NB = param(4); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +X = fscanf(fid,'%g',[4,NX]); X = X'; X(:,1) = []; %X(:,3)=X(:,3)+rand(size(X(:,3)))*0.0000001; +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +for g = 1:NG + junk = fgetl(fid); + group = str2num(junk(10:15)); + elements = str2num(junk(26:35)); + nodes = str2num(junk(50:55)); + geom = str2num(junk(67:70)); + type = str2num(junk(77:80)); + entity = fgetl(fid); + connect = fscanf(fid,'%g',[nodes+1,elements]); connect = connect'; + junk = fgetl(fid); + if(entity(end-4:end)=='BC101') + break + end +end + +tri = connect(:,2:4); +NS = size(tri,1); +rec_filename = input(' Filename of receiver locations(suffix ".dat" is appended): ','s'); +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PLOT SURFACE TRIANGULATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%Print mesh information on screen +disp(sprintf('\n\tFound %g surface triangles',NS)); +disp(sprintf('\tFound %g surface stations with xyz-coordinates:\n',size(st,1))); +figure; hold on +trisurf(tri,X(:,1),X(:,2),X(:,3),X(:,3)); axis equal,xlabel('x'),ylabel('y'),zlabel('z') +%save surface triangulation for use by gambit_receivers_fast +disp(' Surface triangulation with vertices saved!'); disp(' ') +eval(['save ',filename,'_tri.mat tri']) +eval(['save ',filename,'_vert.mat X']) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% COMPUTE STATION ELEVATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +t = tsearch(X(:,1),X(:,2),tri,st(:,1),st(:,2)); +for i = 1:size(st,1) + %t(i) = tsearch(X(:,1),X(:,2),tri,st(i,1),st(i,2)); + v0 = X(tri(t(i),1),:); + v1 = X(tri(t(i),2),:); + v2 = X(tri(t(i),3),:); + A = [1, v0(1), v0(2);1, v1(1), v1(2);1, v2(1), v2(2)]; + f = [v0(3);v1(3);v2(3)]; + c = A\f; + est(i) = c(1)+c(2)*st(i,1)+c(3)*st(i,2); +end +depth = input(' Specify depth to burry the receivers under the surface (in meters): '); +receivers = [st(:,1),st(:,2),est'-depth]; +plot3(st(:,1),st(:,2),est','r*','MarkerSize',8) + +disp(' Receiver coordinates under topography:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +choice = input([' Save receiver coordinates as ',filename,'_receivers.dat ? (y/n)'], 's'); +if choice=='y' + fid_out = fopen([filename ,'_receivers.dat'],'w'); + fprintf(fid_out,'\n%10.1f%10.1f%10.1f',receivers'); + fclose(fid_out); + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + +disp(' FINISHED'); diff --git a/science/icem_receivers_sphere.m b/science/icem_receivers_sphere.m new file mode 100644 index 0000000..c6f41fa --- /dev/null +++ b/science/icem_receivers_sphere.m @@ -0,0 +1,157 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% +% @section LICENSE +% Copyright (c) 2009, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% ICEM_RECEIVERS_GLOBAL %%') +disp(' %% TO COMPUTE STATION ELEVATIONS ON A SPHERE %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Give ICEM mesh-file and station coordinates for a sphere in order to compute') +disp(' the exact elevation of the stations on the particular ICEM mesh,') +disp(' which approximates the topography with piecewise linear polynomials') +disp(' in the surface triangulation!') +disp(' '),disp(' ') +clear, close all; + +filename = input(' Filename of mesh(suffix ".neu" is appended): ','s'); +fid = fopen([filename ,'.neu']); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +param = fscanf(fid,'%i',[5,1]); NX = param(1); NT = param(2); NG = param(3); NB = param(4); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +X = fscanf(fid,'%g',[4,NX]); X = X'; X(:,1) = []; %X(:,3)=X(:,3)+rand(size(X(:,3)))*0.0000001; +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +for g = 1:NG + junk = fgetl(fid); + group = str2num(junk(10:15)); + elements = str2num(junk(26:35)); + nodes = str2num(junk(50:55)); + geom = str2num(junk(67:70)); + type = str2num(junk(77:80)); + entity = fgetl(fid); + connect = fscanf(fid,'%g',[nodes+1,elements]); connect = connect'; + junk = fgetl(fid); + if(entity(end-4:end)=='BC101') + break + end +end + +tri = connect(:,2:4); +NS = size(tri,1); +rec_filename = input(' Filename of receiver locations(suffix ".dat" is appended): ','s'); +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PLOT SURFACE TRIANGULATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%Print mesh information on screen +disp(sprintf('\n\tFound %g surface triangles',NS)); +disp(sprintf('\tFound %g surface stations with xyz-coordinates:\n',size(st,1))); +figure; hold on +trisurf(tri,X(:,1),X(:,2),X(:,3),X(:,3)); axis equal,xlabel('x'),ylabel('y'),zlabel('z') +%save surface triangulation for use by gambit_receivers_fast +disp(' Surface triangulation with vertices saved!'); disp(' ') +eval(['save ',filename,'_tri.mat tri']) +eval(['save ',filename,'_vert.mat X']) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% COMPUTE STATION ELEVATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +t = tsearch(X(:,1),X(:,2),tri,st(:,1),st(:,2)); +for i = 1:size(st,1) + %t(i) = tsearch(X(:,1),X(:,2),tri,st(i,1),st(i,2)); + v0 = X(tri(t(i),1),:); + v1 = X(tri(t(i),2),:); + v2 = X(tri(t(i),3),:); + A = [1, v0(1), v0(2);1, v1(1), v1(2);1, v2(1), v2(2)]; + f = [v0(3);v1(3);v2(3)]; + c = A\f; + est(i) = c(1)+c(2)*st(i,1)+c(3)*st(i,2); +end +st(:,3) = est'; + +%transformation from cartesian to spherical coordinates +r = sqrt(st(:,1).^2+st(:,2).^2+st(:,3).^2); +long = atan(st(:,2)./st(:,1)); +lat = atan(sqrt(st(:,1).^2+st(:,2).^2)./st(:,3)); + +depth = input(' Specify depth to burry the receivers under the surface (pos. value): '); +r = r - depth; + +%back-transformation from spherical to cartesian coordinates +st(:,1) = r.*sin(lat).*cos(long); +st(:,2) = r.*sin(lat).*sin(long); +st(:,3) = r.*cos(lat); +receivers = [st(:,1),st(:,2),st(:,3)]; + +plot3(st(:,1),st(:,2),st(:,3),'r*','MarkerSize',8) +disp(' Receiver coordinates under topography:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +choice = input([' Save receiver coordinates as ',filename,'_receivers.dat ? (y/n)'], 's'); +if choice=='y' + fid_out = fopen([filename ,'_receivers.dat'],'w'); + fprintf(fid_out,'\n%10.1f%10.1f%10.1f',receivers'); + fclose(fid_out); + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + +disp(' FINISHED'); diff --git a/science/kinematic_models/FaultPlane.py b/science/kinematic_models/FaultPlane.py new file mode 100644 index 0000000..d52ca9c --- /dev/null +++ b/science/kinematic_models/FaultPlane.py @@ -0,0 +1,742 @@ +import numpy as np +import pyproj +import scipy.ndimage +from scipy import interpolate +from netCDF4 import Dataset +from Yoffe import regularizedYoffe +from scipy import ndimage +from GaussianSTF import GaussianSTF +from scipy.interpolate import RegularGridInterpolator +import xarray as xr + + +def writeNetcdf(sname, lDimVar, lName, lData, paraview_readable=False): + """create a netcdf file either readable by ASAGI + or by paraview (paraview_readable=True) + + Parameters + ---------- + sname: str prefix name of output file + lDimVar: list of 1d numpy array containing the dimension variables + lName: list if str containing the name of the nd variables + lData: list if n-d numpy array containing the data + paraview_readable: bool + """ + fname = f"{sname}.nc" + print("writing " + fname) + + with Dataset(fname, "w", format="NETCDF4") as rootgrp: + # Create dimension and 1d variables + sdimVarNames = "uvwxyz" + dims = [] + for i, xi in enumerate(lDimVar): + nxi = xi.shape[0] + dimName = sdimVarNames[i] + dims.append(dimName) + rootgrp.createDimension(dimName, nxi) + vx = rootgrp.createVariable(dimName, "f4", (dimName,)) + vx[:] = xi + dims.reverse() + dims = tuple(dims) + + if paraview_readable: + for i in range(len(lName)): + vTd = rootgrp.createVariable(lName[i], "f4", dims) + vTd[:] = lData[i] + else: + ldata4 = [(name, "f4") for name in lName] + ldata8 = [(name, "f8") for name in lName] + mattype4 = np.dtype(ldata4) + mattype8 = np.dtype(ldata8) + mat_t = rootgrp.createCompoundType(mattype4, "material") + + # this transform the nD array into an array of tuples + arr = np.stack([lData[i] for i in range(len(lName))], axis=len(dims)) + arr = np.ascontiguousarray(arr) + newarr = arr.view(dtype=mattype8) + newarr = newarr.reshape(newarr.shape[:-1]) + mat = rootgrp.createVariable("data", mat_t, dims) + mat[:] = newarr + + +def cosine_taper(npts, p=0.1, freqs=None, flimit=None, halfcosine=True, sactaper=False): + """ + Cosine Taper. (copied from obspy: + https://docs.obspy.org/master/_modules/obspy/signal/invsim.html#cosine_taper + + :type npts: int + :param npts: Number of points of cosine taper. + :type p: float + :param p: Decimal percentage of cosine taper (ranging from 0 to 1). Default + is 0.1 (10%) which tapers 5% from the beginning and 5% form the end. + :rtype: float NumPy :class:`~numpy.ndarray` + :return: Cosine taper array/vector of length npts. + :type freqs: NumPy :class:`~numpy.ndarray` + :param freqs: Frequencies as, for example, returned by fftfreq + :type flimit: list or tuple of floats + :param flimit: The list or tuple defines the four corner frequencies + (f1, f2, f3, f4) of the cosine taper which is one between f2 and f3 and + tapers to zero for f1 < f < f2 and f3 < f < f4. + :type halfcosine: bool + :param halfcosine: If True the taper is a half cosine function. If False it + is a quarter cosine function. + :type sactaper: bool + :param sactaper: If set to True the cosine taper already tapers at the + corner frequency (SAC behavior). By default, the taper has a value + of 1.0 at the corner frequencies. + + .. rubric:: Example + + >>> tap = cosine_taper(100, 1.0) + >>> tap2 = 0.5 * (1 + np.cos(np.linspace(np.pi, 2 * np.pi, 50))) + >>> np.allclose(tap[0:50], tap2) + True + >>> npts = 100 + >>> p = 0.1 + >>> tap3 = cosine_taper(npts, p) + >>> (tap3[int(npts*p/2):int(npts*(1-p/2))]==np.ones(int(npts*(1-p)))).all() + True + """ + if p < 0 or p > 1: + msg = "Decimal taper percentage must be between 0 and 1." + raise ValueError(msg) + if p == 0.0 or p == 1.0: + frac = int(npts * p / 2.0) + else: + frac = int(npts * p / 2.0 + 0.5) + + if freqs is not None and flimit is not None: + fl1, fl2, fl3, fl4 = flimit + idx1 = np.argmin(abs(freqs - fl1)) + idx2 = np.argmin(abs(freqs - fl2)) + idx3 = np.argmin(abs(freqs - fl3)) + idx4 = np.argmin(abs(freqs - fl4)) + else: + idx1 = 0 + idx2 = frac - 1 + idx3 = npts - frac + idx4 = npts - 1 + if sactaper: + # in SAC the second and third + # index are already tapered + idx2 += 1 + idx3 -= 1 + + # Very small data lengths or small decimal taper percentages can result in + # idx1 == idx2 and idx3 == idx4. This breaks the following calculations. + if idx1 == idx2: + idx2 += 1 + if idx3 == idx4: + idx3 -= 1 + + # the taper at idx1 and idx4 equals zero and + # at idx2 and idx3 equals one + cos_win = np.zeros(npts) + if halfcosine: + # cos_win[idx1:idx2+1] = 0.5 * (1.0 + np.cos((np.pi * \ + # (idx2 - np.arange(idx1, idx2+1)) / (idx2 - idx1)))) + cos_win[idx1 : idx2 + 1] = 0.5 * (1.0 - np.cos((np.pi * (np.arange(idx1, idx2 + 1) - float(idx1)) / (idx2 - idx1)))) + cos_win[idx2 + 1 : idx3] = 1.0 + cos_win[idx3 : idx4 + 1] = 0.5 * (1.0 + np.cos((np.pi * (float(idx3) - np.arange(idx3, idx4 + 1)) / (idx4 - idx3)))) + else: + cos_win[idx1 : idx2 + 1] = np.cos(-(np.pi / 2.0 * (float(idx2) - np.arange(idx1, idx2 + 1)) / (idx2 - idx1))) + cos_win[idx2 + 1 : idx3] = 1.0 + cos_win[idx3 : idx4 + 1] = np.cos((np.pi / 2.0 * (float(idx3) - np.arange(idx3, idx4 + 1)) / (idx4 - idx3))) + + # if indices are identical division by zero + # causes NaN values in cos_win + if idx1 == idx2: + cos_win[idx1] = 0.0 + if idx3 == idx4: + cos_win[idx3] = 0.0 + return cos_win + + +def interpolate_nan_from_neighbors(array): + """rise_time and tacc may not be defined where there is no slip (no SR function). + in this case, we interpolate from neighbors + source: https://stackoverflow.com/questions/37662180/interpolate-missing-values-2d-python + """ + x = np.arange(0, array.shape[1]) + y = np.arange(0, array.shape[0]) + # mask invalid values + array = np.ma.masked_invalid(array) + xx, yy = np.meshgrid(x, y) + # get only the valid values + x1 = xx[~array.mask] + y1 = yy[~array.mask] + newarr = array[~array.mask] + return interpolate.griddata((x1, y1), newarr.ravel(), (xx, yy), method="linear", fill_value=np.average(array)) + + +def compute_block_mean(ar, fact): + a = xr.DataArray(ar, dims=["x", "y"]) + return a.coarsen(x=fact, y=fact).mean().to_numpy() + + +def upsample_quantities(allarr, spatial_order, spatial_zoom, padding="constant", extra_padding_layer=False, minimize_block_average_variations=False): + """1. pad + 2. upsample, adding spatial_zoom per node + """ + nd = allarr.shape[0] + ny, nx = [val * spatial_zoom for val in allarr[0].shape] + if extra_padding_layer: + # required for vertex aligned netcdf format + nx = nx + 2 + ny = ny + 2 + allarr0 = np.zeros((nd, ny, nx)) + for k in range(nd): + if padding == "extrapolate": + my_array0 = np.pad(allarr[k, :, :], ((1, 1), (1, 1)), "reflect", reflect_type="odd") + else: + my_array0 = np.pad(allarr[k, :, :], ((1, 1), (1, 1)), padding) + if extra_padding_layer: + ncrop = spatial_zoom - 1 + else: + ncrop = spatial_zoom + my_array = scipy.ndimage.zoom(my_array0, spatial_zoom, order=spatial_order, mode="grid-constant", grid_mode=True) + if minimize_block_average_variations: + # inspired by Tinti et al. (2005) (Appendix A) + # This is for the specific case of fault slip. + # We want to preserve the seismic moment of each subfault after interpolation + # the rock rigidity is not know by this script (would require some python binding of easi). + # the subfault area is typically constant over the kinematic model + # So we just want to perserve subfault average. + print("trying to perserve subfault average...") + my_array = np.maximum(0, my_array) + best_misfit = float("inf") + # The algorithm does not seem to converge, but produces better model + # (given the misfit) that inital after 2-3 iterations + niter = 30 + for i in range(niter): + block_average = compute_block_mean(my_array, spatial_zoom) + correction = my_array0 / block_average + # having a misfit as misfit = np.linalg.norm(correction) does not makes sense as for almost 0 slip, correction can be large + misfit = np.linalg.norm(my_array0 - block_average) / len(my_array0) + if best_misfit > misfit: + if i == 0: + print(f"misfit at iter {i}: {misfit}") + else: + print(f"misfit improved at iter {i}: {misfit}") + best_misfit = misfit + best = np.copy(my_array) + my_array = scipy.ndimage.zoom(correction * my_array0, spatial_zoom, order=spatial_order, mode="grid-constant", grid_mode=True) + my_array = np.maximum(0, my_array) + my_array = best + if ncrop > 0: + allarr0[k, :, :] = my_array[ncrop:-ncrop, ncrop:-ncrop] + else: + allarr0[k, :, :] = my_array + + return allarr0 + + +class FaultPlane: + def __init__(self): + self.nx = 0 + self.ny = 0 + self.ndt = 0 + self.PSarea_cm2 = 0 + self.dt = 0 + # array member initialized to dummy value + self.lon = 0 + self.lat = 0 + self.x = 0 + self.y = 0 + self.depth = 0 + self.t0 = 0 + self.slip1 = 0 + self.strike = 0 + self.dip = 0 + self.rake = 0 + self.aSR = 0 + self.myt = 0 + + def init_spatial_arrays(self, nx, ny): + self.nx = nx + self.ny = ny + self.lon = np.zeros((ny, nx)) + self.lat = np.zeros((ny, nx)) + self.x = np.zeros((ny, nx)) + self.y = np.zeros((ny, nx)) + self.depth = np.zeros((ny, nx)) + self.t0 = np.zeros((ny, nx)) + self.slip1 = np.zeros((ny, nx)) + self.strike = np.zeros((ny, nx)) + self.dip = np.zeros((ny, nx)) + self.rake = np.zeros((ny, nx)) + + def init_aSR(self): + self.aSR = np.zeros((self.ny, self.nx, self.ndt)) + + def extend_aSR(self, ndt_old, ndt_new): + "extend aSR array to more time samplings" + tmpSR = np.copy(self.aSR) + self.ndt = ndt_new + self.aSR = np.zeros((self.ny, self.nx, self.ndt)) + self.aSR[:, :, 0:ndt_old] = tmpSR[:, :, :] + + def compute_xy_from_latlon(self, proj): + if proj: + from pyproj import Transformer + + transformer = Transformer.from_crs("epsg:4326", proj[0], always_xy=True) + self.x, self.y = transformer.transform(self.lon, self.lat) + else: + print("no proj string specified!") + self.x, self.y = self.lon, self.lat + + def compute_latlon_from_xy(self, proj): + if proj: + from pyproj import Transformer + + transformer = Transformer.from_crs(proj[0], "epsg:4326", always_xy=True) + self.lon, self.lat = transformer.transform(self.x, self.y) + else: + self.lon, self.lat = self.x, self.y + + def compute_time_array(self): + self.myt = np.linspace(0, (self.ndt - 1) * self.dt, self.ndt) + + def write_srf(self, fname): + "write kinematic model to a srf file (standard rutpure format)" + with open(fname, "w") as fout: + fout.write("1.0\n") + fout.write("POINTS %d\n" % (self.nx * self.ny)) + for j in range(self.ny): + for i in range(self.nx): + fout.write("%g %g %g %g %g %e %g %g\n" % (self.lon[j, i], self.lat[j, i], self.depth[j, i], self.strike[j, i], self.dip[j, i], self.PSarea_cm2, self.t0[j, i], self.dt)) + fout.write("%g %g %d %f %d %f %d\n" % (self.rake[j, i], self.slip1[j, i], self.ndt, 0.0, 0, 0.0, 0)) + np.savetxt(fout, self.aSR[j, i, :], fmt="%g", newline=" ") + fout.write("\n") + print("done writing", fname) + + def init_from_srf(self, fname): + "init object by reading a srf file (standard rutpure format)" + with open(fname) as fid: + # version + line = fid.readline() + version = float(line) + if not (abs(version - 1.0) < 1e-03 or abs(version - 2.0) < 1e-03): + print("srf version: %s not supported" % (line)) + raise + # skip comments + while True: + line = fid.readline() + if not line.startswith("#"): + break + line_el = line.split() + if line_el[0] != "PLANE": + print("no plane specified") + raise + if line_el[1] != "1": + print("only one plane supported") + raise NotImplementedError + line_el = fid.readline().split() + nx, ny = [int(val) for val in line_el[2:4]] + line_el = fid.readline().split() + # check that the plane data are consistent with the number of points + assert int(line_el[1]) == nx * ny + self.init_spatial_arrays(nx, ny) + for j in range(ny): + for i in range(nx): + # first header line + line = fid.readline() + # rho_vs are only present for srf version 2 + self.lon[j, i], self.lat[j, i], self.depth[j, i], self.strike[j, i], self.dip[j, i], self.PSarea_cm2, self.t0[j, i], dt, *rho_vs = [float(v) for v in line.split()] + # second header line + line = fid.readline() + self.rake[j, i], self.slip1[j, i], ndt1, slip2, ndt2, slip3, ndt3 = [float(v) for v in line.split()] + if max(slip2, slip3) > 0.0: + print("this script assumes slip2 and slip3 are zero", slip2, slip3) + raise NotImplementedError + ndt1 = int(ndt1) + if max(i, j) == 0: + self.ndt = ndt1 + self.dt = dt + self.init_aSR() + lSTF = [] + if ndt1 == 0: + continue + if ndt1 > self.ndt: + print(f"a larger ndt ({ndt1}> {self.ndt}) was found for point source (i,j) = ({i}, {j}) extending aSR array...") + self.extend_aSR(self.ndt, ndt1) + if abs(dt - self.dt) > 1e-6: + print("this script assumes that dt is the same for all sources", dt, self.dt) + raise NotImplementedError + while True: + line = fid.readline() + lSTF.extend(line.split()) + if len(lSTF) == ndt1: + self.aSR[j, i, 0:ndt1] = np.array([float(v) for v in lSTF]) + break + + def assess_STF_parameters(self, threshold): + "compute rise_time (slip duration) and t_acc (peak SR) from SR time histories" + assert threshold >= 0.0 and threshold < 1 + self.rise_time = np.zeros((self.ny, self.nx)) + self.tacc = np.zeros((self.ny, self.nx)) + misfits_Yoffe = [] + misfits_Gaussian = [] + for j in range(self.ny): + for i in range(self.nx): + if not self.slip1[j, i]: + self.rise_time[j, i] = np.nan + self.tacc[j, i] = np.nan + else: + peakSR = np.amax(self.aSR[j, i, :]) + id_max = np.where(self.aSR[j, i, :] == peakSR)[0][0] + ids_greater_than_threshold = np.where(self.aSR[j, i, :] > threshold * peakSR)[0] + first_non_zero = np.amin(ids_greater_than_threshold) + last_non_zero = np.amax(ids_greater_than_threshold) + self.rise_time[j, i] = (last_non_zero - first_non_zero + 1) * self.dt + self.tacc[j, i] = (id_max - first_non_zero + 1) * self.dt + t0_increment = first_non_zero * self.dt + self.t0[j, i] += t0_increment + # 2 dims: 0: Yoffe 1: Gaussian + newSR = np.zeros((self.ndt, 2)) + # Ts and Td parameters of the Yoffe function have no direct physical meaning + # Tinti et al. (2005) suggest that Ts can nevertheless be associated with the acceleration time tacc + # Empirically, they find that Ts and Tacc are for most (Ts,Td) parameter sets linearly related + # with the 'magic' number 1.27 + ts = self.tacc[j, i] / 1.27 + tr = self.rise_time[j, i] - 2.0 * ts + tr = max(tr, ts) + for k, tk in enumerate(self.myt): + newSR[k, 0] = regularizedYoffe(tk - t0_increment, ts, tr) + newSR[k, 1] = GaussianSTF(tk - t0_increment, self.rise_time[j, i], self.dt) + integral_aSTF = np.trapz(np.abs(self.aSR[j, i, :]), dx=self.dt) + integral_Yoffe = np.trapz(np.abs(newSR[:, 0]), dx=self.dt) + integral_Gaussian = np.trapz(np.abs(newSR[:, 1]), dx=self.dt) + if integral_aSTF > 0: + misfits_Yoffe.append(np.linalg.norm(self.aSR[j, i, :] / integral_aSTF - newSR[:, 0] / integral_Yoffe)) + misfits_Gaussian.append(np.linalg.norm(self.aSR[j, i, :] / integral_aSTF - newSR[:, 1] / integral_Gaussian)) + misfits_Yoffe = np.array(misfits_Yoffe) + misfits_Gaussian = np.array(misfits_Gaussian) + print(f"misfit Yoffe (10-50-90%): {np.percentile(misfits_Yoffe,10):.2f} {np.percentile(misfits_Yoffe,50):.2f} {np.percentile(misfits_Yoffe,90):.2f}") + print(f"misfit Gaussian (10-50-90%): {np.percentile(misfits_Gaussian,10):.2f} {np.percentile(misfits_Gaussian,50):.2f} {np.percentile(misfits_Gaussian,90):.2f}") + + self.rise_time = interpolate_nan_from_neighbors(self.rise_time) + self.tacc = interpolate_nan_from_neighbors(self.tacc) + + print("slip rise_time (min, 50%, max)", np.amin(self.rise_time), np.median(self.rise_time), np.amax(self.rise_time)) + print("tacc (min, 50%, max)", np.amin(self.tacc), np.median(self.tacc), np.amax(self.tacc)) + + def upsample_fault(self, spatial_order, spatial_zoom, temporal_zoom, proj, use_Yoffe=False, time_smoothing_kernel_as_dt_fraction=0.5): + "increase spatial and temporal resolution of kinematic model by interpolation" + # time vector + ndt2 = (self.ndt - 1) * temporal_zoom + 1 + ny2, nx2 = self.ny * spatial_zoom, self.nx * spatial_zoom + # resampled source + pf = FaultPlane() + pf.init_spatial_arrays(nx2, ny2) + pf.ndt = ndt2 + pf.init_aSR() + + pf.dt = self.dt / temporal_zoom + pf.compute_time_array() + + # upsample spatially geometry (bilinear interpolation) + allarr = np.array([self.x, self.y, self.depth]) + pf.x, pf.y, pf.depth = upsample_quantities(allarr, spatial_order=1, spatial_zoom=spatial_zoom, padding="extrapolate") + + # upsample other quantities + allarr = np.array([self.t0, self.strike, self.dip, self.rake]) + pf.t0, pf.strike, pf.dip, pf.rake = upsample_quantities(allarr, spatial_order, spatial_zoom, padding="edge") + # the interpolation may generate some acausality that we here prevent + pf.t0 = np.maximum(pf.t0, np.amin(self.t0)) + + allarr = np.array([self.slip1]) + (pf.slip1,) = upsample_quantities(allarr, spatial_order, spatial_zoom, padding="constant", minimize_block_average_variations=True) + pf.compute_latlon_from_xy(proj) + pf.PSarea_cm2 = self.PSarea_cm2 / spatial_zoom**2 + ratio_potency = np.sum(pf.slip1) * pf.PSarea_cm2 / (np.sum(self.slip1) * self.PSarea_cm2) + print(f"seismic potency ratio (upscaled over initial): {ratio_potency}") + + if use_Yoffe: + allarr = np.array([self.rise_time, self.tacc]) + pf.rise_time, pf.tacc = upsample_quantities(allarr, spatial_order, spatial_zoom, padding="edge") + pf.rise_time = np.maximum(pf.rise_time, np.amin(self.rise_time)) + pf.tacc = np.maximum(pf.tacc, np.amin(self.tacc)) + # see comment above explaining why the 1.27 factor + print("using ts = tacc / 1.27 to compute the regularized Yoffe") + ts = pf.tacc / 1.27 + tr = pf.rise_time - 2.0 * ts + tr = np.maximum(tr, ts) + for j in range(pf.ny): + for i in range(pf.nx): + for k, tk in enumerate(pf.myt): + pf.aSR[j, i, k] = pf.slip1[j, i] * regularizedYoffe(tk, ts[j, i], tr[j, i]) + else: + aSRa = np.zeros((pf.ny, pf.nx, self.ndt)) + for k in range(self.ndt): + aSRa[:, :, k] = upsample_quantities(np.array([self.aSR[:, :, k]]), spatial_order, spatial_zoom, padding="constant") + + # interpolate temporally the AST + for j in range(pf.ny): + for i in range(pf.nx): + # 1. upsample with linear interpolation + # 2. apply a gauss kernel to smooth out sharp edges + # 3. tapper the signal smoothly to 0 at both time ends + # 4. rescale SR to ensure integral (SR) = slip + f = interpolate.interp1d(self.myt, aSRa[j, i, :], kind="linear") + pf.aSR[j, i, :] = f(pf.myt) + tapper = cosine_taper(pf.ndt, self.dt / (pf.ndt * pf.dt)) + pf.aSR[j, i, :] = tapper * ndimage.gaussian_filter1d(pf.aSR[j, i, :], time_smoothing_kernel_as_dt_fraction * self.dt / pf.dt, mode="constant") + # With a cubic interpolation, the interpolated slip1 may be negative which does not make sense. + if pf.slip1[j, i] < 0: + pf.aSR[j, i, :] = 0 + continue + # should be the SR + integral_STF = np.trapz(np.abs(pf.aSR[j, i, :]), dx=pf.dt) + if abs(integral_STF) > 0: + pf.aSR[j, i, :] = pf.slip1[j, i] * pf.aSR[j, i, :] / integral_STF + return pf + + def compute_corrected_slip_for_differing_area(self, proj): + """ + self.PSarea_cm2 may slightly differ from the patch area from the fault geometry + (e.g. due to the projection) + Therefore, we need to update slip to keep seismic potency (area*slip) unchanged + """ + cm2m = 0.01 + km2m = 1e3 + PSarea_m2 = self.PSarea_cm2 * cm2m * cm2m + self.compute_xy_from_latlon(proj) + nx, ny = self.nx, self.ny + # Compute actual dx and dy from coordinates + dy = np.zeros((ny, nx)) + dx = np.zeros((ny, nx)) + # central difference for the inside + coords = np.array((self.x, self.y, -km2m * self.depth)) + for i in range(0, nx): + p0 = coords[:, 0 : ny - 2, i] - coords[:, 2:ny, i] + dy[1 : ny - 1, i] = 0.5 * np.linalg.norm(p0, axis=0) + # special case of 0 and ny-1 + p0 = coords[:, 1, :] - coords[:, 0, :] + dy[0, :] = np.linalg.norm(p0, axis=0) + p0 = coords[:, ny - 1, :] - coords[:, ny - 2, :] + dy[ny - 1, :] = np.linalg.norm(p0, axis=0) + # dx for coordinates + for j in range(0, ny): + p0 = coords[:, j, 0 : nx - 2] - coords[:, j, 2:nx] + dx[j, 1 : nx - 1] = 0.5 * np.linalg.norm(p0, axis=0) + p0 = coords[:, :, 1] - coords[:, :, 0] + dx[:, 0] = np.linalg.norm(p0, axis=0) + p0 = coords[:, :, nx - 1] - coords[:, :, nx - 2] + dx[:, nx - 1] = np.linalg.norm(p0, axis=0) + factor_area = dx[:, :] * dy[:, :] / PSarea_m2 + slip1 = self.slip1 * factor_area + print( + f"done correcting slip for area. \ +The correcting factor ranges between {np.amin(factor_area)} and {np.amax(factor_area)}" + ) + return slip1 + + def compute_1d_dimension_arrays(self, spatial_zoom): + self.spatial_zoom = spatial_zoom + # Compute dimension arrays + km2m = 1e3 + coords = np.array([self.x, self.y, -km2m * self.depth]) + ny, nx = coords.shape[1:3] + center_row = coords[:, (ny - 1) // 2, :] - coords[:, (ny - 1) // 2 - 1, :] + dx1 = np.linalg.norm(center_row, axis=0) + # with this convention the first data point is in local coordinate (0,0) + xb = np.cumsum(dx1) - dx1[0] + + center_col = coords[:, :, (nx - 1) // 2] - coords[:, :, (nx - 1) // 2 - 1] + dy1 = np.linalg.norm(center_col, axis=0) + yb = np.cumsum(dy1) - dy1[0] + + self.xb = np.pad(xb, ((1), (1)), "reflect", reflect_type="odd") + self.yb = np.pad(yb, ((1), (1)), "reflect", reflect_type="odd") + + # we want to cover all the fault, that is up to -dx/2. + # With this strategy We will cover a bit more than that, but it is probably not a big deal + + ncrop = spatial_zoom - 1 + self.x_up = scipy.ndimage.zoom(self.xb, spatial_zoom, order=1, mode="grid-constant", grid_mode=True)[ncrop:-ncrop] + self.y_up = scipy.ndimage.zoom(self.yb, spatial_zoom, order=1, mode="grid-constant", grid_mode=True)[ncrop:-ncrop] + + # used for the interpolation + yg, xg = np.meshgrid(self.y_up, self.x_up) + self.yx = np.array([yg.ravel(), xg.ravel()]).T + + def upsample_quantity_RGInterpolator_core(self, arr, method, is_slip=False): + if is_slip: + # tapper to 0 slip except at the top + print("tapper slip to 0, except at the top (hardcoded)") + padded_arr = np.pad(arr, ((1, 0), (1, 1)), "constant") + padded_arr = np.pad(padded_arr, ((0, 1), (0, 0)), "edge") + else: + padded_arr = np.pad(arr, ((1, 1), (1, 1)), "edge") + interp = RegularGridInterpolator([self.yb, self.xb], padded_arr) + return interp(self.yx, method=method).reshape(self.x_up.shape[0], self.y_up.shape[0]).T + + def upsample_quantity_RGInterpolator(self, arr, method, is_slip=False): + my_array = self.upsample_quantity_RGInterpolator_core(arr, method, is_slip) + minimize_block_average_variations = is_slip + if minimize_block_average_variations: + # inspired by Tinti et al. (2005) (Appendix A) + # This is for the specific case of fault slip. + # We want to preserve the seismic moment of each subfault after interpolation + # the rock rigidity is not know by this script (would require some python binding of easi). + # the subfault area is typically constant over the kinematic model + # So we just want to perserve subfault average. + print("trying to perserve subfault average...") + my_array = np.maximum(0, my_array) + best_misfit = float("inf") + # The algorithm does not seem to converge, but produces better model + # (given the misfit) that inital after 2-3 iterations + niter = 3 + for i in range(niter): + block_average = compute_block_mean(my_array[1:-1, 1:-1], self.spatial_zoom) + print(arr.shape, block_average.shape) + correction = arr / block_average + # having a misfit as misfit = np.linalg.norm(correction) does not makes sense as for almost 0 slip, correction can be large + misfit = np.linalg.norm(arr - block_average) / len(arr) + if best_misfit > misfit: + if i == 0: + print(f"misfit at iter {i}: {misfit}") + else: + print(f"misfit improved at iter {i}: {misfit}") + best_misfit = misfit + best = np.copy(my_array) + my_array = self.upsample_quantity_RGInterpolator_core(correction * arr, method, is_slip) + my_array = np.maximum(0, my_array) + my_array = best + return my_array + + def generate_netcdf_fl33(self, prefix, method, spatial_zoom, proj, write_paraview): + "generate netcdf files to be used with SeisSol friction law 33" + + cm2m = 0.01 + km2m = 1e3 + # a kinematic model defines the fault quantities at the subfault center + # a netcdf file defines the quantities at the nodes + # therefore the extra_padding_layer=True, and the added di below + cslip = self.compute_corrected_slip_for_differing_area(proj) + self.compute_1d_dimension_arrays(spatial_zoom) + + upsampled_arrays = [] + + slip = self.upsample_quantity_RGInterpolator(cslip, method, is_slip=True) + for arr in [cslip, self.t0, self.rake, self.rise_time, self.tacc]: + upsampled_arrays.append(self.upsample_quantity_RGInterpolator(arr, method)) + + slip, rupttime, rake, rise_time, tacc = upsampled_arrays + + # upsampled duration, rise_time and acc_time may not be smaller than initial values + # at least rise_time could lead to a non-causal kinematic model + rupttime = np.maximum(rupttime, np.amin(self.t0)) + rise_time = np.maximum(rise_time, np.amin(self.rise_time)) + tacc = np.maximum(tacc, np.amin(self.tacc)) + + rake_rad = np.radians(rake) + strike_slip = slip * np.cos(rake_rad) * cm2m + dip_slip = slip * np.sin(rake_rad) * cm2m + + dx = np.sqrt(self.PSarea_cm2 * cm2m * cm2m) + ldataName = ["strike_slip", "dip_slip", "rupture_onset", "effective_rise_time", "acc_time"] + lgridded_myData = [strike_slip, dip_slip, rupttime, rise_time, tacc] + + prefix2 = f"{prefix}_{spatial_zoom}_{method}" + if write_paraview: + # see comment above + for i, sdata in enumerate(ldataName): + writeNetcdf( + f"{prefix2}_{sdata}", + [self.x_up, self.y_up], + [sdata], + [lgridded_myData[i]], + paraview_readable=True, + ) + writeNetcdf(f"{prefix2}_slip", [self.x_up, self.y_up], ["slip"], [slip], paraview_readable=True) + writeNetcdf(prefix2, [self.x_up, self.y_up], ldataName, lgridded_myData) + + def generate_fault_ts_yaml_fl33(self, prefix, method, spatial_zoom, proj): + """Generate yaml file initializing FL33 arrays and ts file describing the planar fault geometry.""" + # Generate yaml file loading ASAGI file + cm2m = 0.01 + km2m = 1e3 + self.compute_xy_from_latlon(proj) + nx, ny = self.nx, self.ny + p0 = np.array([self.x[0, 0], self.y[0, 0], -km2m * self.depth[0, 0]]) + p1 = np.array([self.x[ny - 1, 0], self.y[ny - 1, 0], -km2m * self.depth[ny - 1, 0]]) + p2 = np.array([self.x[0, nx - 1], self.y[0, nx - 1], -km2m * self.depth[0, nx - 1]]) + p3 = np.array([self.x[ny - 1, nx - 1], self.y[ny - 1, nx - 1], -km2m * self.depth[ny - 1, nx - 1]]) + + hw = p1 - p0 + dx1 = np.linalg.norm(hw) / (ny - 1) + hw = hw / np.linalg.norm(hw) + hh = p2 - p0 + dx2 = np.linalg.norm(hh) / (nx - 1) + hh = hh / np.linalg.norm(hh) + dx = np.sqrt(self.PSarea_cm2 * cm2m * cm2m) + # a kinematic model defines the fault quantities at the subfault center + # a netcdf file defines the quantities at the nodes + # therefore the dx/2 + # the term dxi/np.sqrt(dx1*dx2) allows accounting for non-square patches + non_square_factor = dx / np.sqrt(dx1 * dx2) + t1 = -np.dot(p0, hh) + t2 = -np.dot(p0, hw) + + template_yaml = f"""!Switch +[strike_slip, dip_slip, rupture_onset, tau_S, tau_R, rupture_rise_time]: !EvalModel + parameters: [strike_slip, dip_slip, rupture_onset, effective_rise_time, acc_time] + model: !Switch + [strike_slip, dip_slip, rupture_onset, effective_rise_time, acc_time]: !AffineMap + matrix: + ua: [{hh[0]}, {hh[1]}, {hh[2]}] + ub: [{hw[0]}, {hw[1]}, {hw[2]}] + translation: + ua: {t1} + ub: {t2} + components: !Any + - !ASAGI + file: {prefix}_{spatial_zoom}_{method}.nc + parameters: [strike_slip, dip_slip, rupture_onset, effective_rise_time, acc_time] + var: data + interpolation: linear + - !ConstantMap + map: + strike_slip: 0.0 + dip_slip: 0.0 + rupture_onset: 0.0 + acc_time: 1e100 + effective_rise_time: 2e100 + components: !FunctionMap + map: + #Note the minus on strike_slip to acknowledge the different convention of SeisSol (T_s>0 means right-lateral) + strike_slip: return -strike_slip; + dip_slip: return dip_slip; + rupture_onset: return rupture_onset; + tau_S: return acc_time/1.27; + tau_R: return effective_rise_time - 2.*acc_time/1.27; + rupture_rise_time: return effective_rise_time; + """ + fname = f"{prefix}_fault.yaml" + with open(fname, "w") as fid: + fid.write(template_yaml) + print(f"done writing {fname}") + + # Generate ts file containing mesh geometry + vertex = np.zeros((4, 3)) + vertex[0, :] = p0 + 0.5 * (-hh * dx1 - hw * dx2) * non_square_factor + vertex[1, :] = p2 + 0.5 * (hh * dx1 - hw * dx2) * non_square_factor + vertex[2, :] = p3 + 0.5 * (hh * dx1 + hw * dx2) * non_square_factor + vertex[3, :] = p1 + 0.5 * (-hh * dx1 + hw * dx2) * non_square_factor + + connect = np.zeros((2, 3), dtype=int) + connect[0, :] = [1, 2, 3] + connect[1, :] = [1, 3, 4] + fname = f"{prefix}_fault.ts" + with open(fname, "w") as fout: + fout.write("GOCAD TSURF 1\nHEADER {\nname:%s\nborder: true\nmesh: false\n*border*bstone: true\n}\nTFACE\n" % (fname)) + for ivx in range(1, 5): + fout.write("VRTX %s %s %s %s\n" % (ivx, vertex[ivx - 1, 0], vertex[ivx - 1, 1], vertex[ivx - 1, 2])) + + for i in range(2): + fout.write("TRGL %d %d %d\n" % (connect[i, 0], connect[i, 1], connect[i, 2])) + fout.write("END\n") + print(f"done writing {fname}") diff --git a/science/kinematic_models/GaussianSTF.py b/science/kinematic_models/GaussianSTF.py new file mode 100644 index 0000000..f7e333e --- /dev/null +++ b/science/kinematic_models/GaussianSTF.py @@ -0,0 +1,18 @@ +from math import exp + + +def SmoothStep(time, Tnuc): + if time <= 0: + return 0 + elif time < Tnuc: + return exp((time - Tnuc) ** 2 / (time * (time - 2.0 * Tnuc))) + else: + return 1.0 + + +def GaussianSTF(time, Tnuc, dt): + if time > 0 and time < Tnuc: + Gnuc = SmoothStep(time, Tnuc) - SmoothStep(time - dt, Tnuc) + else: + Gnuc = 0 + return Gnuc diff --git a/science/kinematic_models/Yoffe.py b/science/kinematic_models/Yoffe.py new file mode 100644 index 0000000..e60b017 --- /dev/null +++ b/science/kinematic_models/Yoffe.py @@ -0,0 +1,80 @@ +from math import sqrt, asin, atan, pi + + +def C1(t, ts, tr): + """ C1 to C6 are analytical functions + used for building the regularized Yoffe function + """ + return ( + (0.5 * t + 0.25 * tr) * sqrt(t * (tr - t)) + + (t * tr - tr * tr) * asin(sqrt(t / tr)) + - 0.75 * tr * tr * atan(sqrt((tr - t) / t)) + ) + + +def C2(t, ts, tr): + return 0.375 * pi * tr * tr + + +def C3(t, ts, tr): + return ( + (ts - t - 0.5 * tr) * sqrt((t - ts) * (tr - t + ts)) + + tr * (2 * tr - 2 * t + 2 * ts) * asin(sqrt((t - ts) / tr)) + + 1.5 * tr * tr * atan(sqrt((tr - t + ts) / (t - ts))) + ) + + +def C4(t, ts, tr): + # fixed 2 typos in the second term + return ( + (-ts + 0.5 * t + 0.25 * tr) * sqrt((t - 2.0 * ts) * (tr - t + 2.0 * ts)) + - tr * (tr - t + 2.0 * ts) * asin(sqrt((t - 2.0 * ts) / tr)) + - 0.75 * tr * tr * atan(sqrt((tr - t + 2.0 * ts) / (t - 2.0 * ts))) + ) + + +def C5(t, ts, tr): + return 0.5 * pi * tr * (t - tr) + + +def C6(t, ts, tr): + return 0.5 * pi * tr * (2.0 * ts - t + tr) + + +def regularizedYoffe(t, ts, tr): + """ + Implementation of the regularized Yoffe function + defined in Appendix of Tinti et al. (2005), https://doi.org/10.1785/0120040177 + """ + assert ts <= tr, f"ts:{ts} > tr:{tr}" + K = 2.0 / (pi * tr * ts * ts) + if tr > 2.0 * ts: + if t <= 0: + return 0 + elif t <= ts: + return K * (C1(t, ts, tr) + C2(t, ts, tr)) + elif t <= 2.0 * ts: + return K * (C1(t, ts, tr) - C2(t, ts, tr) + C3(t, ts, tr)) + elif t < tr: + return K * (C1(t, ts, tr) + C3(t, ts, tr) + C4(t, ts, tr)) + elif t < tr + ts: + return K * (C3(t, ts, tr) + C4(t, ts, tr) + C5(t, ts, tr)) + elif t < tr + 2.0 * ts: + return K * (C4(t, ts, tr) + C6(t, ts, tr)) + else: + return 0 + else: + if t <= 0: + return 0 + elif t <= ts: + return K * (C1(t, ts, tr) + C2(t, ts, tr)) + elif t < tr: + return K * (C1(t, ts, tr) - C2(t, ts, tr) + C3(t, ts, tr)) + elif t <= 2.0 * ts: + return K * (C5(t, ts, tr) + C3(t, ts, tr) - C2(t, ts, tr)) + elif t < tr + ts: + return K * (C3(t, ts, tr) + C4(t, ts, tr) + C5(t, ts, tr)) + elif t < tr + 2.0 * ts: + return K * (C4(t, ts, tr) + C6(t, ts, tr)) + else: + return 0 diff --git a/science/kinematic_models/generate_FL33_input_files.py b/science/kinematic_models/generate_FL33_input_files.py new file mode 100644 index 0000000..75b4cc6 --- /dev/null +++ b/science/kinematic_models/generate_FL33_input_files.py @@ -0,0 +1,72 @@ +import os +import argparse +from FaultPlane import FaultPlane +import os.path + +parser = argparse.ArgumentParser( + description="generate yaml and netcdf input to be used with friction law 33/34 based on a (here" + + "upsampled) kinematic model in the standard rupture format srf file." +) +parser.add_argument("filename", help="filename of the srf file") +parser.add_argument( + "--interpolation_method", + nargs=1, + metavar=("interpolation_method"), + default=["linear"], + help="interpolation method", + choices=["linear", "nearest", "slinear", "cubic", "quintic"], +) +parser.add_argument( + "--spatial_zoom", + nargs=1, + metavar=("spatial_zoom"), + required=True, + help="level of spatial upsampling", + type=int, +) +parser.add_argument( + "--write_paraview", + dest="write_paraview", + action="store_true", + help="write also netcdf readable by paraview", + default=False, +) +parser.add_argument( + "--generate_ts_yaml", + metavar=("proj"), + nargs=1, + help="generate fault yaml file and write fault geometry (ts file). proj: proj4 string describing the projection.", +) + +parser.add_argument( + "--PSRthreshold", + help="peak slip rate threshold (0-1) to determine onset time and duration of STF", + nargs=1, + metavar=("PSRthreshold"), + type=float, + default=[0.0], +) + +args = parser.parse_args() + +p1 = FaultPlane() +p1.init_from_srf(args.filename) +p1.compute_time_array() +p1.assess_STF_parameters(args.PSRthreshold[0]) +prefix, ext = os.path.splitext(args.filename) +prefix = os.path.basename(prefix) + +p1.generate_netcdf_fl33( + prefix, + method=args.interpolation_method[0], + spatial_zoom=args.spatial_zoom[0], + proj=args.generate_ts_yaml, + write_paraview=args.write_paraview, +) +if args.generate_ts_yaml: + p1.generate_fault_ts_yaml_fl33( + prefix, + method=args.interpolation_method[0], + spatial_zoom=args.spatial_zoom[0], + proj=args.generate_ts_yaml, + ) diff --git a/science/kinematic_models/refine_srf.py b/science/kinematic_models/refine_srf.py new file mode 100644 index 0000000..228d07e --- /dev/null +++ b/science/kinematic_models/refine_srf.py @@ -0,0 +1,78 @@ +import os +import argparse +from FaultPlane import FaultPlane + +parser = argparse.ArgumentParser( + description="upsample temporally and spatially a kinematic model (should consist of only one segment) in the standard rupture format" +) +parser.add_argument("filename", help="filename of the srf file") +parser.add_argument( + "--proj", + help="transform geometry given proj4 string (as it might be better to upsample the geometry in the local coordinate system)", +) +parser.add_argument( + "--spatial_order", + nargs=1, + metavar=("spatial_order"), + default=([3]), + help="spatial order of the interpolation", + type=int, +) +parser.add_argument( + "--spatial_zoom", + nargs=1, + metavar=("spatial_zoom"), + required=True, + help="level of spatial upsampling", + type=int, +) +parser.add_argument( + "--temporal_zoom", + nargs=1, + metavar=("temporal_zoom"), + required=True, + help="level of temporal upsampling", + type=int, +) + +parser.add_argument( + "--time_smoothing_kernel_as_dt_fraction", + nargs=1, + metavar=("alpha_dt"), + default=([0.5]), + help="sigma, expressed as a portion of dt, of the gaussian kernel used to smooth SR", + type=float, +) + +parser.add_argument( + "--use_Yoffe", + help="replace the discretized STF with a Yoffe function (e.g. for comparison with FL33).\ + Requires peak slip rate threshold (0-1) to determine onset time and duration of STF", + dest="use_Yoffe", + nargs=1, + metavar=("PSRthreshold"), + type=float, +) + +args = parser.parse_args() + +p1 = FaultPlane() +p1.init_from_srf(args.filename) +p1.compute_xy_from_latlon(args.proj) +p1.compute_time_array() + +use_Yoffe = True if args.use_Yoffe else False +if use_Yoffe: + p1.assess_STF_parameters(args.use_Yoffe[0]) + +p2 = p1.upsample_fault( + spatial_order=args.spatial_order[0], + spatial_zoom=args.spatial_zoom[0], + temporal_zoom=args.temporal_zoom[0], + proj=args.proj, + use_Yoffe=use_Yoffe, + time_smoothing_kernel_as_dt_fraction=args.time_smoothing_kernel_as_dt_fraction[0], +) +prefix, ext = os.path.splitext(args.filename) +fnout = prefix + "_resampled" + ".srf" +p2.write_srf(fnout) diff --git a/science/place_faultreceivers.m b/science/place_faultreceivers.m new file mode 100644 index 0000000..ced28cd --- /dev/null +++ b/science/place_faultreceivers.m @@ -0,0 +1,295 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% @author Christian Pelties (pelties AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/pelties) +% +% @section LICENSE +% Copyright (c) 2005-2012, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + +home; +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% PLACE_FAULTRECEIVERS %%') +disp(' %% TO COMPUTE FAULTRECEIVER POSITIONS %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Give Gambit mesh-file and station coordinates in order to compute') +disp(' the exact positions of the stations on the particular Gambit mesh,') +disp(' which approximates the fault with piecewise linear polynomials') +disp(' in the fault-surface triangulation!') +disp(' '),disp(' ') +clear, close all; + +format long + +% get input +filename = input(' Filename of mesh(suffix ".neu" is appended) : ','s'); +normal = input(' Normal axis to fault (x,y,z) : ','s'); +rec_filename = input(' Filename of 2D receiver locations(suffix ".dat" is appended): ','s'); +plotmesh = input(' Do you wish to plot the mesh? (y,n) : ','s'); +if plotmesh == 'y' + plotmarker = input(' Do you wish to plot the marker into the mesh? (y,n) : ','s'); +else + plotmarker = 'n'; +end + +% input check +if normal == 'x' || normal == 'y' || normal == 'z' +else + disp('Wrong input for normal axis!') + return +end + +% load receiver stations +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); + +% read neu file +fid = fopen([filename ,'.neu']); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +param = fscanf(fid,'%i',[6,1]); NX = param(1); NT = param(2); NG = param(3); NB = param(4); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); + +% read nodes +X = fscanf(fid,'%g',[4,NX]);X = X'; +X(:,1) = []; % delete indices +X(:,3)=X(:,3)+rand(size(X(:,3)))*0.0000001; % random field needed to avoid NaNs. it supports matlab by finding the closest neighbor. +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +% read connectivity information +tetra = fscanf(fid,'%g',[7,NT]); tetra = tetra'; tetra(:,1:3) = []; +junk = fgetl(fid); + +% read groups +for i = 1:NG + junk = fgetl(fid); + junk = fgetl(fid); + junk = fgetl(fid); + n = str2num(junk(30:38)); + junk = fgetl(fid); + junk = fgetl(fid); + ju = fscanf(fid,'%g',[10,ceil(n/10)]); +end +junk = fgetl(fid); +if(length(junk)==0) + junk = fgetl(fid); +end + +% read NBSETS +for i = 1:NB + junk = fgetl(fid); + param = fscanf(fid,'%i',[5,1]); NS = param(3); + % search for fault elements + if (param(1)~=103) + junk = fgetl(fid); + TS = fscanf(fid,'%g',[3,NS]); LocalFace = TS(3,:)'; TS = TS(1,:)'; + junk = fgetl(fid); junk = fgetl(fid); + else + junk = fgetl(fid); + TS = fscanf(fid,'%g',[3,NS]); LocalFace = TS(3,:)'; TS = TS(1,:)'; + junk = fgetl(fid); break + end +end +fclose(fid); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PLOT SURFACE TRIANGULATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +s_vert(1,:) = [1,3,2]; s_vert(2,:) = [1,2,4]; s_vert(3,:) = [2,3,4]; s_vert(4,:) = [1,4,3]; + +Y = []; tri = []; +j = 0; + +Y = X(tetra(TS(1),s_vert(LocalFace(1),:))',:); +tri = [1,2,3]; +for i = 2:NS + tmp = X(tetra(TS(i),s_vert(LocalFace(i),:))',:); + mem = ismember(Y,tmp); + mloc = ismember(tmp,Y); + a = find(sum(mem,2)==3); + b = find(sum(mloc,2)==3); + if length(b)>0 + tmp(b,:) = []; + end + Y = [Y;tmp]; + + trinew = [length(Y):-1:length(Y)-2]; + trinew = [a',trinew]; + tri = [tri;trinew(1:3)]; +% fill3(tmp(:,1),tmp(:,2),tmp(:,3),'r'); + if(mod(i,round(NS/10))==0) + j = j+1; + disp(sprintf(' %g percent done!',j*10)) + end +end + +%Print mesh information on screen +disp(sprintf('\n\tFound %g fault triangles',NS)); +disp(sprintf('\tFound %g faultreceiver with xyz-coordinates:',size(st,1))); + +if plotmesh == 'y' + figure; hold on + trimesh(tri,Y(:,1),Y(:,2),Y(:,3),Y(:,3)); axis equal,xlabel('x'),ylabel('y'),zlabel('z') +end + +% saving of data not necessary +% %save surface triangulation for use by gambit_receivers_fast +% X = Y; +% disp(' Fault-surface triangulation with vertices saved!'); disp(' ') +% eval(['save ',filename,'_tri.mat tri']) +% eval(['save ',filename,'_vert.mat X']) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% COMPUTE STATION ELEVATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Note, fault sides appear twice and therefore two faces will be found that +% will be cleaned out later. This way, a fault station will be projected +% also to branches lying behind the main fault. + +k=0; +for i = 1:size(st,1) + for j = 1:size(tri) + % get correct orientation + if normal == 'x' + x(1) = Y(tri(j,1),2); + x(2) = Y(tri(j,2),2); + x(3) = Y(tri(j,3),2); + y(1) = Y(tri(j,1),3); + y(2) = Y(tri(j,2),3); + y(3) = Y(tri(j,3),3); + elseif normal == 'y' + x(1) = Y(tri(j,1),1); + x(2) = Y(tri(j,2),1); + x(3) = Y(tri(j,3),1); + y(1) = Y(tri(j,1),3); + y(2) = Y(tri(j,2),3); + y(3) = Y(tri(j,3),3); + elseif normal == 'z' + x(1) = Y(tri(j,1),1); + x(2) = Y(tri(j,2),1); + x(3) = Y(tri(j,3),1); + y(1) = Y(tri(j,1),2); + y(2) = Y(tri(j,2),2); + y(3) = Y(tri(j,3),2); + end + + inside = XYinElement(x,y,st(i,1),st(i,2)); + if inside == 1 + k=k+1; + t(k) = j; + newst(k,1)=st(i,1); + newst(k,2)=st(i,2); + end + end +end + +est(1:k) = 0.0; + +% linear interpolation +for i=1:k % add new stations generated by branch e.g. + + % load the three vertices for the receiver position + v0 = Y(tri(t(i),1),:); + v1 = Y(tri(t(i),2),:); + v2 = Y(tri(t(i),3),:); + + % generate interpolation matrix + if normal == 'x' + A = [1, v0(2), v0(3);1, v1(2), v1(3);1, v2(2), v2(3)]; + f = [v0(1);v1(1);v2(1)]; + elseif normal == 'y' + A = [1, v0(1), v0(3);1, v1(1), v1(3);1, v2(1), v2(3)]; + f = [v0(2);v1(2);v2(2)]; + elseif normal == 'z' + A = [1, v0(1), v0(2);1, v1(1), v1(2);1, v2(1), v2(2)]; + f = [v0(3);v1(3);v2(3)]; + end + + % solve matrix and get desired coordinate: + c = A\f; + est(i) = c(1)+c(2)*newst(i,1)+c(3)*newst(i,2); +end + +% plot markers into mesh: +if normal == 'x' + xplot = est'; + yplot = newst(:,1); + zplot = newst(:,2); +elseif normal == 'y' + xplot = newst(:,1); + yplot = est'; + zplot = newst(:,2); +elseif normal == 'z' + xplot = newst(:,1); + yplot = newst(:,2); + zplot = est'; +end + +% clean double receiver positions (due to double counted fault sides) +receivers = [xplot,yplot,zplot]; +receivers = unique(receivers,'rows'); + +if plotmarker == 'y' + plot3(receivers(:,1),receivers(:,2),receivers(:,3),'r*','MarkerSize',8) + axis tight +end + +%disp(' Receiver coordinates at fault:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +choice = input([' Save receiver coordinates as ',filename,'_faultreceivers.dat ? (y/n)'], 's'); +if choice=='y' + fid_out = fopen([filename ,'_faultreceivers.dat'],'w'); + fprintf(fid_out,'%20.12f%20.12f%20.12f\n',receivers'); + fclose(fid_out); + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + +disp(' FINISHED'); diff --git a/science/place_quickly_faultreceivers.m b/science/place_quickly_faultreceivers.m new file mode 100644 index 0000000..aaaa7bc --- /dev/null +++ b/science/place_quickly_faultreceivers.m @@ -0,0 +1,317 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Martin Kaeser (martin.kaeser AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/kaeser) +% @author Christian Pelties (pelties AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/pelties) +% +% @section LICENSE +% Copyright (c) 2005-2012, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + + +% Thomas Ulrich 03.2015 +% The original routine place_faultreceivers.m takes a lonnnng time +% when the mesh is very large (+5e6 elements) +% This amended version should do the job quicker +home; +if verLessThan('matlab', '8.5') + disp('YOUR MATLAB VERSION IS TOO OLD FOR THAT SCRIPT') + return +end + +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% PLACE_QUICKLY_FAULTRECEIVERS %%') +disp(' %% TO COMPUTE FAULTRECEIVER POSITIONS %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Give Gambit mesh-file and station coordinates in order to compute') +disp(' the exact positions of the stations on the particular Gambit mesh,') +disp(' which approximates the fault with piecewise linear polynomials') +disp(' in the fault-surface triangulation!') +disp(' '),disp(' ') +clear, close all; + +format long + +% get input +filename = input(' Filename of mesh(suffix ".neu" is appended) : ','s'); +normal = input(' Normal axis to fault (x,y,z) : ','s'); +rec_filename = input(' Filename of 2D receiver locations(suffix ".dat" is appended): ','s'); +plotmesh = input(' Do you wish to plot the mesh? (y,n) : ','s'); +if plotmesh == 'y' + plotmarker = input(' Do you wish to plot the marker into the mesh? (y,n) : ','s'); +else + plotmarker = 'n'; +end + +% input check +if normal == 'x' || normal == 'y' || normal == 'z' +else + disp('Wrong input for normal axis!') + return +end + +% load receiver stations +eval(['load ',rec_filename,'.dat']); +eval(['st = ',rec_filename,';']); + +% read neu file +fid = fopen([filename ,'.neu']); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +param = fscanf(fid,'%i',[6,1]); NX = param(1); NT = param(2); NG = param(3); NB = param(4); +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); + +% read nodes +X = fscanf(fid,'%g',[4,NX]);X = X'; +X(:,1) = []; % delete indices +X(:,3)=X(:,3)+rand(size(X(:,3)))*0.0000001; % random field needed to avoid NaNs. it supports matlab by finding the closest neighbor. +junk = fgetl(fid); +junk = fgetl(fid); +junk = fgetl(fid); +% read connectivity information +tetra = fscanf(fid,'%g',[7,NT]); tetra = tetra'; tetra(:,1:3) = []; +junk = fgetl(fid); + +% read groups +for i = 1:NG + junk = fgetl(fid); + junk = fgetl(fid); + junk = fgetl(fid); + %TU 07.2015 before 30:39 but clearly it was a mistake (particularly visible with meshes generated by SimModeler) + n = str2num(junk(30:38)); + junk = fgetl(fid); + junk = fgetl(fid); + ju = fscanf(fid,'%g',[10,ceil(n/10)]); +end +junk = fgetl(fid); +if(length(junk)==0) + junk = fgetl(fid); +end + +% read NBSETS +for i = 1:NB + junk = fgetl(fid); + param = fscanf(fid,'%i',[5,1]); NS = param(3); + % search for fault elements + if (param(1)~=103) + junk = fgetl(fid); + TS = fscanf(fid,'%g',[3,NS]); LocalFace = TS(3,:)'; TS = TS(1,:)'; + junk = fgetl(fid); junk = fgetl(fid); + else + junk = fgetl(fid); + TS = fscanf(fid,'%g',[3,NS]); LocalFace = TS(3,:)'; TS = TS(1,:)'; + junk = fgetl(fid); break + end +end +fclose(fid); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PLOT SURFACE TRIANGULATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +s_vert(1,:) = [1,3,2]; s_vert(2,:) = [1,2,4]; s_vert(3,:) = [2,3,4]; s_vert(4,:) = [1,4,3]; + +Y = []; tri = []; +j = 0; + + +tri=zeros(NS,3); +for i = 1:NS + tri(i,:)=tetra(TS(i),s_vert(LocalFace(i),:))'; +end + +%Print mesh information on screen +disp(sprintf('\n\tFound %g fault triangles',NS)); +disp(sprintf('\tFound %g faultreceiver with xyz-coordinates:',size(st,1))); + + +if plotmesh == 'y' + figure; hold on + trimesh(tri,X(:,1),X(:,2),X(:,3),X(:,3)); + axis equal,xlabel('x'),ylabel('y'),zlabel('z') +end + +% saving of data not necessary +% %save surface triangulation for use by gambit_receivers_fast +% X = Y; +% disp(' Fault-surface triangulation with vertices saved!'); disp(' ') +% eval(['save ',filename,'_tri.mat tri']) +% eval(['save ',filename,'_vert.mat X']) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% COMPUTE STATION ELEVATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Note, fault sides appear twice and therefore two faces will be found that +% will be cleaned out later. This way, a fault station will be projected +% also to branches lying behind the main fault. + +if normal == 'x' + indexes= 2:3; +elseif normal == 'y' + indexes= 1:2:3; +elseif normal == 'z' + indexes= 1:2; +end +TR = triangulation(tri,X(:,indexes)); +t = pointLocation(TR,st(:,1:2)); + +indicesInTriangulation = find(~isnan(t)); +disp(sprintf('%d points outside the triangulation', size(t)-size(indicesInTriangulation))); +t=t(indicesInTriangulation); +newst=st(indicesInTriangulation,1:2); +k=size(t); + +% k=0; +% for i = 1:size(st,1) +% disp(sprintf('done %d/%d ',i,size(st,1))) +% +% for j = 1:size(tri) +% % get correct orientation +% if normal == 'x' +% x(1) = X(tri(j,1),2); +% x(2) = X(tri(j,2),2); +% x(3) = X(tri(j,3),2); +% y(1) = X(tri(j,1),3); +% y(2) = X(tri(j,2),3); +% y(3) = X(tri(j,3),3); +% elseif normal == 'y' +% x(1) = X(tri(j,1),1); +% x(2) = X(tri(j,2),1); +% x(3) = X(tri(j,3),1); +% y(1) = X(tri(j,1),3); +% y(2) = X(tri(j,2),3); +% y(3) = X(tri(j,3),3); +% elseif normal == 'z' +% x(1) = X(tri(j,1),1); +% x(2) = X(tri(j,2),1); +% x(3) = X(tri(j,3),1); +% y(1) = X(tri(j,1),2); +% y(2) = X(tri(j,2),2); +% y(3) = X(tri(j,3),2); +% end +% % if abs(st(i,1)-mean(x(:)))>100e3 | abs(st(i,2)-mean(y(:)))>100e3 +% % inside=0; +% % else +% inside = XYinElement(x,y,st(i,1),st(i,2)); +% % end +% if inside == 1 +% k=k+1; +% t(k) = j +% newst(k,1)=st(i,1); +% newst(k,2)=st(i,2); +% end +% end +% end + +est(1:k) = 0.0; + +% linear interpolation +for i=1:k % add new stations generated by branch e.g. + + % load the three vertices for the receiver position + v0 = X(tri(t(i),1),:); + v1 = X(tri(t(i),2),:); + v2 = X(tri(t(i),3),:); + + % generate interpolation matrix + if normal == 'x' + A = [1, v0(2), v0(3);1, v1(2), v1(3);1, v2(2), v2(3)]; + f = [v0(1);v1(1);v2(1)]; + elseif normal == 'y' + A = [1, v0(1), v0(3);1, v1(1), v1(3);1, v2(1), v2(3)]; + f = [v0(2);v1(2);v2(2)]; + elseif normal == 'z' + A = [1, v0(1), v0(2);1, v1(1), v1(2);1, v2(1), v2(2)]; + f = [v0(3);v1(3);v2(3)]; + end + + % solve matrix and get desired coordinate: + c = A\f; + est(i) = c(1)+c(2)*newst(i,1)+c(3)*newst(i,2); +end + +% plot markers into mesh: +if normal == 'x' + xplot = est'; + yplot = newst(:,1); + zplot = newst(:,2); +elseif normal == 'y' + xplot = newst(:,1); + yplot = est'; + zplot = newst(:,2); +elseif normal == 'z' + xplot = newst(:,1); + yplot = newst(:,2); + zplot = est'; +end + +% clean double receiver positions (due to double counted fault sides) +receivers = [xplot,yplot,zplot]; +[tmp,uniquecol]=unique(receivers(:,1:2:end),'rows'); +receivers=receivers(uniquecol,:); + + +if plotmarker == 'y' + plot3(receivers(:,1),receivers(:,2),receivers(:,3),'r*','MarkerSize',8) + axis tight +end + +%disp(' Receiver coordinates at fault:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +choice = input([' Save receiver coordinates as ',filename,'_faultreceivers.dat ? (y/n)'], 's'); +if choice=='y' + fid_out = fopen([filename ,'_faultreceivers.dat'],'w'); + fprintf(fid_out,'%20.12f%20.12f%20.12f\n',receivers'); + %fprintf(fid_out,'%.20e %.20e %.20e\n',receivers'); + fclose(fid_out); + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + + + +disp(' FINISHED'); diff --git a/science/place_quickly_faultreceivers_netcdf_any_normal.m b/science/place_quickly_faultreceivers_netcdf_any_normal.m new file mode 100644 index 0000000..fe3031a --- /dev/null +++ b/science/place_quickly_faultreceivers_netcdf_any_normal.m @@ -0,0 +1,245 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Thomas Ulrich (ulrich AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/ulrich) +% +% @section LICENSE +% Copyright (c) 2005-2012, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. + + +% Thomas Ulrich 01.2016 +% The original routine reads a gambit neu mesh +% This amended version reads a netcdf file +% the normal vector to the surface can be any vector +home; +if verLessThan('matlab', '8.5') + disp('YOUR MATLAB VERSION IS TOO OLD FOR THAT SCRIPT') + return +end + +disp(' ') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' %% %%') +disp(' %% PLACE_QUICKLY_FAULTRECEIVERS_NETCDF_ANY_NORMAL %%') +disp(' %% TO COMPUTE FAULTRECEIVER POSITIONS %%') +disp(' %% %%') +disp(' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%') +disp(' ') +disp(' Give netcdf mesh-file and station coordinates in order to compute') +disp(' the exact positions of the stations on the particular mesh,') +disp(' which approximates the fault with piecewise linear polynomials') +disp(' in the fault-surface triangulation!') +disp(' '),disp(' ') +clear, close all; +warning('off','MATLAB:triangulation:PtsNotInTriWarnId') +format long + +% get input +filename0 = input(' Filename of mesh(suffix ".nc" is appended) : ','s'); +snormal = input(' Normal coordinates \"nx,ny,nz\" : ','s'); +rec_filename = input(' Filename of 3D receiver locations(suffix ".dat" is appended): ','s'); +SufaceId = input(' surface to be considered (1: Free Surface, 3: Fault) : ','s'); +plotmesh = input(' Do you wish to plot the mesh? (y,n) : ','s'); +if plotmesh == 'y' + plotmarker = input(' Do you wish to plot the marker into the mesh? (y,n) : ','s'); +else + plotmarker = 'n'; +end +SufaceId = str2num(SufaceId); +if SufaceId==1 + depthdecrement = input(' depth (in m) to decrement for more accurate outputs (ex 0 or 50) : ','s'); + depthdecrement = str2double(depthdecrement); +end + +coords = strsplit(snormal,','); +normal(1) = str2double(coords(1)); +normal(2) = str2double(coords(2)); +normal(3) = str2double(coords(3)); +normal = normal/norm(normal); +%now determine 2 perpendicular vectors: +randomV = rand(3,1); +ux = cross(randomV,normal); +ux = ux/norm(ux); +uy = cross(ux, normal); + +% load receiver stations +%eval(['load ',rec_filename,'.dat']); +%eval(['st = ',rec_filename,';']); +st = load([rec_filename,'.dat']); +if size(st,2)~=3 + disp(sprintf('Error in %s: number of columns not equal 3',rec_filename)) + return +end + +filename = sprintf('%s.nc',filename0); + + +element_size = ncread(filename,'element_size'); +[nPartition, ntrash] = (size(element_size)); +element_vertices = ncread(filename,'element_vertices'); +element_boundaries = ncread(filename,'element_boundaries'); +vertex_coordinates = ncread(filename,'vertex_coordinates'); +vertex_size = ncread(filename,'vertex_size'); + +receivers=[]; +if plotmesh == 'y' + figure; hold on +end +disp(sprintf('\tFound %g faultreceiver with xyz-coordinates:',size(st,1))); + +for iPartition=1:nPartition + %read vertices + X = vertex_coordinates(:,1:vertex_size(iPartition),iPartition); + X=X'; + %read elements (+1 because numeration starts at 0 in netcdf) + tetra = element_vertices(:,1:element_size(iPartition),iPartition)+1; + tetra = tetra'; + %read elements boudary + elemBound = element_boundaries(:,1:element_size(iPartition),iPartition); + elemBound = elemBound'; + %find Boundary elements + [tetraId, faceId] = find(elemBound==SufaceId); + [NS, ntrash] = size(tetraId); + if NS==0 + continue + end + + tri = []; + tri=zeros(NS,3); + %GAMBIT convention + %s_vert(1,:) = [1,3,2]; s_vert(2,:) = [1,2,4]; s_vert(3,:) = [2,3,4]; s_vert(4,:) = [1,4,3]; + %ICEM convention + s_vert(1,:) = [1,3,2]; s_vert(2,:) = [1,2,4]; s_vert(4,:) = [2,3,4]; s_vert(3,:) = [1,4,3]; + + for idBound = 1:NS + tri(idBound,:) = tetra(tetraId(idBound), s_vert(faceId(idBound),:))'; + end + + + + if plotmesh == 'y' + %figure; hold on + trimesh(tri,X(:,1),X(:,2),X(:,3),X(:,3)); + axis equal,xlabel('x'),ylabel('y'),zlabel('z') + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % COMPUTE STATION ELEVATION + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % Note, fault sides appear twice and therefore two faces will be found that + % will be cleaned out later. This way, a fault station will be projected + % also to branches lying behind the main fault. + x1 = zeros(size(X,1),2); + for kkk=1:size(X,1) + x1(kkk,1) = dot(X(kkk,:),ux); + x1(kkk,2) = dot(X(kkk,:),uy); + end + TR = triangulation(tri,x1); + x2 = zeros(size(st,1),2); + for kkk=1:size(st,1) + x2(kkk,1) = dot(st(kkk,:),ux); + x2(kkk,2) = dot(st(kkk,:),uy); + end + [t,barcoords] = pointLocation(TR,x2); + indicesInTriangulation = find(~isnan(t)); + ninside = size(indicesInTriangulation,1); + + %Print mesh information on screen + disp(sprintf('Partition %d:\tFound %g fault triangles,\t%d points inside the triangulation',iPartition, NS, ninside)); + + t=t(indicesInTriangulation); + barcoords = barcoords(indicesInTriangulation,:); + + + newst=st(indicesInTriangulation,1:2); + k=size(t); + + for i=1:k + % load the three vertices for the receiver position + v0 = X(tri(t(i),1),:); + v1 = X(tri(t(i),2),:); + v2 = X(tri(t(i),3),:); + receivers_part = barcoords(i,1)*v0 + barcoords(i,2)*v1+barcoords(i,3)*v2; + receivers = vertcat(receivers,receivers_part); + end +end +if SufaceId==1 + disp(sprintf('!!!removing %f in normal direction!!!!!!', depthdecrement)); + for i =1:size(receivers,1) + receivers(i,:) = receivers(i,:)-depthdecrement*normal; + end +end +disp(sprintf(' %d/%d receiver(s) could be located on the fault', size(receivers,1), size(st,1))); + + +if plotmarker == 'y' + plot3(receivers(:,1),receivers(:,2),receivers(:,3),'r*','MarkerSize',8) + axis tight + view([150 30]) +end + +%disp(' Receiver coordinates at fault:'); disp(' ') +%disp(receivers); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SAVE RECEIVER LOCATIONS TO FILE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%choice = input([' Save receiver coordinates as ',filename,'_faultreceivers.dat ? (y/n)'], 's'); +disp([' receiver coordinates saved as ',filename0,'_faultreceivers.dat']); +choice='y'; + +if choice=='y' + fid_out = fopen([filename0 ,'_faultreceivers.dat'],'w'); + fprintf(fid_out,'%20.12f %20.12f %20.12f\n',receivers'); + %fprintf(fid_out,'%.20e %.20e %.20e\n',receivers'); + fclose(fid_out); + disp(' Receiver coordinates saved!'); +else + disp(' Receiver coordinates NOT saved!'); +end + + + +disp(' FINISHED'); + +%Now writing _sameorder file, in which the initial order of the receiver +%(input file) is kept +disp([' receiver coordinates saved as ',filename0,'_sameorder.dat']); +%for i=1:2 +fid_out = fopen([filename0 ,'_sameorder.dat'],'w'); +for i=1:size(st,1) + indexes2 = find((abs(receivers(:,1)-st(i,1))<1e-3) & (abs(receivers(:,2)-st(i,2))<1e-3)); + fprintf(fid_out,'%20.12f %20.12f %20.12f\n',st(i,1:2), receivers(indexes2,3)); +end +disp(' Receiver coordinates saved!'); +fclose(fid_out); diff --git a/science/rconv/CMakeLists.txt b/science/rconv/CMakeLists.txt new file mode 100644 index 0000000..914ab21 --- /dev/null +++ b/science/rconv/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.7) + +project(SeisSol-RConv LANGUAGES C CXX) + +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../cmake" ${CMAKE_MODULE_PATH}) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "RelWithDebInfo") # MinSizeRel is useless for us +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) + message(STATUS "Set build type to Release as none was supplied.") +endif() + +find_package(Eigen3 3.4 REQUIRED) +find_package(NetCDF REQUIRED) +set(CMAKE_INSTALL_RPATH ${NetCDF_LIBRARY_DIR}) +find_package(PROJ4 QUIET) +if (NOT PROJ4_FOUND) + find_package(PkgConfig QUIET) + if (PkgConfig_FOUND) + pkg_check_modules(PROJ4 QUIET proj>=4.9) + if (PROJ4_FOUND) + set(CMAKE_INSTALL_RPATH "${PROJ4_LIBRARY_DIRS};${CMAKE_INSTALL_RPATH}") + set(PROJ4_LIBRARIES "${PROJ4_LINK_LIBRARIES}") + endif() + endif() +endif() + +# rpath has to be defined before add_executable +# https://stackoverflow.com/questions/30398238/cmake-rpath-not-working-could-not-find-shared-object-file +add_executable(SeisSol-rconv + src/main.cpp + src/XMFWriter.cpp + src/Map.cpp + src/NRFWriter.cpp + src/SRF.cpp) + +target_include_directories(SeisSol-rconv PUBLIC src + "${CMAKE_CURRENT_SOURCE_DIR}/../../submodules/" +) + +target_link_libraries(SeisSol-rconv PUBLIC Eigen3::Eigen) + +target_include_directories(SeisSol-rconv PUBLIC ${NetCDF_INCLUDE_DIRS}) +target_link_libraries(SeisSol-rconv PUBLIC ${NetCDF_LIBRARY}) + +if (PROJ4_FOUND) + message(STATUS "Compiling with proj.4 support.") + target_include_directories(SeisSol-rconv PUBLIC ${PROJ4_INCLUDE_DIRS}) + target_link_libraries(SeisSol-rconv PUBLIC ${PROJ4_LIBRARIES}) +else () + target_compile_definitions(SeisSol-rconv PRIVATE -Dnoproj) + message(WARNING "Compiling WITHOUT proj.4 support.") +endif() + +find_package(HDF5 REQUIRED COMPONENTS C HL) +target_link_libraries(SeisSol-rconv PUBLIC ${HDF5_C_HL_LIBRARIES} ${HDF5_C_LIBRARIES}) + +set_target_properties(SeisSol-rconv PROPERTIES OUTPUT_NAME "rconv") + +install(TARGETS SeisSol-rconv RUNTIME DESTINATION bin) diff --git a/science/rconv/README.md b/science/rconv/README.md new file mode 100644 index 0000000..910329e --- /dev/null +++ b/science/rconv/README.md @@ -0,0 +1,61 @@ +# rconv + +rconv is a tool which allows converting files describing kinematic rupture models +from the Standard Rupture Format (\*.srf) to the intermediate +NetCDF Rupture Format (\*.nrf). + +## Installing rconv + +rconv depends on the PROJ.4 and NetCDF libraries. + +### Installing PROJ.4 + +rconv relies on a deprecated version of the PROJ library (as it includes the file +`projects.h` which is not anymore built in recent releases of PROJ, see +). Also, the most recent version of +PROJ needs access to the internet when running cmake +(because of the googletest 1.8.0 framework). +To install PROJ on supermuc (behind a firewall), we therefore +checkout a deprecated version of the PROJ library: + +```bash +module load gcc +git clone git@github.com:OSGeo/PROJ +cd PROJ +git checkout 4.9.3 +mkdir build +cd build +cmake .. -DCMAKE_INSTALL_PREFIX=$my_proj4_install_prefix +make +make install +``` + +Note that `$my_proj4_install_prefix` should be different than the build directory +(else `make install` will raise the error `cannot find libproj.so.12.0.0`). + +### Installing netcdf + +see the [link in our documentation](https://seissol.readthedocs.io/en/latest/compilation.html#installing-netcdf) + +### Building rconv + +To install rconv, execute the following in the main folder: + +```bash +mkdir build +cd build +cmake .. -DCMAKE_PREFIX_PATH=$my_proj4_install_prefix +make +make install +``` + +## Using rconv + +Starting rconv without arguments gives you a short introduction for using the tool. +You may furthermore consult the [Documentation](https://seissol.readthedocs.io/en/latest/standard-rupture-format.html) +about the Standard Rupture Format. + +## Compilation without PROJ.4 + +rconv can be compiled without proj (e.g. by dropping the argument `-DCMAKE_PREFIX_PATH=$my_proj4_install_prefix`) +In that case, the input file won't be projected anymore. diff --git a/science/rconv/spec/gen.sh b/science/rconv/spec/gen.sh new file mode 100644 index 0000000..d7f8815 --- /dev/null +++ b/science/rconv/spec/gen.sh @@ -0,0 +1,5 @@ +#!/bin/bash +ncgen -l c nrf.cdl > nrf.c +sed -i 's/Vector3_PERIOD_//g' nrf.c +sed -i 's/Subfault_units_PERIOD_//g' nrf.c +sed -i 's/Subfault_PERIOD_//g' nrf.c diff --git a/science/rconv/spec/nrf.cdl b/science/rconv/spec/nrf.cdl new file mode 100644 index 0000000..7da9dfd --- /dev/null +++ b/science/rconv/spec/nrf.cdl @@ -0,0 +1,54 @@ +netcdf nrf { +types: + compound Vector3 { + double x; + double y; + double z; + } ; + + compound Subfault { + double tinit ; + double timestep ; + double mu ; + double area ; + Vector3 tan1 ; + Vector3 tan2 ; + Vector3 normal ; + } ; + + compound Subfault_units { + string tinit ; + string timestep ; + string mu ; + string area ; + string tan1 ; + string tan2 ; + string normal ; + } ; + +dimensions: + source = UNLIMITED ; + sroffset = UNLIMITED ; + direction = 3 ; + sample1 = UNLIMITED ; + sample2 = UNLIMITED ; + sample3 = UNLIMITED ; + +variables: + Vector3 centres(source) ; + centres:units = "m" ; + Subfault subfaults(source) ; + Subfault_units subfaults:units = {"s", "s", "pascal", "m^2", "m", "m", "m"} ; + subfaults:_DeflateLevel = 1 ; + uint sroffsets(sroffset, direction) ; + sroffsets:_DeflateLevel = 1 ; + double sliprates1(sample1) ; + sliprates1:units = "m/s" ; + sliprates1:_DeflateLevel = 1 ; + double sliprates2(sample2) ; + sliprates2:units = "m/s" ; + sliprates2:_DeflateLevel = 1 ; + double sliprates3(sample3) ; + sliprates3:units = "m/s" ; + sliprates3:_DeflateLevel = 1 ; +} diff --git a/science/rconv/src/Map.cpp b/science/rconv/src/Map.cpp new file mode 100644 index 0000000..5642397 --- /dev/null +++ b/science/rconv/src/Map.cpp @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "Map.h" +#include +#include + +#ifndef noproj +void printLastError() +{ + if (pj_errno != 0) { + std::cout << "Proj.4 error: " << pj_strerrno(pj_errno) << std::endl; + } +} + + +Map::Map(std::string const& targetCoordSystem) +{ + if (!(pj_lonlat = pj_init_plus("+proj=lonlat +datum=WGS84 +units=km +no_defs"))) { + printLastError(); + } + if (!(pj_mesh = pj_init_plus(targetCoordSystem.c_str()))) { + printLastError(); + } + + if (pj_mesh->to_meter != 1.0 || pj_mesh->vto_meter != 1.0) { + std::cout << "Warning: The MCS does not use meter as length unit. Note that area and sliprate will be saved in m^2 and m/s so prepare for trouble." << std::endl; + } +} + +Map::~Map() +{ + pj_free(pj_lonlat); + pj_free(pj_mesh); +} + +void Map::map(double longitude, double latitude, double depth, double* x, double* y, double* z) const +{ + *x = longitude * DEG_TO_RAD; + *y = latitude * DEG_TO_RAD; + *z = -depth; + pj_transform(pj_lonlat, pj_mesh, 1, 1, x, y, z); + printLastError(); +} + +// transform from ned (srf coord system) to pj_mesh->axis +void Map::adjustAxes(double* x, double* y, double* z) const +{ + double p[3] = { *x, *y, *z }; // x = n, y = e, z = d + double* v[3] = { x, y, z }; + + for (unsigned i = 0; i < 3; ++i) { + switch (pj_mesh->axis[i]) { + case 'e': + *v[i] = p[1]; + break; + case 'w': + *v[i] = -p[1]; + break; + case 'n': + *v[i] = p[0]; + break; + case 's': + *v[i] = -p[0]; + break; + case 'd': + *v[i] = p[2]; + break; + case 'u': + *v[i] = -p[2]; + break; + default: + std::cerr << "Weird axis definition: " << pj_mesh->axis[i] << std::endl; + break; + } + } +} +#else + +Map::Map(std::string const& targetCoordSystem) +{} + +Map::~Map() +{} +#define DEG_TO_RAD .017453292519943296 +#endif + +void Map::toMCS(double strike, double dip, double rake, double u1, double u2, double u3, double* x, double* y, double* z) const +{ + strike *= DEG_TO_RAD; + dip *= DEG_TO_RAD; + rake *= DEG_TO_RAD; + *x = u1*(sin(rake)*sin(strike)*cos(dip) + cos(rake)*cos(strike)) + u2*(-sin(rake)*cos(strike) + sin(strike)*cos(dip)*cos(rake)) - u3*sin(dip)*sin(strike); + *y = u1*(-sin(rake)*cos(dip)*cos(strike) + sin(strike)*cos(rake)) + u2*(-sin(rake)*sin(strike) - cos(dip)*cos(rake)*cos(strike)) + u3*sin(dip)*cos(strike); + *z = -u1*sin(dip)*sin(rake) - u2*sin(dip)*cos(rake) - u3*cos(dip); +#ifndef noproj + adjustAxes(x, y, z); +#endif +} diff --git a/science/rconv/src/Map.h b/science/rconv/src/Map.h new file mode 100644 index 0000000..6abb32e --- /dev/null +++ b/science/rconv/src/Map.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ +#ifndef RCONV_MAP_H_ +#define RCONV_MAP_H_ + +#ifndef noproj +#include +#endif +#include + +class Map { +public: + Map(std::string const& targetCoordSystem); + ~Map(); + + void map(double longitude, double latitude, double depth, double* x, double* y, double* z) const; + void toMCS(double strike, double dip, double rake, double u1, double u2, double u3, double* x, double* y, double* z) const; + +private: + void adjustAxes(double* x, double* y, double* z) const; + +#ifndef noproj + projPJ pj_lonlat; + projPJ pj_mesh; +#endif +}; + +#endif diff --git a/science/rconv/src/NRFWriter.cpp b/science/rconv/src/NRFWriter.cpp new file mode 100644 index 0000000..321eefa --- /dev/null +++ b/science/rconv/src/NRFWriter.cpp @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "NRFWriter.h" +#include +#include +#include +#include +#include + +using seissol::sourceterm::Subfault; +using seissol::sourceterm::Subfault_units; +using seissol::sourceterm::Offsets; + +struct Point3d { + double x, y, z; +}; + +void check_err(const int stat, const int line, const char *file) { + if (stat != NC_NOERR) { + (void)fprintf(stderr,"line %d of %s: %s\n", line, file, nc_strerror(stat)); + fflush(stderr); + exit(1); + } +} + +void writeNRF(char const* filename, std::vector const& sources, Map const& map, bool normalizeOnset) +{ + unsigned numSources = sources.size(); + double minTinit = std::numeric_limits::max(); + unsigned numSamples[3] = { 0, 0, 0 }; + + for (std::vector::const_iterator source = sources.begin(); source != sources.end(); ++source) { + minTinit = std::min(minTinit, source->tinit); + for (unsigned sr = 0; sr < 3; ++sr) { + numSamples[sr] += source->slipRate[sr].size(); + } + } + if (normalizeOnset) { + std::cout << "Minimal tinit: " << minTinit << " -> 0" << std::endl; + } else { + minTinit = 0.0; + } + + Offsets* offsets = new Offsets[numSources+1]; + memset(offsets, 0, (numSources+1) * sizeof(Offsets)); + + double** sliprates = new double*[3]; + for (unsigned sr = 0; sr < 3; ++sr) { + sliprates[sr] = new double[numSamples[sr]]; + memset(sliprates[sr], 0, numSamples[sr] * sizeof(double)); + } + + Point3d* centres = new Point3d[numSources]; + Subfault* subfaults = new Subfault[numSources]; + for (unsigned i = 0; i < numSources; ++i) { + SRFPointSource const& source = sources[i]; + Point3d& centre = centres[i]; + Subfault& sf = subfaults[i]; + sf.tinit = source.tinit - minTinit; + sf.timestep = source.dt; + +#ifdef noproj + centre.x = source.longitude; + centre.y = source.latitude; + centre.z = source.depth; +#else + map.map(source.longitude, source.latitude, source.depth, ¢re.x, ¢re.y, ¢re.z); +#endif + + map.toMCS(source.strike, source.dip, source.rake, 1.0, 0.0, 0.0, &sf.tan1(0), &sf.tan1(1), &sf.tan1(2)); + map.toMCS(source.strike, source.dip, source.rake, 0.0, 1.0, 0.0, &sf.tan2(0), &sf.tan2(1), &sf.tan2(2)); + map.toMCS(source.strike, source.dip, source.rake, 0.0, 0.0, 1.0, &sf.normal(0), &sf.normal(1), &sf.normal(2)); + + // g / (cm s^2) -> Pa (= kg / (m s^2)) + sf.mu = source.shearModulus * 1.0e-1; + // cm^2 -> m^2 + sf.area = source.area * 1.0e-4; + for (unsigned sr = 0; sr < 3; ++sr) { + unsigned offset = offsets[i][sr]; + std::copy(source.slipRate[sr].begin(), source.slipRate[sr].end(), &sliprates[sr][ offset ]); + offsets[i+1][sr] = offset + source.slipRate[sr].size(); + } + } + + // convert cm / s -> m / s + for (unsigned sr = 0; sr < 3; ++sr) { + for (unsigned sample = 0; sample < numSamples[sr]; ++sample) { + sliprates[sr][sample] *= 1.0e-2; + } + } + + int stat; /* return status */ + int ncid; /* netCDF id */ + + /* group ids */ + int nrf_grp; + + /* type ids */ + int Vector3_typ; + int Subfault_units_typ; + int Subfault_typ; + + /* dimension ids */ + int source_dim; + int sroffset_dim; + int direction_dim; + int sample1_dim; + int sample2_dim; + int sample3_dim; + + /* dimension lengths */ + size_t source_len = numSources; + size_t sroffset_len = numSources + 1; + size_t direction_len = 3; + size_t sample1_len = numSamples[0]; + size_t sample2_len = numSamples[1]; + size_t sample3_len = numSamples[2]; + + /* variable ids */ + int centres_id; + int subfaults_id; + int sroffsets_id; + int sliprates1_id; + int sliprates2_id; + int sliprates3_id; + + /* rank (number of dimensions) for each variable */ +# define RANK_centres 1 +# define RANK_subfaults 1 +# define RANK_sroffsets 2 +# define RANK_sliprates1 1 +# define RANK_sliprates2 1 +# define RANK_sliprates3 1 + + /* variable shapes */ + int centres_dims[RANK_centres]; + int subfaults_dims[RANK_subfaults]; + int sroffsets_dims[RANK_sroffsets]; + int sliprates1_dims[RANK_sliprates1]; + int sliprates2_dims[RANK_sliprates2]; + int sliprates3_dims[RANK_sliprates3]; + + /* enter define mode */ + stat = nc_create(filename, NC_CLOBBER|NC_NETCDF4, &ncid); + check_err(stat,__LINE__,__FILE__); + nrf_grp = ncid; + + stat = nc_def_compound(nrf_grp, sizeof(Point3d), "Vector3", &Vector3_typ); check_err(stat,__LINE__,__FILE__); + { + stat = nc_insert_compound(nrf_grp, Vector3_typ, "x", NC_COMPOUND_OFFSET(Point3d,x), NC_DOUBLE); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Vector3_typ, "y", NC_COMPOUND_OFFSET(Point3d,y), NC_DOUBLE); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Vector3_typ, "z", NC_COMPOUND_OFFSET(Point3d,z), NC_DOUBLE); check_err(stat,__LINE__,__FILE__); + } + + stat = nc_def_compound(nrf_grp, sizeof(Subfault_units), "Subfault_units", &Subfault_units_typ); check_err(stat,__LINE__,__FILE__); + { + stat = nc_insert_compound(nrf_grp, Subfault_units_typ, "tinit", NC_COMPOUND_OFFSET(Subfault_units,tinit), NC_STRING); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_units_typ, "timestep", NC_COMPOUND_OFFSET(Subfault_units,timestep), NC_STRING); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_units_typ, "mu", NC_COMPOUND_OFFSET(Subfault_units,mu), NC_STRING); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_units_typ, "area", NC_COMPOUND_OFFSET(Subfault_units,area), NC_STRING); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_units_typ, "tan1", NC_COMPOUND_OFFSET(Subfault_units,tan1), NC_STRING); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_units_typ, "tan2", NC_COMPOUND_OFFSET(Subfault_units,tan2), NC_STRING); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_units_typ, "normal", NC_COMPOUND_OFFSET(Subfault_units,normal), NC_STRING); check_err(stat,__LINE__,__FILE__); + } + + stat = nc_def_compound(nrf_grp, sizeof(Subfault), "Subfault", &Subfault_typ); check_err(stat,__LINE__,__FILE__); + { + stat = nc_insert_compound(nrf_grp, Subfault_typ, "tinit", NC_COMPOUND_OFFSET(Subfault,tinit), NC_DOUBLE); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_typ, "timestep", NC_COMPOUND_OFFSET(Subfault,timestep), NC_DOUBLE); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_typ, "mu", NC_COMPOUND_OFFSET(Subfault,mu), NC_DOUBLE); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_typ, "area", NC_COMPOUND_OFFSET(Subfault,area), NC_DOUBLE); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_typ, "tan1", NC_COMPOUND_OFFSET(Subfault,tan1), Vector3_typ); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_typ, "tan2", NC_COMPOUND_OFFSET(Subfault,tan2), Vector3_typ); check_err(stat,__LINE__,__FILE__); + stat = nc_insert_compound(nrf_grp, Subfault_typ, "normal", NC_COMPOUND_OFFSET(Subfault,normal), Vector3_typ); check_err(stat,__LINE__,__FILE__); + } + + + /* define dimensions */ + stat = nc_def_dim(nrf_grp, "source", source_len, &source_dim); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_dim(nrf_grp, "sroffset", sroffset_len, &sroffset_dim); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_dim(nrf_grp, "direction", direction_len, &direction_dim); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_dim(nrf_grp, "sample1", sample1_len, &sample1_dim); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_dim(nrf_grp, "sample2", sample2_len, &sample2_dim); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_dim(nrf_grp, "sample3", sample3_len, &sample3_dim); + check_err(stat,__LINE__,__FILE__); + + /* define variables */ + + centres_dims[0] = source_dim; + stat = nc_def_var(nrf_grp, "centres", Vector3_typ, RANK_centres, centres_dims, ¢res_id); + check_err(stat,__LINE__,__FILE__); + + subfaults_dims[0] = source_dim; + stat = nc_def_var(nrf_grp, "subfaults", Subfault_typ, RANK_subfaults, subfaults_dims, &subfaults_id); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_var_deflate(nrf_grp, subfaults_id, NC_NOSHUFFLE, 1, 1); + check_err(stat,__LINE__,__FILE__); + + sroffsets_dims[0] = sroffset_dim; + sroffsets_dims[1] = direction_dim; + stat = nc_def_var(nrf_grp, "sroffsets", NC_UINT, RANK_sroffsets, sroffsets_dims, &sroffsets_id); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_var_deflate(nrf_grp, sroffsets_id, NC_NOSHUFFLE, 1, 1); + check_err(stat,__LINE__,__FILE__); + + sliprates1_dims[0] = sample1_dim; + stat = nc_def_var(nrf_grp, "sliprates1", NC_DOUBLE, RANK_sliprates1, sliprates1_dims, &sliprates1_id); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_var_deflate(nrf_grp, sliprates1_id, NC_NOSHUFFLE, 1, 1); + check_err(stat,__LINE__,__FILE__); + + sliprates2_dims[0] = sample2_dim; + stat = nc_def_var(nrf_grp, "sliprates2", NC_DOUBLE, RANK_sliprates2, sliprates2_dims, &sliprates2_id); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_var_deflate(nrf_grp, sliprates2_id, NC_NOSHUFFLE, 1, 1); + check_err(stat,__LINE__,__FILE__); + + sliprates3_dims[0] = sample3_dim; + stat = nc_def_var(nrf_grp, "sliprates3", NC_DOUBLE, RANK_sliprates3, sliprates3_dims, &sliprates3_id); + check_err(stat,__LINE__,__FILE__); + stat = nc_def_var_deflate(nrf_grp, sliprates3_id, NC_NOSHUFFLE, 1, 1); + check_err(stat,__LINE__,__FILE__); + + /* assign per-variable attributes */ + + { + stat = nc_put_att_text(nrf_grp, centres_id, "units", 1, "m"); + check_err(stat,__LINE__,__FILE__); + } + + { + static const Subfault_units units_att[1] = {{"s", "s", "pascal", "m^2", "m", "m", "m"}} ; + stat = nc_put_att(nrf_grp, subfaults_id, "units", Subfault_units_typ, 1, units_att); + check_err(stat,__LINE__,__FILE__); + } + + { + stat = nc_put_att_text(nrf_grp, sliprates1_id, "units", 3, "m/s"); + check_err(stat,__LINE__,__FILE__); + } + + { + stat = nc_put_att_text(nrf_grp, sliprates2_id, "units", 3, "m/s"); + check_err(stat,__LINE__,__FILE__); + } + + { + stat = nc_put_att_text(nrf_grp, sliprates3_id, "units", 3, "m/s"); + check_err(stat,__LINE__,__FILE__); + } + + + /* leave define mode */ + stat = nc_enddef (nrf_grp); + check_err(stat,__LINE__,__FILE__); + + /* assign variable data */ + + stat = nc_put_var(ncid, centres_id, ¢res[0]); + check_err(stat,__LINE__,__FILE__); + + stat = nc_put_var(ncid, subfaults_id, &subfaults[0]); + check_err(stat,__LINE__,__FILE__); + + stat = nc_put_var_uint(ncid, sroffsets_id, &offsets[0][0]); + check_err(stat,__LINE__,__FILE__); + + stat = nc_put_var_double(ncid, sliprates1_id, sliprates[0]); + check_err(stat,__LINE__,__FILE__); + + stat = nc_put_var_double(ncid, sliprates2_id, sliprates[1]); + check_err(stat,__LINE__,__FILE__); + + stat = nc_put_var_double(ncid, sliprates3_id, sliprates[2]); + check_err(stat,__LINE__,__FILE__); + + stat = nc_close(nrf_grp); + check_err(stat,__LINE__,__FILE__); + + delete[] centres; + delete[] subfaults; + for (unsigned sr = 0; sr < 3; ++sr) { + delete[] sliprates[sr]; + } + delete[] sliprates; + delete[] offsets; +} diff --git a/science/rconv/src/NRFWriter.h b/science/rconv/src/NRFWriter.h new file mode 100644 index 0000000..1bd7706 --- /dev/null +++ b/science/rconv/src/NRFWriter.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ +#ifndef RCONV_NRF_H_ +#define RCONV_NRF_H_ + +#include "SRF.h" +#include "Map.h" + +#include "SourceTerm/NRF.h" + +void writeNRF(char const* filename, std::vector const& sources, Map const& map, bool normalizeOnset = false); + +#endif diff --git a/science/rconv/src/SConscript b/science/rconv/src/SConscript new file mode 100644 index 0000000..3354e0a --- /dev/null +++ b/science/rconv/src/SConscript @@ -0,0 +1,52 @@ +#! /usr/bin/python +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) +# +# @section LICENSE +# Copyright (c) 2015, SeisSol Group +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# @section DESCRIPTION +# + +Import('env') + +env.sourceFiles.extend([ + env.Object('main.cpp'), + env.Object('SRF.cpp'), + env.Object('NRFWriter.cpp'), + env.Object('XMFWriter.cpp'), + env.Object('Map.cpp') +]) + +Export('env') diff --git a/science/rconv/src/SRF.cpp b/science/rconv/src/SRF.cpp new file mode 100644 index 0000000..98eb0ee --- /dev/null +++ b/science/rconv/src/SRF.cpp @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "SRF.h" +#include +#include + +void parseSamples(std::ifstream& in, std::vector& samples, unsigned numSamples) +{ + samples.resize(numSamples); + for (unsigned sampleNo = 0; sampleNo < numSamples; ++sampleNo) { + in >> samples[sampleNo]; + } +} + +void parsePOINTS_1_0(std::ifstream& in, SRFPointSource& ps) +{ + double dummy; + unsigned nt[3]; + + // Point source, line 1 + in >> ps.longitude >> ps.latitude >> ps.depth >> ps.strike >> ps.dip >> ps.area >> ps.tinit >> ps.dt; + // Point source, line 2 + in >> ps.rake >> dummy >> nt[0] >> dummy >> nt[1] >> dummy >> nt[2]; + + ps.shearModulus = 0.0; // = unknown + + for (unsigned i = 0; i < 3; ++i) { + parseSamples(in, ps.slipRate[i], nt[i]); + } +} + +void parsePOINTS_2_0(std::ifstream& in, SRFPointSource& ps) +{ + double vs, den, dummy; + unsigned nt[3]; + + // Point source, line 1 + in >> ps.longitude >> ps.latitude >> ps.depth >> ps.strike >> ps.dip >> ps.area >> ps.tinit >> ps.dt >> vs >> den; + // Point source, line 2 + in >> ps.rake >> dummy >> nt[0] >> dummy >> nt[1] >> dummy >> nt[2]; + + ps.shearModulus = (vs > 0.0 && den > 0.0) ? vs * vs * den : 0.0; + + for (unsigned i = 0; i < 3; ++i) { + parseSamples(in, ps.slipRate[i], nt[i]); + } +} + +std::vector parseSRF(char const* filename) +{ + std::vector srf; + + std::ifstream in(filename, std::ifstream::in); + + double version; + in >> version; + void (*parsePoints)(std::ifstream&, SRFPointSource&); + + if (version == 2.0) { + parsePoints = parsePOINTS_2_0; + } else if (version == 1.0) { + parsePoints = parsePOINTS_1_0; + } else { + std::cerr << "Unsupported SRF version " << version << " in " << filename << "." << std::endl; + return srf; + } + + while (in.good()) { + std::string block; + unsigned num; + in >> block; + if (block.compare("POINTS") == 0) { + in >> num; + unsigned numSources = srf.size(); + unsigned newSize = numSources + num; + srf.resize(newSize); + for (unsigned point = numSources; point < newSize; ++point) { + parsePoints(in, srf[point]); + } + } else if (block.compare("PLANE") == 0) { + in >> num; + // skip plane segments + for (unsigned l = 0; l < 2*num && in.good(); ++ l) { + std::string line; + getline(in, line); + } + } else if (block.compare(0, 1, "#") == 0) { // ignore comments + std::string line; + getline(in, line); // skip line + } else if (block.find_first_not_of(" \t\n\v\f\r") == std::string::npos) { // ignore whitespace line + continue; + } else { + std::cerr << "Unsupported block type " << block << " in " << filename << "." << std::endl; + return srf; + } + } + + in.close(); + + // Erasing sources with zero samples + unsigned numRemoved = 0; + std::vector::iterator source = srf.begin(); + while (source != srf.end()) { + if (source->slipRate[0].size() != 0 || source->slipRate[1].size() != 0 || source->slipRate[2].size() != 0) { + ++source; + } else { + ++numRemoved; + source = srf.erase(source); + } + } + if (numRemoved > 0) { + std::cout << "Removed " << numRemoved << " point sources that did not contain samples." << std::endl; + } + + return srf; +} diff --git a/science/rconv/src/SRF.h b/science/rconv/src/SRF.h new file mode 100644 index 0000000..e0b6f8e --- /dev/null +++ b/science/rconv/src/SRF.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ +#ifndef RCONV_SRF_H_ +#define RCONV_SRF_H_ + +#include +#include + +struct SRFPointSource { + double longitude; // (degree) + double latitude; // (degree) + double depth; // (km) + double strike; // (degree) + double dip; // (degree) + double rake; // (degree) + double shearModulus; // (g/(cm s^2)) + double area; // (cm^2) + double tinit; // (s) initiation time of slip + double dt; // (s) time step of slip rate function + std::vector slipRate[3]; // (cm/s) slip rate samples in u_{1,2,3} direction +}; + +std::vector parseSRF(char const* filename); + +#endif diff --git a/science/rconv/src/SourceTerm/NRF.h b/science/rconv/src/SourceTerm/NRF.h new file mode 100644 index 0000000..621ab70 --- /dev/null +++ b/science/rconv/src/SourceTerm/NRF.h @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2015 SeisSol Group +// SPDX-FileCopyrightText: 2023 Intel Corporation +// +// SPDX-License-Identifier: BSD-3-Clause +// SPDX-LicenseComments: Full text under /LICENSE and /LICENSES/ +// +// SPDX-FileContributor: Author lists in /AUTHORS and /CITATION.cff +// SPDX-FileContributor: Carsten Uphoff + +#ifndef SEISSOL_SRC_SOURCETERM_NRF_H_ +#define SEISSOL_SRC_SOURCETERM_NRF_H_ + +#include +#include +#include +#include + +namespace seissol::sourceterm { + +// (NOTE: naming also used in rconv; hence avoid clang-tidy styleguiding here) + +// NOLINTBEGIN + +typedef struct Subfault_units { + char* tinit; + char* timestep; + char* mu; + char* area; + char* tan1; + char* tan2; + char* normal; +} Subfault_units; + +// NOLINTEND + +using Subfault = struct Subfault { + double tinit{}; + double timestep{}; + double mu{}; + double area{}; + Eigen::Vector3d tan1; + Eigen::Vector3d tan2; + Eigen::Vector3d normal; +}; + +using Offsets = std::array; + +struct NRF { + std::vector centres; + std::vector subfaults; + std::vector sroffsets; + std::array, 3U> sliprates; + [[nodiscard]] std::size_t size() const { return centres.size(); } +}; +} // namespace seissol::sourceterm + +#endif // SEISSOL_SRC_SOURCETERM_NRF_H_ diff --git a/science/rconv/src/XMFWriter.cpp b/science/rconv/src/XMFWriter.cpp new file mode 100644 index 0000000..c6f191f --- /dev/null +++ b/science/rconv/src/XMFWriter.cpp @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2016, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "XMFWriter.h" +#include +#include + + +void writeSlip(std::vector const& sources, std::ofstream& xdmfFile) +{ + xdmfFile << " " << std::endl + << " " << std::endl; + for (std::vector::const_iterator source = sources.begin(); source != sources.end(); ++source) { + std::size_t maxSteps = std::max(std::max(source->slipRate[0].size(), source->slipRate[1].size()), source->slipRate[2].size()); + double slip = 0.0; + double lastAbsSlipRate = 0.0; + // Slip path integration with trapezoidal rule + for (std::size_t step = 0; step < maxSteps; ++step) { + double sr[3]; + for (int d = 0; d < 3; ++d) { + sr[d] = (step < source->slipRate[d].size()) ? source->slipRate[d][step] : 0.0; + } + double absSlipRate = sqrt(sr[0]*sr[0] + sr[1]*sr[1] + sr[2]*sr[2]); + slip += source->dt * (absSlipRate + lastAbsSlipRate) / 2.0; + lastAbsSlipRate = absSlipRate; + } + // Convert to meter and write + xdmfFile << slip / 100.0 << std::endl; + } + xdmfFile << " " << std::endl + << " " << std::endl; +} + +void writeXMF(char const* filename, std::vector const& sources, Map const& map) +{ + std::ofstream xdmfFile; + xdmfFile.open(filename); + + xdmfFile << "" << std::endl + << "" << std::endl + << "" << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl; + + for (std::vector::const_iterator source = sources.begin(); source != sources.end(); ++source) { + double x, y, z; +#ifdef noproj + x = source->longitude; + y = source->latitude; + z = source->depth; +#else + map.map(source->longitude, source->latitude, source->depth, &x, &y, &z); +#endif + xdmfFile << x << " " << y << " " << z << std::endl; + } + + xdmfFile << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl; + + writeSlip(sources, xdmfFile); + + xdmfFile << " " << std::endl + << " " << std::endl + << "" << std::endl; + + xdmfFile.close(); +} diff --git a/science/rconv/src/XMFWriter.h b/science/rconv/src/XMFWriter.h new file mode 100644 index 0000000..4ec92b2 --- /dev/null +++ b/science/rconv/src/XMFWriter.h @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2016, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ +#ifndef RCONV_XMFWRITER_H_ +#define RCONV_XMFWRITER_H_ + +#include "SRF.h" +#include "Map.h" + +void writeXMF(char const* filename, std::vector const& sources, Map const& map); + +#endif diff --git a/science/rconv/src/main.cpp b/science/rconv/src/main.cpp new file mode 100644 index 0000000..8a3eed0 --- /dev/null +++ b/science/rconv/src/main.cpp @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: BSD-3-Clause +/** + * @file + * This file is part of SeisSol. + * + * @author Carsten Uphoff (c.uphoff AT tum.de, http://www5.in.tum.de/wiki/index.php/Carsten_Uphoff,_M.Sc.) + * + * @section LICENSE + * Copyright (c) 2015, SeisSol Group + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @section DESCRIPTION + **/ + +#include "SRF.h" +#include "NRFWriter.h" +#include "XMFWriter.h" + +#include +#include + + +int main(int argc, char** argv) +{ + utils::Args args; + args.addOption("input", 'i', "Input file (.srf)"); + args.addOption("mcs", 'm', "Proj.4 string that describes the mesh coordinate system (e.g. \"+proj=utm +zone=10 +datum=WGS84 +units=m +no_defs\").", utils::Args::Required, false); + args.addOption("output", 'o', "Output file (.nrf)", utils::Args::Required, false); + args.addOption("normalize-onset", 'n', "Subtract the minimum onset time from all onsets.", utils::Args::No, false); + args.addOption("vcs", 'v', "Proj.4 string that describes the coordinate system for visualisation (defaults to geocentric if mcs not given, i.e. \"+proj=geocent +datum=WGS84 +units=m +no_def\").", utils::Args::Required, false); + args.addOption("xdmf", 'x', "Output for visualisation (.xmf)", utils::Args::Required, false); + + args.setCustomHelpMessage("\nWith rconv you may either convert a SRF file to a NRF file, which you can use as input in SeisSol.\n" + "In this case, give the options -i, -m, -o, and optionally -n.\n\n" + "You may also write a file which may be loaded in Paraview for visualisation of the SRF file.\n" + "In this case, give the options -i, -x, and optionally -v.\n\n" + "You may write both files simultaneously by giving all options.\n"); + + if (args.parse(argc, argv) == utils::Args::Success) { + std::string in = args.getArgument("input"); + std::string mcs = args.getArgument("mcs", ""); + std::string out = args.getArgument("output", ""); + bool normalizeOnset = args.isSet("normalize-onset"); + std::string vcs = args.getArgument("vcs", ""); + std::string xdmf = args.getArgument("xdmf", ""); + + if (mcs.empty() && vcs.empty()) { + vcs = "+proj=geocent +datum=WGS84 +units=m +no_defs"; + } else if (vcs.empty()) { + vcs = mcs; + } + + std::cout << "Reading SRF..." << std::flush; + std::vector srf = parseSRF(in.c_str()); + std::cout << "finished." << std::endl; + + if (mcs.empty() != out.empty()) { + std::cerr << "Error: -o and -m may only be given simultaneously." << std::endl; + return -1; + } else if (!mcs.empty()) { + Map map(mcs); + std::cout << "Writing NRF..." << std::flush; + writeNRF(out.c_str(), srf, map, normalizeOnset); + std::cout << "finished." << std::endl; + } + + if (!xdmf.empty()) { + Map mapGeocent(vcs); + std::cout << "Writing XDMF..." << std::flush; + writeXMF(xdmf.c_str(), srf, mapGeocent); + std::cout << "finished." << std::endl; + } + } else { + return -1; + } + + return 0; +} diff --git a/science/read_ini_fault_parameter.py b/science/read_ini_fault_parameter.py new file mode 100755 index 0000000..9e2940d --- /dev/null +++ b/science/read_ini_fault_parameter.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +import easi +import seissolxdmf +import seissolxdmfwriter as sxw +import argparse +import numpy as np + + +class SeissolxdmfExtended(seissolxdmf.seissolxdmf): + def __init__(self, xdmfFilename): + super().__init__(xdmfFilename) + self.xyz = self.ReadGeometry() + self.connect = self.ReadConnect() + + def ReadFaultTags(self): + """Read partition array""" + return self.Read1dData("fault-tag", self.nElements, isInt=True).T + + def ComputeCellCenters(self): + """compute cell center array""" + return ( + self.xyz[self.connect[:, 0]] + + self.xyz[self.connect[:, 1]] + + self.xyz[self.connect[:, 2]] + ) / 3.0 + + def ComputeCellNormals(self, ref_vector): + un = np.cross( + self.xyz[self.connect[:, 1], :] - self.xyz[self.connect[:, 0], :], + self.xyz[self.connect[:, 2], :] - self.xyz[self.connect[:, 0], :], + ) + norm = np.apply_along_axis(np.linalg.norm, 1, un) + un = un / norm[:, np.newaxis] + mysign = np.sign(np.dot(un, ref_vector)) + un = un * mysign[:, np.newaxis] + return un + + +def compute_tractions(dicStress, un): + # compute Strike and dip direction + us = np.zeros(un.shape) + us[:, 0] = -un[:, 1] + us[:, 1] = un[:, 0] + norm = np.apply_along_axis(np.linalg.norm, 1, us) + us = us / norm[:, np.newaxis] + ud = np.cross(un, us) + + def compute_traction_vector(dicStress, un): + nel = un.shape[0] + Tractions = np.zeros((nel, 3)) + a = np.stack((dicStress["s_xx"], dicStress["s_xy"], dicStress["s_xz"]), axis=1) + Tractions[:, 0] = np.sum(a * un, axis=1) + a = np.stack((dicStress["s_xy"], dicStress["s_yy"], dicStress["s_yz"]), axis=1) + Tractions[:, 1] = np.sum(a * un, axis=1) + a = np.stack((dicStress["s_xz"], dicStress["s_yz"], dicStress["s_zz"]), axis=1) + Tractions[:, 2] = np.sum(a * un, axis=1) + return Tractions + + Tractions = compute_traction_vector(dicStress, un) + + outDict = {} + # compute Traction components + outDict["T_n"] = np.sum(Tractions * un, axis=1) + outDict["T_s"] = np.sum(Tractions * us, axis=1) + outDict["T_d"] = np.sum(Tractions * ud, axis=1) + return outDict + + +if __name__ == "__main__": + # parsing python arguments + parser = argparse.ArgumentParser( + description=( + " retrieve initial fault stress from easi/yaml file and fault output file" + ) + ) + parser.add_argument("fault_filename", help="fault.xdmf filename") + parser.add_argument("yaml_filename", help="fault easi/yaml filename") + parser.add_argument( + "--parameters", + help="variable to be read in the yaml file. 'tractions' for initial stress. (coma separated string).", + nargs=1, + default=["tractions"], + ) + parser.add_argument( + "--ref_vector", + nargs=1, + help="reference vector (see seissol parameter file) used to choose fault normal (coma separated string)", + ) + parser.add_argument( + "--output_file", + help="path and prefix of the output file", + nargs=1, + default=["initial-stress-fault"], + ) + args = parser.parse_args() + + sx = SeissolxdmfExtended(args.fault_filename) + centers = sx.ComputeCellCenters() + tags = sx.ReadFaultTags() + parameters = args.parameters[0].split(",") + if "tractions" in parameters: + try: + out = easi.evaluate_model( + centers, tags, ["T_s", "T_d", "T_n"], args.yaml_filename + ) + except ValueError: + if not args.ref_vector: + raise ValueError( + "ref_vector has to be defined for computing tractions from stress" + ) + else: + ref_vector = [float(v) for v in args.ref_vector[0].split(",")] + print(f"[T_s, T_d, T_n] not found in {args.yaml_filename}, using s_ij") + dicStress = easi.evaluate_model( + centers, + tags, + ["s_xx", "s_yy", "s_zz", "s_xy", "s_xz", "s_yz"], + args.yaml_filename, + ) + normals = sx.ComputeCellNormals(ref_vector) + out = compute_tractions(dicStress, normals) + else: + out = easi.evaluate_model(centers, tags, parameters, args.yaml_filename) + + sxw.write( + args.output_file[0], + sx.xyz, + sx.connect, + out, + {}, + reduce_precision=True, + backend="raw", + ) diff --git a/science/stations2reference.py b/science/stations2reference.py new file mode 100644 index 0000000..f6d2204 --- /dev/null +++ b/science/stations2reference.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: BSD-3-Clause +## +# @file +# This file is part of SeisSol. +# +# @author Martin van Driel (driel AT geophysik.uni-muenchen.de) +# +# @section LICENSE +# Copyright (c) 2011, Martin van Driel +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +#--------------------------------------------------------------------- +# Purpose: Transform station coordinates to reference tetrahedron +#--------------------------------------------------------------------- +# +# usage: +# python stations2reference.py +# +# input: +# assumes to find a file 'stations.txt' containing the station coordinates in +# the working directory +# +# output: +# produces a file 'xi_eta_zeta.txt' containing the reference coordinates of +# the stations + +import numpy as np +import sys + +fi = open(sys.argv[1], 'r') + +stats = np.loadtxt('stations.txt') + +xP = stats[:,0] +yP = stats[:,1] +zP = stats[:,2] + +EP = np.zeros(len(xP), dtype=int) +XI = np.zeros(len(xP)) +ETA = np.zeros(len(xP)) +ZETA = np.zeros(len(xP)) +found = np.zeros(len(xP), dtype=bool) + +# read mesh + +for i in range(7): + s = fi.readline() +s = s.split() + +npts = int(s[0]) +nelem = int(s[1]) + +elems = np.empty((nelem, 4), dtype=int) +points = np.empty((npts, 3), dtype=float) + +fi.readline() +fi.readline() + +for i in range(npts): + s = fi.readline().split() + points[i,0] = float(s[1]) + points[i,1] = float(s[2]) + points[i,2] = float(s[3]) + +fi.readline() +fi.readline() + +for i in range(nelem): + s = fi.readline().split() + elems[i,0] = int(s[3]) - 1 + elems[i,1] = int(s[4]) - 1 + elems[i,2] = int(s[5]) - 1 + elems[i,3] = int(s[6]) - 1 + +fi.close() + +x = np.empty(4) +y = np.empty(4) +z = np.empty(4) + +# loop over all elements in mesh + +percent = np.arange(1,11) * (nelem - 1) / 10 +for i in range(nelem): + if i in percent: + print '%3d %% done' % (((percent == i)* np.arange(1, 11)).sum() * 10) + + x[0] = points[elems[i,0],0] + x[1] = points[elems[i,1],0] + x[2] = points[elems[i,2],0] + x[3] = points[elems[i,3],0] + + y[0] = points[elems[i,0],1] + y[1] = points[elems[i,1],1] + y[2] = points[elems[i,2],1] + y[3] = points[elems[i,3],1] + + z[0] = points[elems[i,0],2] + z[1] = points[elems[i,1],2] + z[2] = points[elems[i,2],2] + z[3] = points[elems[i,3],2] + + # transform to reference tetrahedron + + J = -z[0]*x[1]*y[2]+x[0]*z[2]*y[3]+x[0]*z[1]*y[2]+z[3]*x[1]*y[2]+ \ + z[2]*x[3]*y[1]+z[1]*y[3]*x[2]+z[3]*y[0]*x[2]-z[2]*y[0]*x[3]+z[2]* \ + y[0]*x[1]-x[0]*z[1]*y[3]+x[0]*z[3]*y[1]+z[0]*x[1]*y[3]+z[1]*y[0]* \ + x[3]-z[3]*y[0]*x[1]-x[0]*z[3]*y[2]-z[2]*y[3]*x[1]-z[0]*x[2]*y[3]- \ + z[3]*x[2]*y[1]-z[1]*x[3]*y[2]+z[0]*x[2]*y[1]-z[1]*y[0]*x[2]-z[0]*x[3]* \ + y[1]-x[0]*z[2]*y[1]+z[0]*x[3]*y[2] + + + xi = ( z[3]*y[2]+z[0]*y[3]-z[2]*y[3]-z[0]*y[2]-z[3]*y[0]+z[2]*y[0])/J*xP + \ + (-x[0]*z[2]+z[3]*x[0]-z[3]*x[2]+z[0]*x[2]-z[0]*x[3]+x[3]*z[2])/J*yP + \ + (-y[0]*x[2]+y[2]*x[0]+y[0]*x[3]+y[3]*x[2]-y[2]*x[3]-y[3]*x[0])/J*zP + \ + ( x[0]*z[2]*y[3]-z[2]*y[0]*x[3]+z[0]*x[3]*y[2]-x[0]*z[3]*y[2] - \ + z[0]*x[2]*y[3]+z[3]*y[0]*x[2])/J + + eta = -( z[3]*y[1]-z[0]*y[1]+z[0]*y[3]+z[1]*y[0]-z[1]*y[3]-z[3]*y[0])/J*xP - \ + ( z[1]*x[3]-z[1]*x[0]-z[0]*x[3]-z[3]*x[1]+z[3]*x[0]+z[0]*x[1])/J*yP - \ + (-y[1]*x[3]+y[0]*x[3]+y[3]*x[1]-y[0]*x[1]-y[3]*x[0]+y[1]*x[0])/J*zP - \ + (-z[1]*y[0]*x[3]+x[0]*z[1]*y[3]-x[0]*z[3]*y[1]-z[0]*x[1]*y[3] + \ + z[0]*x[3]*y[1]+z[3]*y[0]*x[1])/J + + zeta = (z[0]*y[2]-z[2]*y[0]-z[0]*y[1]+z[2]*y[1]+z[1]*y[0]-z[1]*y[2])/J*xP + \ + (x[0]*z[2]-z[1]*x[0]-z[2]*x[1]+z[0]*x[1]+z[1]*x[2]-z[0]*x[2])/J*yP + \ + (y[1]*x[0]-y[2]*x[0]+x[1]*y[2]-y[0]*x[1]+y[0]*x[2]-x[2]*y[1])/J*zP + \ + (-x[0]*z[2]*y[3]-z[3]*x[1]*y[2]+z[0]*x[2]*y[3]-z[2]*x[3]*y[1] - \ + z[1]*y[3]*x[2]-z[3]*y[0]*x[2]+z[2]*y[0]*x[3]-z[1]*y[0]*x[3] + \ + x[0]*z[1]*y[3]-x[0]*z[3]*y[1]-z[0]*x[1]*y[3]+z[0]*x[3]*y[1] + \ + z[3]*y[0]*x[1]+x[0]*z[3]*y[2]+z[2]*y[3]*x[1]+z[3]*x[2]*y[1] - \ + z[0]*x[3]*y[2]+z[1]*x[3]*y[2]+J)/J + + # test if station is in this element + + inelem = ((xi <= 0.) | (eta <= 0.) | (zeta <= 0.) | (zeta >= (1.-xi-eta))) + inelem = (inelem == False) + + EP += inelem * i + XI += inelem * xi + ETA += inelem * eta + ZETA += inelem * zeta + found += inelem * True + +if False in found: + print 'some station are exactly on a boundary or outside the mesh' + +XI[found == False] = np.nan +ETA[found == False] = np.nan +ZETA[found == False] = np.nan + +# write to file +np.savetxt('stations_xi_eta_zeta.txt', np.array((XI, ETA, ZETA)).T) diff --git a/science/stressrotation2D.m b/science/stressrotation2D.m new file mode 100644 index 0000000..a0c44a8 --- /dev/null +++ b/science/stressrotation2D.m @@ -0,0 +1,86 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Amaryllis Nerger (amaryllis.nerger AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/anerger) +% @author Christian Pelties (pelties AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/pelties) +% +% @section LICENSE +% Copyright (c) 2012-2013, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% @section DESCRIPTION +% 2D Rotation of the fault's stress tensor into the coordinatesystem of the main +% fault + +% convention: +disp('Right-handed coordinate system required'); +disp('Please, make sure to follow this convention during model/mesh generation!'); +disp(''); +disp('z y free-surface North'); +disp('| / | /'); +disp('| / | /'); +disp('| ---> x = | ---> East'); +disp('-z depth'); +disp(' '); +disp('- Normal stress negative in compression'); +disp('- Shear traction right lateral positive'); +disp('- Shear traction left lateral negative'); +disp(' '); +disp('Script rotates values in fault coordinate system into global xyz coordinate system values'); +disp(' '); + +% Input normal stresses +disp('Input normal stresses'); +sxx = input('sxx='); +syy = input('syy='); +disp(' '); + +% Input shear stress +disp('Input shear traction') +sxy = input('sxy='); +disp(' '); + +disp('Input angle: If you transform your values counter clockwise, use a plus sign'); +disp(' If you transform your values clockwise, use a minus sign.'); + +theta = input('theta='); +disp(' '); + +% stress tensor in fault coordinate system Koordinatensystem des Branch +A=[sxx sxy; + sxy syy]; + +% rotary tensor +T=[cos(theta*pi/180) -sin(theta*pi/180); + sin(theta*pi/180) cos(theta*pi/180)]; + +% stress tensor in coordinatesystem of main fault +Stress_in_global_xyz=T*A*T' diff --git a/science/stressrotation3D.m b/science/stressrotation3D.m new file mode 100644 index 0000000..5335868 --- /dev/null +++ b/science/stressrotation3D.m @@ -0,0 +1,109 @@ +%% +% @file +% This file is part of SeisSol. +% SPDX-License-Identifier: BSD-3-Clause +% +% @author Alice Gabriel (gabriel AT geophysik.uni-muenchen.de, http://www.geophysik.uni-muenchen.de/Members/gabriel) +% +% @section LICENSE +% Copyright (c) 2013, SeisSol Group +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% 3. Neither the name of the copyright holder nor the names of its +% contributors may be used to endorse or promote products derived from this +% software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% POSSIBILITY OF SUCH DAMAGE. +% +% @section DESCRIPTION +% 3D Rotation of the fault's stress tensor into the coordinatesystem of the main +% fault; modified from stressrotation2D + +% convention: +disp('Right-handed coordinate system required'); +disp('Please, make sure to follow this convention during model/mesh generation!'); +disp(''); +disp('z y free-surface North'); +disp('| / | /'); +disp('| / | /'); +disp('| ---> x = | ---> East'); +disp('-z depth'); +disp(' '); +disp('- Normal stress negative in compression'); +disp('- Shear traction in strike direction right lateral: positive'); +disp('- Shear traction in strike direction left lateral: negative'); +disp('- Shear traction along dip direction: positive'); +disp('- Shear traction anti dip direction: negative'); +disp(' '); +disp('Script rotates values in fault coordinate system into global xyz coordinate system values'); +disp(' '); + +% Input normal stresses +disp('Input normal stresses'); +sxx = input('sxx='); %example TPV10 at z=-1m: 0 +syy = input('syy='); %example TPV10: -7378 +disp(' '); + +% Input shear stress +disp('Input shear traction') +sxy = input('sxy='); %example TPV10: 0 +syz = input('syz='); %example TPV10: 0.55*7378 +szx = input('szx='); %example TPV10: 0 +disp(' '); + +disp('Input angles: If you transform your values counter clockwise, use a plus sign'); +disp(' If you transform your values clockwise, use a minus sign.'); + +disp(' '); +disp('Input rotation angles about each axis') +thetax = input('theta x='); %example TPV10: -30 +thetay = input('theta y='); %example TPV10: 0 +thetaz = input('theta z='); %example TPV10: 0 + +% stress tensor in fault coordinate system Koordinatensystem des Branch +A=[sxx sxy szx; + sxy syy syz; + szx syz 0]; + +% rotary tensor for rotation around x-axis +Tx=[1 0 0; + 0 cos(thetax*pi/180) -sin(thetax*pi/180) ; + 0 sin(thetax*pi/180) cos(thetax*pi/180) ]; + + +% rotary tensor for rotation around y-axis +Ty=[cos(thetay*pi/180) 0 -sin(thetay*pi/180); + 0 1 0; + sin(thetay*pi/180) 0 cos(thetay*pi/180) ]; + + +% rotary tensor for rotation around z-axis +Tz=[cos(thetaz*pi/180) -sin(thetaz*pi/180) 0; + sin(thetaz*pi/180) cos(thetaz*pi/180) 0 + 0 0 1]; + +% stress tensor in coordinatesystem of main fault +% chain of rotations +A_tempx=Tx*A*Tx'; +A_tempy=Ty*A_tempx*Ty'; +Stress_in_global_xyz=Tz*A_tempy*Tz'