Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added an image definition and a workflow to publish the image #1143

Merged
merged 3 commits into from
Feb 24, 2025
Merged
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
64 changes: 64 additions & 0 deletions .github/workflows/publish-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Publish Image

on:
release:
types: [published]

# Run the workflow manually from the Actions tab
workflow_dispatch:

env:
# Will use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}

jobs:
build:

runs-on: ubuntu-latest
permissions:
contents: read
packages: write

defaults:
run:
shell: bash -l {0}

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-tags: true

- name: Get tags
run: |
git fetch --unshallow --tags
git describe --tags > tag.txt
echo "TAG=$(cat tag.txt)" >> $GITHUB_ENV

# Login against the registry
- name: Log into registry ${{ env.REGISTRY }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# Extract metadata (tags, labels)
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ env.TAG }}

# Build and push image with Buildx
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
push: true
context: ${{ inputs.image_name }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
70 changes: 70 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Define image with OpenMDAO and Dymos

FROM ubuntu:24.04

SHELL ["/bin/bash", "-c"]

# Install updates
RUN apt-get update -y && apt-get -y install wget git g++ gfortran make libblas-dev liblapack-dev

RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb ;\
apt-get install -y ./google-chrome-stable_current_amd64.deb

# Create user
ENV USER=omdao
RUN adduser --shell /bin/bash --disabled-password ${USER}
RUN adduser ${USER} sudo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

USER ${USER}
WORKDIR /home/${USER}

# Install Miniforge
RUN wget -q -O Miniforge3.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh" ;\
bash Miniforge3.sh -b ;\
rm Miniforge3.sh ;\
export PATH=$HOME/miniforge3/bin:$PATH ;\
conda init bash

# Create conda environment
RUN source $HOME/miniforge3/etc/profile.d/conda.sh ;\
#
# Create conda environment
#
conda create -n mdaowork python=3.12 'numpy<2' scipy cython swig -y ;\
conda activate mdaowork ;\
conda install matplotlib graphviz -y ;\
conda install mpi4py petsc4py=3.20 -y ;\
python -m pip install pyparsing psutil objgraph plotly pyxdsm pydot ;\
#
# Install pyoptsparse
#
python -m pip install git+https://github.com/openmdao/build_pyoptsparse ;\
build_pyoptsparse -v ;\
#
# Install OpenMDAO
#
git clone https://github.com/OpenMDAO/OpenMDAO.git ;\
python -m pip install -e 'OpenMDAO[all]' ;\
#
# Install Dymos
#
git clone https://github.com/OpenMDAO/dymos.git ;\
python -m pip install -e 'dymos[all]'

# Modify .bashrc
RUN echo "## Always activate mdaowork environment on startup ##" >> ~/.bashrc ;\
echo "conda activate mdaowork" >> ~/.bashrc ;\
echo "" >> ~/.bashrc ;\
echo "## OpenMPI settings" >> ~/.bashrc ;\
echo "export OMPI_MCA_rmaps_base_oversubscribe=1" >> ~/.bashrc ;\
echo "export OMPI_MCA_btl=^openib" >> ~/.bashrc ;\
echo "" >> ~/.bashrc ;\
echo "## Required for some newer MPI / libfabric instances" >> ~/.bashrc ;\
echo "export RDMAV_FORK_SAFE=true" >> ~/.bashrc ;\
echo "" >> ~/.bashrc

# Set up a work directory that can be shared with the host operating system
WORKDIR /home/${USER}/work

ENTRYPOINT ["tail", "-f", "/dev/null"]
46 changes: 6 additions & 40 deletions dymos/phase/test/test_add_boundary_constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,12 @@
from dymos.utils.misc import om_version

import dymos as dm


class BrachistochroneVectorStatesODE(om.ExplicitComponent):
def initialize(self):
self.options.declare('num_nodes', types=int)

def setup(self):
nn = self.options['num_nodes']

self.add_input('v', val=np.zeros(nn), desc='velocity', units='m/s')
self.add_input('g', val=9.80665 * np.ones(nn), desc='grav. acceleration', units='m/s/s')
self.add_input('theta', val=np.zeros(nn), desc='angle of wire', units='rad')

self.add_output('pos_dot', val=np.zeros((nn, 2)), desc='velocity components', units='m/s')
self.add_output('vdot', val=np.zeros(nn), desc='acceleration magnitude', units='m/s**2')
self.add_output('check', val=np.zeros(nn), desc='check solution: v/sin(theta) = constant', units='m/s')

# Setup partials
arange = np.arange(self.options['num_nodes'])

self.declare_partials(of='vdot', wrt='g', rows=arange, cols=arange)
self.declare_partials(of='vdot', wrt='theta', rows=arange, cols=arange)

self.declare_coloring(wrt='*', method='cs', show_sparsity=False)

def compute(self, inputs, outputs):
theta = inputs['theta']
cos_theta = np.cos(theta)
sin_theta = np.sin(theta)
g = inputs['g']
v = inputs['v']

outputs['vdot'] = g * cos_theta
outputs['pos_dot'][:, 0] = v * sin_theta
outputs['pos_dot'][:, 1] = -v * cos_theta

outputs['check'] = v / sin_theta
from dymos.examples.brachistochrone.brachistochrone_vector_states_ode import BrachistochroneVectorStatesODE


@use_tempdirs
class TestAddBoundaryConstraint(unittest.TestCase):

@unittest.skipIf(om_version()[0] >= (3, 36, 1) and om_version()[0] < (3, 37, 0),
reason='Test is broken in OpenMDAO 3.37.0 interim development.')
@require_pyoptsparse(optimizer='SLSQP')
def test_simple_no_exception(self):
p = om.Problem(model=om.Group())
Expand Down Expand Up @@ -91,7 +53,7 @@ def test_simple_no_exception(self):
continuity=True, rate_continuity=True,
units='deg', lower=0.01, upper=179.9)

phase.add_parameter('g', units='m/s**2', val=9.80665, opt=False)
phase.add_parameter('g', units='m/s**2', val=9, opt=False)

# Minimize time at the end of the phase
phase.add_objective('time', loc='final', scaler=10)
Expand Down Expand Up @@ -251,3 +213,7 @@ def test_duplicate_constraint(self):

expected = 'Cannot add new final boundary constraint for variable `pos` and indices None. One already exists.'
self.assertEqual(expected, str(e.exception))


if __name__ == '__main__':
unittest.main()
Loading