Skip to content

Commit

Permalink
Pcse2: irrigation challenge (#1341)
Browse files Browse the repository at this point in the history
* irrigation_challenge

* flute

* fix

* Update __init__.py

* Update experiments.py

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix_gym

* fix_gym

* fix_gym

* fix

* fix
  • Loading branch information
teytaud committed Dec 9, 2022
1 parent 9bc4cfd commit 5569d69
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 2 deletions.
19 changes: 19 additions & 0 deletions nevergrad/benchmark/experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from nevergrad.functions.ac import NgAquacrop
from nevergrad.functions.stsp import STSP
from nevergrad.functions.rocket import Rocket
from nevergrad.functions.irrigation import Irrigation
from nevergrad.functions.pcse import CropSimulator
from nevergrad.functions.mixsimulator import OptimizeMix
from nevergrad.functions.unitcommitment import UnitCommitmentProblem
Expand Down Expand Up @@ -1276,6 +1277,24 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe


@registry.register
def irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]:
"""Irrigation simulator. Maximize leaf area index,
so that you get a lot of primary production.
Sequential or 30 workers."""
funcs = [Irrigation(i) for i in range(17)]
seedg = create_seed_generator(seed)
optims = get_optimizers("basics", seed=next(seedg))
for budget in [25, 50, 100, 200]:
for num_workers in [1, 30, 60]:
if num_workers < budget:
for algo in optims:
for fu in funcs:
xp = Experiment(fu, algo, budget, num_workers=num_workers, seed=next(seedg))
skip_ci(reason="Too slow")
if not xp.is_incoherent:
yield xp


def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]:
"""Crop simulator.
Expand Down
23 changes: 23 additions & 0 deletions nevergrad/functions/gym/test_multigym.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,17 @@ def test_multigym() -> None:
assert env_name in GYM_ENV_NAMES, f"{env_name} unknown!"
assert env_name not in multigym.NO_LENGTH, f"{env_name} in no length and in ng_gym!"
for env_name in multigym.GUARANTEED_GYM_ENV_NAMES:
if any(x in env_name for x in ["MemorizeDigit"]):
continue
assert env_name in GYM_ENV_NAMES, f"{env_name} should be guaranteed!"
assert len(GYM_ENV_NAMES) >= 10 or os.name == "nt"

#def test_compiler_gym() -> None:
# func = multigym.CompilerGym(17)
# candidate = func.parametrization.sample()
# results = [func.evaluation_function(candidate) for _ in range(4)]
# assert min(results) == max(results), "CompilerGym should be deterministic."


def test_cartpole() -> None:
func = multigym.GymMulti(name="CartPole-v0", control="neural", neural_factor=1, randomized=True)
Expand All @@ -46,17 +54,32 @@ def test_sparse_cartpole() -> None:
assert min(results) != max(results), "CartPole should not be deterministic."


<<<<<<< HEAD
@pytest.mark.parametrize("name", ["LunarLander-v2"]) # type: ignore
def test_run_multigym(name: str) -> None:
if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name:
=======
def test_default_run_multigym() -> None:
if os.name == "nt":
>>>>>>> 1691eaa4 (Pcse2: irrigation challenge (#1341))
raise SkipTest("Skipping Windows and running only 1 out of 8")
if "ANM" in name:
raise SkipTest("We skip ANM6Easy and related problems.")

func = multigym.GymMulti(randomized=False, neural_factor=None)
x = np.zeros(func.dimension)
value = func(x)
<<<<<<< HEAD
np.testing.assert_almost_equal(value, 178.2, decimal=2)
=======
np.testing.assert_almost_equal(value, 178.20, decimal=2)


@pytest.mark.parametrize("name", GYM_ENV_NAMES) # type: ignore
def test_run_multigym(name: str) -> None:
if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name:
raise SkipTest("Skipping Windows and running only 1 out of 8")
>>>>>>> 1691eaa4 (Pcse2: irrigation challenge (#1341))
i = GYM_ENV_NAMES.index(name)
control = multigym.CONTROLLERS[i % len(multigym.CONTROLLERS)]
print(f"Working with {control} on {name}.")
Expand Down
8 changes: 8 additions & 0 deletions nevergrad/functions/irrigation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

# Based on https://github.com/ajwdewit/pcse_notebooks
# (MIT License).
from .irrigation import Irrigation as Irrigation
Binary file not shown.
122 changes: 122 additions & 0 deletions nevergrad/functions/irrigation/irrigation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

"""
Approximate crop Simulation
Based on
https://raw.githubusercontent.com/purdue-orbital/pcse-simulation/master/Simulation2.py
"""


from pathlib import Path
import urllib.request
import numpy as np
import nevergrad as ng
from ..base import ArrayExperimentFunction

# pylint: disable=too-many-locals,too-many-statements


class Irrigation(ArrayExperimentFunction):
def __init__(self, symmetry: int) -> None:
import nevergrad as ng

param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8")
super().__init__(leaf_area_index, parametrization=param, symmetry=symmetry)


import numpy as np


def leaf_area_index(x: np.ndarray):
d0 = int(1.01 + 29.98 * x[0])
d1 = int(1.01 + 30.98 * x[1])
d2 = int(1.01 + 30.98 * x[2])
d3 = int(1.01 + 29.98 * x[3])
a0 = 15.0 * x[4] / (x[4] + x[5] + x[6] + x[7])
a1 = 15.0 * x[5] / (x[4] + x[5] + x[6] + x[7])
a2 = 15.0 * x[6] / (x[4] + x[5] + x[6] + x[7])
a3 = 15.0 * x[7] / (x[4] + x[5] + x[6] + x[7])
import os, sys

# import matplotlib
# matplotlib.style.use("ggplot")
# import matplotlib.pyplot as plt
import pandas as pd
import yaml

import pcse
from pcse.models import Wofost72_WLP_FD
from pcse.fileinput import CABOFileReader, YAMLCropDataProvider

# from pcse.db import NASAPowerWeatherDataProvider
from pcse.util import WOFOST72SiteDataProvider
from pcse.base import ParameterProvider

# data_dir = os.path.join(os.getcwd(), "data")
data_dir = Path(__file__).with_name("data")

print("This notebook was built with:")
print("python version: %s " % sys.version)
print("PCSE version: %s" % pcse.__version__)

crop = YAMLCropDataProvider()
if os.environ.get("CIRCLECI", False):
raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI")
urllib.request.urlretrieve(
"https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil",
str(data_dir) + "/soil/ec3.soil",
)
soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil"))
site = WOFOST72SiteDataProvider(WAV=100, CO2=360)
parameterprovider = ParameterProvider(soildata=soil, cropdata=crop, sitedata=site)

crop = YAMLCropDataProvider()

from pcse.fileinput import ExcelWeatherDataProvider

weatherfile = os.path.join(data_dir, "meteo", "nl1.xlsx")
weatherdataprovider = ExcelWeatherDataProvider(weatherfile)

yaml_agro = f"""
- 2006-01-01:
CropCalendar:
crop_name: sugarbeet
variety_name: Sugarbeet_603
crop_start_date: 2006-03-31
crop_start_type: emergence
crop_end_date: 2006-10-20
crop_end_type: harvest
max_duration: 300
TimedEvents:
- event_signal: irrigate
name: Irrigation application table
comment: All irrigation amounts in cm
events_table:
- 2006-06-{d0:02}: {{amount: {a0}, efficiency: 0.7}}
- 2006-07-{d1:02}: {{amount: {a1}, efficiency: 0.7}}
- 2006-08-{d2:02}: {{amount: {a2}, efficiency: 0.7}}
- 2006-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}}
StateEvents: null
"""
try:
agromanagement = yaml.safe_load(yaml_agro)
wofost = Wofost72_WLP_FD(parameterprovider, weatherdataprovider, agromanagement)
wofost.run_till_terminate()
except Exception as e:
assert False, f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n"
raise e

output = wofost.get_output()
df = pd.DataFrame(output).set_index("day")
df.tail()

# print(output)
# print(len(output))
return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None])
# fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16,8))
# df['LAI'].plot(ax=axes[0], title="Leaf Area Index")
# df['SM'].plot(ax=axes[1], title="Root zone soil moisture")
# fig.autofmt_xdate()
19 changes: 19 additions & 0 deletions nevergrad/functions/irrigation/test_irrigation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import numpy as np
from . import irrigation


def test_irrigation() -> None:
func = irrigation.Irrigation(2)
x = np.random.rand(func.dimension)
value = func(x)
value2 = func(x)
x = np.random.rand(func.dimension)
value3 = func(x)
assert value <= 0.0 # type: ignore
assert value3 != value # this should not be flat.
np.testing.assert_almost_equal(value, value2)
2 changes: 1 addition & 1 deletion nevergrad/functions/pcse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

# Based on https://github.com/ajwdewit/pcse_notebooks
# MIT License.
from .pcse import Pcse as Pcse
from .pcse import CropSimulator as CropSimulator
2 changes: 1 addition & 1 deletion nevergrad/functions/pcse/test_pcse.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


def test_pcse() -> None:
func = pcse.Pcse()
func = pcse.CropSimulator()
x = 0 * np.random.rand(func.dimension)
value = func(x)
value2 = func(x)
Expand Down
1 change: 1 addition & 0 deletions requirements/bench.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ box2d-py>=2.3.5
glfw
mujoco
pcse
pygame

0 comments on commit 5569d69

Please sign in to comment.