diff --git a/.conda/README.md b/.conda/README.md index dd9f7956e..ec2be7ada 100644 --- a/.conda/README.md +++ b/.conda/README.md @@ -165,4 +165,49 @@ conda activate fierro-dev ``` And then you have all of the dependencies necessary to successfully build Fierro from source. -These packages are `noarch: generic` packages, because they don't contain any architecture/OS specific build artifacts themselves. Whether or not you can install them on your system depends solely on the dependencies being available. \ No newline at end of file +These packages are `noarch: generic` packages, because they don't contain any architecture/OS specific build artifacts themselves. Whether or not you can install them on your system depends solely on the dependencies being available. + + +## Debugging Tips +Anaconda packages are great when they work, but debugging them can be a pain, since it takes so long (relatively) to initailize the build environment. If you find yourself having to debug a conda package, don't waste time and follow these tips: + + +### Inspect the build/host environments. +The intermediate build environments created can be found under `~/anaconda3/conda-bld/`. These are cleaned up if the build is successful, but are left for inspecting if it fails. Your intermediate environemnts might look something like `~/mambaforge/conda-bld/fierro-cpu_1702931506301`, and ones that are still around can be uncovered by running `conda env list`: +``` +# conda environments: +# + ~/anaconda3 +base * ~/mambaforge + ~/mambaforge/conda-bld/cross-apple-test_1699913171912/_build_env + ~/mambaforge/conda-bld/fierro-cpu_1702931083445/_build_env + ~/mambaforge/conda-bld/fierro-cpu_1702931506301/_build_env + ~/mambaforge/conda-bld/fierro-evpfft_1700005728459/_build_env + ~/mambaforge/conda-bld/fierro-heffte-cuda_1702567877996/_build_env + ~/mambaforge/conda-bld/fierro-heffte-cuda_1702568248715/_build_env + ~/mambaforge/conda-bld/fierro-heffte-cuda_1702569485778/_build_env + ~/mambaforge/conda-bld/fierro-heffte-cuda_1702571726755/_build_env + ~/mambaforge/conda-bld/fierro-heffte-cuda_1702572653009/_build_env + ~/mambaforge/conda-bld/fierro-heffte-cuda_1702573356532/_build_env + ~/mambaforge/conda-bld/fierro-heffte-cuda_1702581207071/_build_env + ~/mambaforge/conda-bld/fierro-heffte-cuda_1702582399999/_build_env + ~/mambaforge/conda-bld/fierro-voxelizer-py_1700001705130/_build_env + ~/mambaforge/conda-bld/fierro-voxelizer-py_1700003960166/_build_env + ~/mambaforge/conda-bld/fierro-voxelizer-py_1700006765747/_build_env +EVPFFT_MATAR ~/mambaforge/envs/EVPFFT_MATAR +... ... + +``` + +Under that build folder you will find 3 relevant things: +1. `_build_env` -- The environment where your "build" dependencies get installed (aka `$BUILD_PREFIX`) +2. `_h_env_placehold_placehold_placehold_placehold_placehold...` -- The environment where your "host" dependencies get installed, and where you install your package (aka `$PREFIX`). +3. `work` -- Where your source files are placed + where `conda_build.sh` (the exact script that is run) can be found. + +You can activate each of these environments or just inspect the installed packages with `conda list -p `. + +### Modify and rebuild under `work` +If you think you identified the issue, don't go back and try the package build again. First modify the intermediate build files and try the rebuild from there. If you think you are missing a host dependency, for example, run `conda install -p ` and rerun `work/conda_build.sh` to see if that fixes it. If you think you need to modify the build script, just change `conda_build.sh` and rerun. Once the package builds successfully, make sure to make you changes to the original `meta.yaml` and/or `build.sh` files and then try the package build again. + +### Targetting Cross Compiling +If you are having issues with the cross-compiling build targets, you can speicfically target just those by adding `--variants "{ target_platform: linux-aarch64 }"`. If you are using the `.conda/build_variants.yaml` file, you will need to comment out the variants you don't want to test. \ No newline at end of file diff --git a/.conda/fierro/cpu/build.sh b/.conda/fierro/cpu/build.sh index b2c2cd210..58a902ee3 100755 --- a/.conda/fierro/cpu/build.sh +++ b/.conda/fierro/cpu/build.sh @@ -1,26 +1,22 @@ -export SRC_DIR=$(pwd) -mkdir -p build -cd build - -export MPI_FLAGS="--allow-run-as-root" - -if [ $(uname) == Linux ]; then - export MPI_FLAGS="$MPI_FLAGS;-mca;plm;isolated" -fi - # These flag variables are set by anaconda. source "$RECIPE_DIR/../../cross-compile-setup.sh" +mkdir build +cd build + +# -D _LIBCPP_DISABLE_AVAILABILITY +# is added to the CXXFLAGS for MacOS builds. +# see https://conda-forge.org/docs/maintainer/knowledge_base.html#newer-c-features-with-old-sdk -cmake -D CMAKE_BUILD_TYPE:STRING=RELEASE \ +cmake .. \ + -D CMAKE_BUILD_TYPE:STRING=RELEASE \ -D CMAKE_INSTALL_PREFIX:PATH=$PREFIX \ -D CMAKE_CXX_STANDARD:STRING=17 \ -D BUILD_PARALLEL_EXPLICIT_SOLVER=ON \ -D BUILD_IMPLICIT_SOLVER=ON \ -D BUILD_ELEMENTS=OFF \ - -D DISTRIBUTION=True \ + -D DISTRIBUTION=On \ $CMAKE_ARGS \ - $SRC_DIR \ - -D CMAKE_CXX_FLAGS="$PATCHED_CXXFLAGS -fopenmp" \ + -D CMAKE_CXX_FLAGS="$PATCHED_CXXFLAGS -fopenmp -D_LIBCPP_DISABLE_AVAILABILITY" \ -D MPI_C_COMPILER="$BUILD_PREFIX/bin/mpicc" \ -D MPI_CXX_COMPILER="$BUILD_PREFIX/bin/mpicxx" \ -D VECTOR_ARCH_FLAGS="$VECTOR_ARCH_FLAGS" \ diff --git a/.conda/fierro/cpu/meta.yaml b/.conda/fierro/cpu/meta.yaml index 1a5688b42..80e12407c 100644 --- a/.conda/fierro/cpu/meta.yaml +++ b/.conda/fierro/cpu/meta.yaml @@ -1,5 +1,9 @@ {% set version = "1.0.0" %} -{% set compiler_version = "10.4.0" %} +{% set linux_compiler_version = "10.4.0" %} +{% set macos_compiler_version = "12" %} +# We need the same MPI version in build + host. +# So we have to specify it, unfortunately +{% set mpi_version = "4.1" %} package: name: fierro-cpu @@ -10,27 +14,28 @@ source: git_depth: 1 build: - number: 1 + number: 2 script_env: - PLATFORM={{ target_platform }} requirements: build: - cmake >=3.17.0 - - {{ compiler('c') }} ={{ compiler_version }} - - {{ compiler('cxx') }} ={{ compiler_version }} - - openmpi + - {{ compiler('c') }}={{ linux_compiler_version }} # [linux] + - {{ compiler('c') }}={{ macos_compiler_version }} # [osx] + - {{ compiler('cxx') }}={{ linux_compiler_version }} # [linux] + - {{ compiler('cxx') }}={{ macos_compiler_version }} # [osx] + - openmpi={{ mpi_version }} host: - - _openmp_mutex - - openmpi + - _openmp_mutex # [linux] + - llvm-openmp # [osx] + - openmpi={{ mpi_version }} - fierro-trilinos-cpu - elements run: - fierro-trilinos-cpu - mpi -#TODO: Add tests - about: home: https://github.com/lanl/Fierro license: BSD-3-Clause diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 93bffff8f..8b310de57 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -60,3 +60,15 @@ The recipe_dir is the folder containing the conda build `meta.yaml` file as well The second is the package specific action that triggers off of package specific source code changes and invokes `build-conda-package` with the correct package recipe location and additional build variants. In the case of our source-in-repo packages, these trigger of off relevant source code changes. For other dependencies, where the source is not contained in the repo, we configure the actions for manual dispatch. + +# Debugging +Complex github actions can be very annoying to debug for two reasons: +1. The feedback loop is long/slow. Pushing changes to github and waiting for a runner to initialize can easily add ~5 mins to your feedback loop. +2. You don't have easy access to the runtime environment. Github automatically will unmount the docker image and be on its way if an action fails. + +We have some tools to deal with this, though. If you can run docker (not WSL1), you can use [act](https://github.com/nektos/act) to execute github actions locally. This is **much** faster for debugging things like action syntax. We also have a tool to deal with #2 that I have built into the `build-conda-package` action. We have a `debug` option that enables a special workflow step after the package building step. If the debug flag is set, we make use of the [tmate](https://github.com/mxschmitt/action-tmate) github action to create a temporary ssh host and wait for 30 minutes. On the github Actions page you can inspect the log and find something like: +``` +SSH: ssh bJV7VnwDn5NUzBn6fGrkJYQg9@nyc1.tmate.io +``` + +If you are the user that triggered the action, you can ssh into the docker container that was runing your build action. From there you can continue debugging. \ No newline at end of file diff --git a/.github/workflows/publish-fierro-cpu.yaml b/.github/workflows/publish-fierro-cpu.yaml new file mode 100644 index 000000000..561447e42 --- /dev/null +++ b/.github/workflows/publish-fierro-cpu.yaml @@ -0,0 +1,15 @@ +name: 'Publish Fierro-CPU' + +on: + push: + paths: + - .conda/fierro/cpu/** + - .github/workflows/publish-fierro-cpu.yaml + workflow_dispatch: + +jobs: + publish: + uses: ./.github/workflows/build-conda-package.yaml + with: + recipe_dir: .conda/fierro/cpu + secrets: inherit diff --git a/src/CLI/README.md b/src/CLI/README.md new file mode 100644 index 000000000..9fb134b7e --- /dev/null +++ b/src/CLI/README.md @@ -0,0 +1,168 @@ +# Fiero Command Line Interface +This CLI package is a Fierro command line interface that is intended to act as a consolidated front-end for our Fierro backend tools. It provides a consistent interface and framework for exposing tools to the user. + +## Front-End +The front end here is built off of [argparse](https://github.com/p-ranav/argparse), which implements a language agnostic standard for simple command line interface design. It defines a syntax for programs from the command line with suitable helptext/defaults/post-processing. + +The Fierro-CLI implements two things: +1. Output directory -- A directory to run the program in. Outputs of the program will by default be put here if some other backend specific option is not specified. +2. Subcommands -- a list of argparse "subcommands" that each represent an available backend tool. + +Example: +``` +$ fierro -h + +Usage: fierro [--help] [--version] [--output VAR] {mesh-builder,parallel-explicit,parallel-implicit,voxelizer} + +Optional arguments: + -h, --help shows help message and exits + -v, --version prints version information and exits + -o, --output output directory for the program [default: "."] + +Subcommands: + mesh-builder Build rectangular or cylindrical mesh in 2 or 3 dimensions. Useful for setting up test problems. + parallel-explicit Use an explicit solution scheme to step the system. + parallel-implicit Use an implicit solution scheme to step the system. + voxelizer Take a mesh defined by an STL and turn it into a dense voxel grid represented by a VTK structured mesh. The extent of the grid is selected by taking the minimum and maximum extent of the mesh along each dimenison. Note: Only supports binary STL mesh inputs +``` + +## Backends +This Fierro-CLI package is designed to operate decoupled from backends. Each registered backend is an executable that may or may not be present in the system. + +### Registering Backends +To add a new backend, you only need to do a couple of steps. +#### 1. Implementing NewBackend.hpp +You should start by copying one of the existing backend.hpp files and implementing your new backend. We will use `VoxelizerBackend.hpp` as an example. + +You should derive from `FierroBackend` and tell the base class which executable name to look for +```c++ +#include "backend.hpp" +struct VoxelizerBackend: public FierroBackend { + VoxelizerBackend() : FierroBackend("fierro-voxelizer") { + ... + } + ... +}; +``` + +Then, in the constructor, setup your argparse command + +```c++ + +struct VoxelizerBackend: public FierroBackend { + VoxelizerBackend() : FierroBackend("fierro-voxelizer") { + + this->command = std::shared_ptr( + new argparse::ArgumentParser("voxelizer") // <--- This is the name that shows up under "Subcommands:" in the CLI + ); + + // Here you can add your arguments with their helptext. + this->command->add_argument("input-file") + .help("The binary STL file to voxelize.") + .action(absolute_fp); // <-- You can also add a post-processing command. In this case we convert the input filepath to an absolute one. + this->command->add_argument("output-name") + .help("The name of the VTK structured mesh output file."); + this->command->add_argument("x") + .help("The number of voxels along the X direction (int)."); + this->command->add_argument("y") + .help("The number of voxels along the Y direction (int)."); + this->command->add_argument("z") + .help("The number of voxels along the Z direction (int)."); + this->command->add_argument("use-index-space") + .help("Wether or not to output the VTK in index-space coordinates."); + + // Add a description for your subcommand + this->command->add_description( + "Take a mesh defined by an STL and turn it into a dense voxel grid represented by a VTK structured mesh. " + "The extent of the grid is selected by taking the minimum and maximum extent of the mesh along each dimenison. " + "Note: Only supports binary STL mesh inputs." + ); + } + ... +}; +``` + +Lastly you tell the CLI framework how to actually invoke the backend command. This is mostly just building a system command string and invoking it, but I suppose you could do whatever you want. +```c++ + +struct VoxelizerBackend: public FierroBackend { + ... + + /** + * Invoke the backend executable. + * Will throw an ArgumentException if the arguments aren't valid. + * + * @return Return code of the executable. + */ + int invoke() { + if (!exec_path.has_value()) + throw std::runtime_error("Cannot invoke executable without absolute path."); + + auto err = this->validate_arguments(); + if (err.has_value()) throw ArgumentException(err.value()); + + std::string sys_command; + sys_command = this->exec_path.value().string() + + " " + this->command->get("input-file") + + " " + this->command->get("output-name") + + " " + this->command->get("x") + + " " + this->command->get("y") + + " " + this->command->get("z") + + " " + this->command->get("use-index-space"); + + return system(sys_command.c_str()); + } +}; +``` + +You probably also want to add some validation to your input arguments. The voxelizer does this with a serparate function: + +```c++ +struct VoxelizerBackend: public FierroBackend { + ... + + /** + * Check that the arguments of the CLI are valid and make sense. + * + * Checks for explicit/implicit logical consistency. + * Checks that the mesh file is real and readable. + * Does not check that it is correctly formatted. + * + * @return An optional error. If the empty, the arguments are valid. + * + */ + std::optional validate_arguments() { + std::string msg = ""; + auto parser = this->command; + + // Here we just check if the input file is an actual file. + if (!file_exists(parser->get("input-file"))) { + msg = "Unable to find input file: " + parser->get("input-file"); + } + + if (msg.length() > 0) { + return std::optional(msg); + } + return {}; + } + ... +}; +``` + +Now you have a well defined backend. + + +#### 2. Plug it into the CLI framework +Head over to main.cpp and add your backend to the list of backends: +```c++ +std::vector> BACKENDS { + std::shared_ptr(), + std::shared_ptr(), + std::shared_ptr(), + std::shared_ptr(), + //std::shared_ptr() <-- Add yours here +}; + +``` + +Now you have everything set up, and it will automatically be picked up if its compiled and in the system. \ No newline at end of file diff --git a/src/CLI/src/main.cpp b/src/CLI/src/main.cpp index a09949015..70cce4ada 100644 --- a/src/CLI/src/main.cpp +++ b/src/CLI/src/main.cpp @@ -11,10 +11,10 @@ #include std::vector> BACKENDS { - std::shared_ptr(new ParallelExplicit()), - std::shared_ptr(new ParallelImplicit()), - std::shared_ptr(new MeshBuilderBackend()), - std::shared_ptr(new VoxelizerBackend()), + std::shared_ptr(), + std::shared_ptr(), + std::shared_ptr(), + std::shared_ptr(), }; std::vector> find_fierro_backends() {