From ca4588bc756386fecfb10185ac9d39f72dc2e082 Mon Sep 17 00:00:00 2001 From: Mosayeb Shams Date: Thu, 4 May 2023 16:18:00 +0100 Subject: [PATCH] Revise for beta release --- CONTRIBUTING.md | 3 +- README.md | 13 +++--- closed_loop_AFC/jet_cylinder/environment.py | 23 ++++++++++- .../jet_cylinder/ppo_controller.py | 36 ++++++++++++----- .../rotating_cylinder/environment.py | 23 ++++++++++- .../rotating_cylinder/ppo_controller.py | 40 ++++++++++++++++--- .../perpendicular_flap/environment.py | 11 +++-- .../sinusoidal_controller.py | 7 +--- quickstart/environment.py | 23 ++++++++++- 9 files changed, 147 insertions(+), 32 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 29da823..1e304e0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,7 +49,8 @@ Please follow the [development installation instructions](#development-installat **Note:** You might have to run `pre-commit run --all-files` a few times since formatting tool formats the code initially and fails the first time. +**Note:** We do not check or enforce format/style/type/docstring for Python scripts that define controllers (e.g. `ppo_controller.py`) in our tutorials. ## License -By contributing to Gym-preCICE and its tutorials, you agree that your contributions will be licensed under the [Gym-preCICE LICENSE](https://github.com/gymprecice/gymprecice/blob/main/LICENSE). +By contributing to Gym-preCICE and its tutorials, you agree that your contributions will be licensed under [the LICENSE file](https://github.com/gymprecice/tutorials/blob/main/LICENSE) in the root directory of this source tree. diff --git a/README.md b/README.md index a4194b7..ea7a3fd 100644 --- a/README.md +++ b/README.md @@ -43,16 +43,17 @@ To make sure you can successfully run the tutorials, you need to install some ex Please check out the [Quickstart](https://github.com/gymprecice/gymprecice-tutorials/blob/master/quickstart/quickstart.ipynb) to follow running a control case step by step. - ## Citing Us If you use Gym-preCICE, please cite the following paper: + ``` -@misc{, - Author = {Mosayeb Shams, Ahmed H. Elsheikh}, - Title = {Gym-preCICE: Reinforcement Learning Environments for Active Flow Control}, - Year = {2023}, - Eprint = {arXiv:}, +@misc{shams2023gymprecice, + title={Gym-preCICE: Reinforcement Learning Environments for Active Flow Control}, + author={Mosayeb Shams and Ahmed H. Elsheikh}, + year={2023}, + eprint={2305.02033}, + archivePrefix={arXiv} } ``` diff --git a/closed_loop_AFC/jet_cylinder/environment.py b/closed_loop_AFC/jet_cylinder/environment.py index 50c98eb..32e7ca3 100644 --- a/closed_loop_AFC/jet_cylinder/environment.py +++ b/closed_loop_AFC/jet_cylinder/environment.py @@ -1,4 +1,25 @@ -"""AFC environment for jet cylinder control.""" +"""AFC environment for jet cylinder control. + +The mesh for our OpenFOAM case in `physics-simulation-engine/fluid-openfoam` is adapted from +[DRLinFluids](https://github.com/venturi123/DRLinFluids) under the following licence: + +Apache Software License 2.0 + +Copyright (c) 2022, Qiulei Wang + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + import logging import math from os.path import join diff --git a/closed_loop_AFC/jet_cylinder/ppo_controller.py b/closed_loop_AFC/jet_cylinder/ppo_controller.py index 349ba6d..62dc737 100644 --- a/closed_loop_AFC/jet_cylinder/ppo_controller.py +++ b/closed_loop_AFC/jet_cylinder/ppo_controller.py @@ -1,3 +1,29 @@ +""" +This code is adapted from [cleanrl](https://github.com/vwxyzjn/cleanrl) released under the following licence: + +MIT License + +Copyright (c) 2019 CleanRL developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + import argparse import logging import math @@ -89,7 +115,6 @@ def get_action_and_value(self, x, action=None): squashed_sample * self.action_scale + self.action_bias ) # we scale the sampled action - # TODO: this should be done only when action is not None squashed_action = ( 2.0 * (action - self.action_min) / (self.action_max - self.action_min) - 1.0 ) @@ -99,7 +124,6 @@ def get_action_and_value(self, x, action=None): gaussian_action = torch.atanh(squashed_action) log_prob = probs.log_prob(gaussian_action) - # log_prob -= torch.log(self.action_scale * (1 - squashed_action.pow(2)) + EPSILON) log_prob -= 2.0 * ( math.log(2.0) - gaussian_action @@ -108,7 +132,6 @@ def get_action_and_value(self, x, action=None): entropy = probs.entropy().sum(1) - # agent returns the mean action for CAP method return action, mean, log_prob.sum(1), entropy, self.critic(x) @@ -154,9 +177,6 @@ def step(self, action): "episode": self.episode_count, } self.wandb_context.log(metrics_dict, commit=True) - print( - f"DEBUG print, episode: {self.episode_count}, rewards : {episode_return / episode_length}" - ) self.episode_count += 1 self.episode_returns[i] = 0 @@ -249,7 +269,7 @@ def parse_args(): parser.add_argument( "--num-envs", type=int, - default=24, + default=2, help="the number of parallel game environments", ) parser.add_argument( @@ -368,8 +388,6 @@ def parse_args(): # TRY NOT TO MODIFY: seeding random.seed(args.seed) np.random.seed(args.seed) - torch.manual_seed(args.seed) - torch.backends.cudnn.deterministic = args.torch_deterministic def make_env(options, idx, wrappers=None): def _make_env(): diff --git a/closed_loop_AFC/rotating_cylinder/environment.py b/closed_loop_AFC/rotating_cylinder/environment.py index fc1a3fe..42c6be5 100644 --- a/closed_loop_AFC/rotating_cylinder/environment.py +++ b/closed_loop_AFC/rotating_cylinder/environment.py @@ -1,4 +1,25 @@ -"""AFC environment for rotating cylinder control.""" +"""AFC environment for rotating cylinder control. + +The mesh for our OpenFOAM case in `physics-simulation-engine/fluid-openfoam` is adapted from +[DRLinFluids](https://github.com/venturi123/DRLinFluids) under the following licence: + +Apache Software License 2.0 + +Copyright (c) 2022, Qiulei Wang + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + import logging import math from os.path import join diff --git a/closed_loop_AFC/rotating_cylinder/ppo_controller.py b/closed_loop_AFC/rotating_cylinder/ppo_controller.py index 2f6692d..5ef00e0 100644 --- a/closed_loop_AFC/rotating_cylinder/ppo_controller.py +++ b/closed_loop_AFC/rotating_cylinder/ppo_controller.py @@ -1,6 +1,33 @@ +""" +This code is adapted from [cleanrl](https://github.com/vwxyzjn/cleanrl) released under the following licence: + +MIT License + +Copyright (c) 2019 CleanRL developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + import argparse import logging import math +import random import time from distutils.util import strtobool from typing import Optional @@ -154,9 +181,6 @@ def step(self, action): "episode": self.episode_count, } self.wandb_context.log(metrics_dict, commit=True) - print( - f"DEBUG print, episode: {self.episode_count}, rewards : {episode_return / episode_length}" - ) self.episode_count += 1 self.episode_returns[i] = 0 @@ -179,7 +203,9 @@ def close(self): def parse_args(): # Training specific arguments parser = argparse.ArgumentParser() - parser.add_argument("--seed", type=int, default=1, help="seed of the experiment") + parser.add_argument( + "--seed", type=int, default=12345, help="seed of the experiment" + ) parser.add_argument( "--torch-deterministic", type=lambda x: bool(strtobool(x)), @@ -248,7 +274,7 @@ def parse_args(): parser.add_argument( "--num-envs", type=int, - default=24, + default=2, help="the number of parallel game environments", ) parser.add_argument( @@ -364,6 +390,10 @@ def parse_args(): logger.error("wandb is not installed, run `pip install gymprecice[vis]`") raise err + # TRY NOT TO MODIFY: seeding + random.seed(args.seed) + np.random.seed(args.seed) + def make_env(options, idx, wrappers=None): def _make_env(): env = RotatingCylinder2DEnv(options, idx) diff --git a/open_loop_AFC/perpendicular_flap/environment.py b/open_loop_AFC/perpendicular_flap/environment.py index c48c2fa..ab3a294 100644 --- a/open_loop_AFC/perpendicular_flap/environment.py +++ b/open_loop_AFC/perpendicular_flap/environment.py @@ -1,4 +1,11 @@ -"""AFC environment for perpendicular-flap control.""" +"""AFC environment for perpendicular-flap control. + +The physics-simulation-engine used for this environment is a fluid-structure interaction model adapted +from ["preCICE tutorials"](https://github.com/precice/tutorials/tree/master/perpendicular-flap) under the following licence: + +[GNU LESSER GENERAL PUBLIC LICENSE](https://github.com/precice/tutorials/blob/master/LICENSE) +""" + import logging import math from os.path import join @@ -25,8 +32,6 @@ class PerpendicularFlapEnv(Adapter): from different simulation software packages). We control centre position of an inflow jet to manipulate the motion of a wall-mounted elastic flap in a two-dimensional channel flow. The goal is to keep the elastic flap oscillating within the channel flow. - This physics-simulation-engine used for this environment is a fluid-structure interaction model adapted - from ["preCICE tutorials"](https://github.com/precice/tutorials/tree/master/perpendicular-flap). ## Action Space The action is a `ndarray` with shape `(1,)` with the value corresponding to the centre position of the inflow jet. diff --git a/open_loop_AFC/perpendicular_flap/sinusoidal_controller.py b/open_loop_AFC/perpendicular_flap/sinusoidal_controller.py index 57a47e0..a320b50 100644 --- a/open_loop_AFC/perpendicular_flap/sinusoidal_controller.py +++ b/open_loop_AFC/perpendicular_flap/sinusoidal_controller.py @@ -40,11 +40,8 @@ def act(self): _, _ = env.reset() print("\n...") - print("The control case is running!") - print( - "This task is expected to be completed in about 5 minutes on a system with two cores @ 2.10GHz." - ) - print("...\n") + print("The sinusoidal control case is running!") + print("Please wait ...\n") # step through the environment and control it for one complete episode (8 seconds, 320 steps) while not terminated: diff --git a/quickstart/environment.py b/quickstart/environment.py index 50c98eb..32e7ca3 100644 --- a/quickstart/environment.py +++ b/quickstart/environment.py @@ -1,4 +1,25 @@ -"""AFC environment for jet cylinder control.""" +"""AFC environment for jet cylinder control. + +The mesh for our OpenFOAM case in `physics-simulation-engine/fluid-openfoam` is adapted from +[DRLinFluids](https://github.com/venturi123/DRLinFluids) under the following licence: + +Apache Software License 2.0 + +Copyright (c) 2022, Qiulei Wang + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + import logging import math from os.path import join