Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
05403d2
[WIP] Drafting the Compressible Euler LES solver (3D)
fluidnumerics-joe Jan 30, 2025
76b367c
Draft json configs and interface for python
fluidnumerics-joe Feb 4, 2025
12308a8
Fix build errors and add self interface library
fluidnumerics-joe Feb 4, 2025
85e8ac9
Add SelfModelConfig class on python side
fluidnumerics-joe Mar 2, 2025
dce1dfb
Merge branch 'feature/python-interface' of github.com:FluidNumerics/S…
fluidnumerics-joe Mar 2, 2025
0e1ea7f
Draft model interface from python side
fluidnumerics-joe Mar 2, 2025
84043bf
Change build option to SELF_ENABLE_INTERFACE
fluidnumerics-joe Mar 12, 2025
ab374de
Allow lib to be set dyamically in the SelfModel init
fluidnumerics-joe Mar 12, 2025
d3152bc
Add ctypes interface for fortran interface module.
fluidnumerics-joe Mar 12, 2025
ee0998d
Add additional support methods for interface
fluidnumerics-joe Mar 13, 2025
75c8fb4
Set up generic interfaces for geometry, port all public interface met…
fluidnumerics-joe Mar 13, 2025
71ebb13
Add utils and consolidate models
fluidnumerics-joe Apr 9, 2025
850c5b1
tidy up draft of python interface
fluidnumerics-joe Apr 10, 2025
a988bd1
Draft class for dynamic boundary conditions
fluidnumerics-joe Apr 25, 2025
b3183a0
Split BoundaryConditions into separate module
fluidnumerics-joe Jul 4, 2025
411f08a
Use extensible bcs in DGModel1D_t
fluidnumerics-joe Jul 4, 2025
4416e17
Split models out of this repository
fluidnumerics-joe Aug 31, 2025
ecfb4c7
Remove distinction between gradient and state bc list
fluidnumerics-joe Oct 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 25.1.0
hooks:
- id: black
language_version: python3
- repo: local
hooks:
- id: fprettify
Expand Down
50 changes: 25 additions & 25 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#
# Maintainers : [email protected]
# Official Repository : https://github.com/FluidNumerics/self/
#
#
# Copyright © 2024 Fluid Numerics LLC
#
#
# 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.
#
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

cmake_minimum_required(VERSION 3.21)
cmake_policy(VERSION 3.21...3.27)
Expand All @@ -38,6 +38,7 @@ option(SELF_ENABLE_EXAMPLES "Option to enable build of examples. (Default On)"
option(SELF_ENABLE_GPU "Option to enable GPU backend. Requires either CUDA or HIP. (Default Off)" OFF)
option(SELF_ENABLE_APU "Option to enable APU backend. Requires either CUDA or HIP. (Default Off)" OFF)
option(SELF_ENABLE_DOUBLE_PRECISION "Option to enable double precision for floating point arithmetic. (Default On)" ON)
option(SELF_ENABLE_INTERFACE "Option to enable Python interface. (Default Off)" OFF)

set(SELF_MPIEXEC_NUMPROCS "2" CACHE STRING "The number of MPI ranks to use to launch MPI tests. Only used when launching test programs via ctest.")
set(SELF_MPIEXEC_OPTIONS "" CACHE STRING "Any additional options, such as binding options, to use for MPI tests.Only used when launching test programs via ctest. Defaults to nothing")
Expand All @@ -54,7 +55,7 @@ FortranCInterface_VERIFY()
if(NOT FortranCInterface_VERIFIED_C)
message(FATAL_ERROR "Fortran compiler must support C Interface")
endif(NOT FortranCInterface_VERIFIED_C)

if(NOT CMAKE_Fortran_COMPILER_SUPPORTS_F90)
MESSAGE(FATAL_ERROR "Fortran compiler does not support F90")
endif(NOT CMAKE_Fortran_COMPILER_SUPPORTS_F90)
Expand Down Expand Up @@ -131,11 +132,6 @@ find_package(MPI COMPONENTS Fortran C REQUIRED)
# HDF5 : See https://cmake.org/cmake/help/latest/module/FindHDF5.html
find_package(HDF5 REQUIRED Fortran)

# # JSON-Fortran
# find_library(JSONFORTRAN_LIBRARIES NAMES jsonfortran REQUIRED)
# find_path(JSONFORTRAN_INCLUDE_DIRS json_module.mod)


# FEQ-Parse
find_library(FEQPARSE_LIBRARIES NAMES feqparse REQUIRED)
find_path(FEQPARSE_INCLUDE_DIRS feqparse.mod)
Expand Down Expand Up @@ -225,19 +221,23 @@ endif()

# Libraries
add_subdirectory(${CMAKE_SOURCE_DIR}/src)
# link_directories(${CMAKE_BINARY_DIR}/src)

if(SELF_ENABLE_INTERFACE)
# JSON-Fortran
find_library(JSONFORTRAN_LIBRARIES NAMES jsonfortran REQUIRED)
find_path(JSONFORTRAN_INCLUDE_DIRS json_module.mod)
add_subdirectory(${CMAKE_SOURCE_DIR}/src/python)
endif()

if(SELF_ENABLE_TESTING)
enable_testing()
add_subdirectory(${CMAKE_SOURCE_DIR}/test)
if(SELF_ENABLE_EXAMPLES)
add_subdirectory(${CMAKE_SOURCE_DIR}/examples)
endif()
else()
if(SELF_ENABLE_EXAMPLES)
enable_testing()
add_subdirectory(${CMAKE_SOURCE_DIR}/examples)
endif()
endif()

if(SELF_ENABLE_EXAMPLES)
add_subdirectory(${CMAKE_SOURCE_DIR}/examples)
endif()


# Share / etc resources
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/share DESTINATION ${CMAKE_INSTALL_PREFIX})
5 changes: 5 additions & 0 deletions docs/MeshGeneration/BoundaryConditions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Boundary Conditions

In most mesh generation software, you are given the ability to align a name (string/character) and an integer id with each face, node, or edge that lies on a physical boundary. This information is often used in physical modeling software, like SELF, to implement the appropriate boundary conditions for your model. SELF provides a flexible framework for mapping boundary condition names and integer ids to procedures that you can implement for specific boundary conditions. This section of the documentation provides an overview of how you can register custom boundary conditions for a model built with SELF. Additionally we'll cover how you will want to register boundary conditions in a way that is consistent with the meshes that you create in other external software (e.g. HOHQMesh).

## How boundary conditions are registered in SELF
59 changes: 59 additions & 0 deletions examples/linear_shallow_water2d_kelvinwaves.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from pyself.interface import SelfModel
from pyself.config import SelfModelConfig
import os
from datetime import datetime


pwd = os.path.dirname(os.path.abspath(__file__))
# Set the case directory to a new unique directory based in the time stamp
# get current working directory

case_directory = f"{os.getcwd()}/kelvinwaves-{datetime.now().strftime('%Y%m%d-%H%M%S')}"


def configure_geometry(config):
# Configure geometry
config.set_parameter(
"geometry", "mesh_file", f"{pwd}/../share/mesh/Circle/Circle_mesh.h5"
)
config.set_parameter("geometry", "uniform_boundary_condition", "no_normal_flow")
config.set_parameter("geometry", "control_degree", 7)
config.set_parameter("geometry", "control_quadrature", "gauss")


def configure_time_options(config):
# Configure time options
config.set_parameter("time_options", "integrator", "euler")
config.set_parameter("time_options", "dt", 0.0025)
config.set_parameter("time_options", "start_time", 0.0)
config.set_parameter("time_options", "duration", 1.0)
config.set_parameter("time_options", "io_interval", 0.05)
config.set_parameter("time_options", "update_interval", 50)


def configure_shallow_water(config):
# Configure shallow water parameters
config.set_parameter("linear-shallow-water-2d", "g", 1.0)
config.set_parameter("linear-shallow-water-2d", "H", 1.0)
config.set_parameter("linear-shallow-water-2d", "Cd", 0.25)
config.set_parameter("linear-shallow-water-2d", "f0", 10.0)
config.set_parameter("linear-shallow-water-2d", "beta", 0.0)


def main():

config = SelfModelConfig(case_directory=case_directory)
config.config["model_name"] = "linear-shallow-water-2d"

configure_geometry(config)
configure_time_options(config)
configure_shallow_water(config)

# Create the model
model = SelfModel(config=config)

x, y = model.get_coordinates()


if __name__ == "__main__":
main()
12 changes: 11 additions & 1 deletion pyself/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
A python package for interfacing with the Spectral Element Library in Fortran (https://github.com/fluidnumerics/SELF).
"""

__version__ = "0.1.0"
from ._version import version

__version__ = version
__title__ = "pyself"
__author__ = "Dr. Joe Schoonover"
__credits__ = "Fluid Numerics LLC"


from pyself.config import *
from pyself.geometry import *
from pyself.interface import *
from pyself.lagrange import *
from pyself.model import *
1 change: 1 addition & 0 deletions pyself/_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .library import *
39 changes: 39 additions & 0 deletions pyself/_utils/library.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import ctypes.util
import os


def find_library_full_path(library_name):
"""
Finds the full path of a library using ctypes.util.find_library.

Args:
library_name: The name of the library to find.

Returns:
The full path of the library, or None if not found.
"""
library_path = ctypes.util.find_library(library_name)
print(f"Library path for {library_name}: {library_path}")
if library_path:
if os.path.isabs(library_path):
return library_path
else:
# On Linux, find_library often returns just the filename, so we search in common library paths
for path in ["/lib", "/usr/lib", "/usr/local/lib"]:
full_path = os.path.join(path, library_path)
if os.path.exists(full_path):
return full_path
# If not found in standard paths, try searching in the directories in LD_LIBRARY_PATH
ld_library_path = os.environ.get("LD_LIBRARY_PATH")
print(f"LD_LIBRARY_PATH: {ld_library_path}")
if ld_library_path:
for path in ld_library_path.split(":"):
full_path = os.path.join(path, library_path)
print(
f"Checking {full_path} for library {library_name} : {os.path.exists(full_path)}"
)
if os.path.exists(full_path):
return full_path
# If still not found, return None
return None
return None
1 change: 1 addition & 0 deletions pyself/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version = "v0.1.0"
101 changes: 101 additions & 0 deletions pyself/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import json
from typing import Optional, Dict, Any
import os
from ._version import version


class SelfModelConfig:
def __init__(
self, config_file: Optional[str] = None, case_directory: Optional[str] = None
):
"""Initialize the SELF model configuration from a JSON file or defaults."""
self.config = self.default_config()

self.config_file = config_file

if config_file:
self.load_config(config_file)

if case_directory:
self.case_directory = case_directory
os.makedirs(self.case_directory, exist_ok=True)
else:
self.case_directory = os.getcwd()

@staticmethod
def default_config() -> Dict[str, Any]:
"""Return default configuration based on the JSON schema."""
return {
"version": version,
"model_name": "linear-shallow-water-2d",
"geometry": {
"mesh_file": "",
"uniform_boundary_condition": "no_normal_flow",
"control_degree": 7,
"control_quadrature": "gauss",
"target_degree": 10,
"target_quadrature": "uniform",
"nX": 5,
"nY": 5,
"nZ": 5,
"nTx": 1,
"nTy": 1,
"nTz": 1,
"dx": 0.02,
"dy": 0.02,
"dz": 0.02,
},
"time_options": {
"integrator": "euler",
"dt": 0.001,
"cfl_max": 0.5,
"start_time": 0.0,
"duration": 1.0,
"io_interval": 0.1,
"update_interval": 50,
},
"units": {"time": "s", "length": "m", "mass": "kg"},
"linear-shallow-water-2d": {
"g": 1.0,
"H": 1.0,
"Cd": 0.01,
"f0": 0.0,
"beta": 0.0,
"initial_conditions": {
"geostrophic_balance": False,
"file": "",
"u": 0.0,
"v": 0.0,
"eta": 0.0,
},
"boundary_conditions": {
"time_dependent": False,
"dt": 0.0,
"from_initial_conditions": False,
"u": 0.0,
"v": 0.0,
"eta": 0.0,
},
},
}

def load_config(self, file_path: str):
"""Load configuration from a JSON file"""
with open(file_path, "r") as f:
self.config.update(json.load(f))

def save_config(self):
"""Save configuration to a JSON file in the self.case_directory."""
with open(f"{self.case_directory}/model_input.json", "w") as f:
json.dump(self.config, f, indent=4)

def set_parameter(self, section: str, key: str, value: Any):
"""Set a specific parameter within the configuration."""
if section in self.config and key in self.config[section]:
self.config[section][key] = value
else:
raise KeyError(f"Invalid section '{section}' or key '{key}'.")

def get_parameter(self, section: str, key: str) -> Any:
"""Retrieve a specific parameter value."""
return self.config.get(section, {}).get(key, None)
Loading
Loading