Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
57 changes: 57 additions & 0 deletions build_sfincs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
set -euo pipefail

# Build the BMI shared library in the same environment style as the documented
# working SFINCS build.

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SRC_DIR="$ROOT/extern/SFINCS/source/src"
BUILD_DIR="$ROOT/extern/SFINCS/cmake_build"

# Prefer the active conda/pixi env if present
if [[ -n "${CONDA_PREFIX:-}" ]]; then
export NETCDF_PREFIX="$CONDA_PREFIX"
export PKG_CONFIG_PATH="$CONDA_PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
fi

# Fall back to nc-config if available
if command -v nc-config >/dev/null 2>&1; then
NC_INC="$(nc-config --includedir)"
NC_LIB="$(nc-config --libdir)"
else
echo "ERROR: nc-config not found on PATH"
exit 1
fi

# Match the documented SFINCS build flags as closely as possible
export FCFLAGS="${FCFLAGS:-} -fopenmp -O3 -fallow-argument-mismatch -w"
export FFLAGS="${FFLAGS:-} -fopenmp -O3 -fallow-argument-mismatch -w"
export CFLAGS="${CFLAGS:-}"
export CXXFLAGS="${CXXFLAGS:-}"

# Clean rebuild while debugging env issues
rm -rf "$BUILD_DIR"

cmake -S "$SRC_DIR" -B "$BUILD_DIR" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER="${CC:-gcc}" \
-DCMAKE_Fortran_COMPILER="${FC:-gfortran}" \
-DNETCDF_PREFIX="${NETCDF_PREFIX:-}" \
-DSFINCS_ENABLE_NETCDF=ON \
-DSFINCS_ENABLE_OPENMP=ON \
-DSFINCS_BUILD_TESTS=OFF \
-DCMAKE_Fortran_FLAGS_RELEASE="$FCFLAGS" \
-DCMAKE_EXE_LINKER_FLAGS="-L$NC_LIB -Wl,-rpath,$NC_LIB" \
-DCMAKE_SHARED_LINKER_FLAGS="-L$NC_LIB -Wl,-rpath,$NC_LIB" \
-DCMAKE_Fortran_FLAGS="-g -O0 -fcheck=all -fbacktrace -ffpe-trap=invalid,zero,overflow" \
-DCMAKE_C_FLAGS_RELEASE="${CFLAGS}" \
-DCMAKE_CXX_FLAGS_RELEASE="${CXXFLAGS}"

cmake --build "$BUILD_DIR" -j1

echo
echo "Built:"
echo " $BUILD_DIR/libsfincs_bmi.so"
echo
echo "Runtime linkage:"
ldd "$BUILD_DIR/libsfincs_bmi.so" || true
12 changes: 12 additions & 0 deletions build_test_sfincs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cmake -B cmake_build -S . \
-DNGEN_WITH_BMI_FORTRAN=ON \
-DNGEN_BUILD_COASTAL_TESTS=ON \
-DNGEN_WITH_TESTS=OFF \
-DCMAKE_BUILD_TYPE=Debug \
-DNGEN_ENABLE_SCHISM=OFF \
-DSFINCS_BMI_LIBRARY=/home/mohammed.karim/Calibration/ngen/extern/SFINCS/source/src/build/libsfincs_bmi.so \
-DSFINCS_INIT_CONFIG=/home/mohammed.karim/Calibration/ngen/extern/SFINCS/source/src/build/sfincs_config.txt
cmake --build cmake_build -j
ctest --test-dir cmake_build -N | grep -i sfincs
ctest --test-dir cmake_build -R sfincs -V

21 changes: 21 additions & 0 deletions include/realizations/coastal/SfincsCreator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef SFINCS_CREATOR_HEADER
#define SFINCS_CREATOR_HEADER

#include "realizations/coastal/ModelCreator.h"
#include "realizations/coastal/Coastal_Config_Params.h"

class SfincsCreator : public ModelCreator {
public:
std::unique_ptr<CoastalFormulation>
createCoastalFormulation(coastal_config_params const&,
Simulation_Time const&) const override;

SfincsCreator* clone() const override;

private:
void writeInitConfig(coastal_config_params const&,
Simulation_Time const&) const;
};

#endif // SFINCS_CREATOR_HEADER

94 changes: 94 additions & 0 deletions include/realizations/coastal/SfincsFormulation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#pragma once

#include <string>
#include <vector>
#include <memory>

#include <boost/core/span.hpp>

#include "NGenConfig.h"

#include "realizations/coastal/CoastalFormulation.hpp"

// BMI Fortran adapter (correct include + namespace)
#if NGEN_WITH_BMI_FORTRAN
#include "bmi/Bmi_Fortran_Adapter.hpp"
#endif

/**
* SfincsFormulation
*
* Mirrors the structure of SchismFormulation:
* - derives from CoastalFormulation (which derives MeshPointsDataProvider)
* - provides required DataProvider<> pure virtuals
* - owns a BMI adapter instance
* - optionally consumes met/offshore/channel boundary providers
*/
class SfincsFormulation final : public CoastalFormulation
{
public:
// Match SchismFormulation style typedefs
using ProviderType = data_access::MeshPointsDataProvider;
using ProviderPtr = std::shared_ptr<ProviderType>;

SfincsFormulation(std::string model_id,
std::string library_file,
std::string init_config,
ProviderPtr met_provider,
ProviderPtr offshore_provider,
ProviderPtr channel_provider);

~SfincsFormulation() override;

// --- BMI lifecycle ---
void initialize() override;
void finalize() override;
void update() override;
void update_until(double const& t) override;

// --- Time ---
double get_current_time() override;
double get_start_time() override;
double get_end_time() override;
double get_time_step() override;

// --- MeshPointsDataProvider interface (from MeshPointsDataProvider) ---
// Required by CoastalFormulation (pure virtual)
void get_values(const selection_type& selector, boost::span<double> data) override;

// Optional convenience overload (NOT override)
void get_values(const selection_type& selector, std::vector<double>& out);

std::size_t mesh_size(const std::string& mesh_name) override;

// --- DataProvider<double, MeshPointsSelector> pure virtuals ---
boost::span<const std::string> get_available_variable_names() const override;
long get_data_start_time() const override;
long get_data_stop_time() const override;
long record_duration() const override;
std::size_t get_ts_index_for_time(const time_t& epoch_time) const override;
data_type get_value(const selection_type& selector, data_access::ReSampleMethod m=data_access::SUM) override;

private:
void create_formulation_();
void destroy_formulation_();

// Optional: push forcing into BMI vars (keep minimal for now)
void set_inputs_();

private:
std::string model_id_;
std::string library_file_;
std::string init_config_;

ProviderPtr met_provider_;
ProviderPtr offshore_provider_;
ProviderPtr channel_provider_;

std::vector<std::string> available_vars_;

#if NGEN_WITH_BMI_FORTRAN
std::unique_ptr<models::bmi::Bmi_Fortran_Adapter> bmi_;
#endif
};

26 changes: 18 additions & 8 deletions src/NGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
#include <Catchment_Formulation.hpp>
#include <HY_Features.hpp>
#include "realizations/coastal/ModelCreatorRegistry.h"

#if NGEN_ENABLE_SCHISM
#include "realizations/coastal/SchismCreator.h"
#endif

#include "realizations/coastal/SfincsCreator.h"

#if NGEN_WITH_SQLITE3
#include <geopackage.hpp>
Expand Down Expand Up @@ -51,7 +56,7 @@ bool is_subdivided_hydrofabric_wanted = false;
#include "core/Partition_Parser.hpp"
#include <HY_Features_MPI.hpp>

#include "core/Partition_One.hpp"
#include "core/Partition_One.hpp>"

std::string PARTITION_PATH = "";
#endif // NGEN_WITH_MPI
Expand Down Expand Up @@ -608,25 +613,30 @@ int main(int argc, char *argv[]) {

// create the factory registry
ModelCreatorRegistry &registry = ModelCreatorRegistry::getInstance();
// add the Schism factory to the registry

// register all supported coastal models
#if NGEN_ENABLE_SCHISM
registry.registerCreator(ModelType::SCHISM, std::make_unique<SchismCreator>());
// add more factories for coastal models, e.g. sfincs
//....

// retrieve the creator for the model selected
#endif

registry.registerCreator(ModelType::SFINCS, std::make_unique<SfincsCreator>()); //

// retrieve the creator for the model selected in the config
std::unique_ptr<ModelCreator> coastal_creator =
registry.getCreator(coastal_conf->getModelType());
// now run the schism model

// execute the selected coastal model (SCHISM or SFINCS)
coastal_creator->executeModel( *coastal_conf,
*(manager->Simulation_Time_Object) );

}

manager->finalize();
manager->finalize();

#if NGEN_WITH_MPI
MPI_Finalize();
#endif

return 0;
}

Loading