From 8f00946d55cc906b9df4cb502a5e652ca2858313 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 12 Jun 2022 23:47:52 -0400 Subject: [PATCH 1/8] add minimize Conflicts: dpdata/driver.py dpdata/system.py --- dpdata/driver.py | 31 ++++++++++++++++++++++++++ dpdata/plugins/amber.py | 6 +++++ dpdata/system.py | 49 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/dpdata/driver.py b/dpdata/driver.py index 97583a101..7ace037e2 100644 --- a/dpdata/driver.py +++ b/dpdata/driver.py @@ -3,6 +3,8 @@ from .plugin import Plugin from abc import ABC, abstractmethod +import dpdata + if TYPE_CHECKING: import ase @@ -81,6 +83,35 @@ def label(self, data: dict) -> dict: """ return NotImplemented + def minimize(self, data: dict) -> dict: + """Minimize the geometry. + + If not implemented, this method calls ASE to minimize. + + Parameters + ---------- + data : dict + data with coordinates and atom types + + Returns + ------- + dict + labeled data with minimized coordinates, energies, and forces + """ + from ase.optimize import BFGS + + system = dpdata.System(data=data) + # list[Atoms] + structures = system.to_ase_structure() + labeled_system = dpdata.LabeledSystem() + for atoms in structures: + atoms.calc = self.ase_calculator + dyn = BFGS(atoms) + dyn.run(fmax=5e-3) + ls = dpdata.LabeledSystem(atoms, fmt="ase/structure") + labeled_system.append(ls) + return labeled_system.data + @property def ase_calculator(self) -> "ase.calculators.calculator.Calculator": """Returns an ase calculator based on this driver.""" diff --git a/dpdata/plugins/amber.py b/dpdata/plugins/amber.py index d2a13c5bf..4974329aa 100644 --- a/dpdata/plugins/amber.py +++ b/dpdata/plugins/amber.py @@ -121,3 +121,9 @@ def label(self, data: dict) -> dict: ) from e labeled_system.append(dpdata.LabeledSystem(out_fn, fmt="sqm/out")) return labeled_system.data + + def minimize(self, data: dict) -> dict: + # sqm has minimize feature + if self.kwargs['maxcyc'] <= 0: + raise RuntimeError("To minimize, maxcyc should be more than 0") + return self.label(data) diff --git a/dpdata/system.py b/dpdata/system.py index 12f839e86..d433b9cf1 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -6,7 +6,7 @@ import dpdata.md.pbc from copy import deepcopy from enum import Enum, unique -from typing import Any, Tuple +from typing import Any, Tuple, Union from monty.json import MSONable from monty.serialization import loadfn,dumpfn from dpdata.periodic_table import Element @@ -830,6 +830,28 @@ def predict(self, *args: Any, driver: str="dp", **kwargs: Any) -> "LabeledSystem data = driver.label(self.data.copy()) return LabeledSystem(data=data) + def minimize(self, *args: Any, driver: Union[str, Driver], **kwargs: Any) -> "LabeledSystem": + """Minimize the geometry. + + Parameters + ---------- + *args : iterable + Arguments passing to the driver + driver : str or Driver + The assigned driver + **kwargs : dict + Other arguments passing to the driver + + Returns + ------- + labeled_sys : LabeledSystem + A new labeled system. + """ + if not isinstance(driver, Driver): + driver = Driver.get_driver(driver)(*args, **kwargs) + data = driver.minimize(self.data.copy()) + return LabeledSystem(data=data) + def pick_atom_idx(self, idx, nopbc=None): """Pick atom index @@ -1273,6 +1295,31 @@ def predict(self, *args: Any, driver="dp", **kwargs: Any) -> "MultiSystems": for ss in self: new_multisystems.append(ss.predict(*args, driver=driver, **kwargs)) return new_multisystems + + def minimize(self, *args: Any, driver: Union[str, Driver], **kwargs: Any) -> "MultiSystems": + """ + Minimize geometry by a driver. + + Parameters + ---------- + *args : iterable + Arguments passing to the driver + driver : str or Driver + The assigned driver + **kwargs : dict + Other arguments passing to the driver + + Returns + ------- + MultiSystems + A new labeled MultiSystems. + """ + if not isinstance(driver, Driver): + driver = Driver.get_driver(driver)(*args, **kwargs) + new_multisystems = dpdata.MultiSystems() + for ss in self: + new_multisystems.append(ss.minimize(*args, driver=driver, **kwargs)) + return new_multisystems def pick_atom_idx(self, idx, nopbc=None): """Pick atom index From c7e79ad979cfb8a2a603fdbb2ac591825685f303 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 13 Jun 2022 00:07:23 -0400 Subject: [PATCH 2/8] add tests --- dpdata/driver.py | 6 +++--- tests/test_predict.py | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/dpdata/driver.py b/dpdata/driver.py index 7ace037e2..93c9f45f4 100644 --- a/dpdata/driver.py +++ b/dpdata/driver.py @@ -98,7 +98,7 @@ def minimize(self, data: dict) -> dict: dict labeled data with minimized coordinates, energies, and forces """ - from ase.optimize import BFGS + from ase.optimize import LBFGS system = dpdata.System(data=data) # list[Atoms] @@ -106,9 +106,9 @@ def minimize(self, data: dict) -> dict: labeled_system = dpdata.LabeledSystem() for atoms in structures: atoms.calc = self.ase_calculator - dyn = BFGS(atoms) + dyn = LBFGS(atoms, logfile=None) dyn.run(fmax=5e-3) - ls = dpdata.LabeledSystem(atoms, fmt="ase/structure") + ls = dpdata.LabeledSystem(atoms, fmt="ase/structure", type_map=data['atom_names']) labeled_system.append(ls) return labeled_system.data diff --git a/tests/test_predict.py b/tests/test_predict.py index 8535d02ea..369da4d9e 100644 --- a/tests/test_predict.py +++ b/tests/test_predict.py @@ -78,7 +78,7 @@ def setUp(self) : @unittest.skipIf(skip_ase,"skip ase related test. install ase to fix") -class TestASEtraj1(unittest.TestCase, CompLabeledSys, IsPBC): +class TestASEDriver(unittest.TestCase, CompLabeledSys, IsPBC): def setUp (self) : ori_sys = dpdata.LabeledSystem('poscars/deepmd.h2o.md', fmt = 'deepmd/raw', @@ -90,3 +90,17 @@ def setUp (self) : self.e_places = 6 self.f_places = 6 self.v_places = 4 + + +@unittest.skipIf(skip_ase,"skip ase related test. install ase to fix") +class TestMinimize(unittest.TestCase, CompLabeledSys, IsPBC): + def setUp (self) : + ori_sys = dpdata.LabeledSystem('poscars/deepmd.h2o.md', + fmt = 'deepmd/raw', + type_map = ['O', 'H']) + self.system_1 = ori_sys.predict(driver="zero") + self.system_2 = ori_sys.minimize(driver="zero") + self.places = 6 + self.e_places = 6 + self.f_places = 6 + self.v_places = 4 From ae710a1f78cecc7abdebaa5d2d1a5c5359b697ef Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 13 Jun 2022 00:12:55 -0400 Subject: [PATCH 3/8] test multi systems --- tests/test_predict.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/test_predict.py b/tests/test_predict.py index 369da4d9e..76c29c00c 100644 --- a/tests/test_predict.py +++ b/tests/test_predict.py @@ -92,7 +92,7 @@ def setUp (self) : self.v_places = 4 -@unittest.skipIf(skip_ase,"skip ase related test. install ase to fix") +@unittest.skipIf(skip_ase, "skip ase related test. install ase to fix") class TestMinimize(unittest.TestCase, CompLabeledSys, IsPBC): def setUp (self) : ori_sys = dpdata.LabeledSystem('poscars/deepmd.h2o.md', @@ -104,3 +104,18 @@ def setUp (self) : self.e_places = 6 self.f_places = 6 self.v_places = 4 + + +@unittest.skipIf(skip_ase, "skip ase related test. install ase to fix") +class TestMinimizeMultiSystems(unittest.TestCase, CompLabeledSys, IsPBC): + def setUp (self) : + ori_sys = dpdata.LabeledSystem('poscars/deepmd.h2o.md', + fmt = 'deepmd/raw', + type_map = ['O', 'H']) + multi_sys = dpdata.MultiSystems(ori_sys) + self.system_1 = list(multi_sys.predict(driver="zero").systems.values())[0] + self.system_2 = list(multi_sys.minimize(driver="zero").systems.values())[0] + self.places = 6 + self.e_places = 6 + self.f_places = 6 + self.v_places = 4 From b55113535473d64c441ab7aef6f16edc2c848903 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 13 Jun 2022 19:00:21 -0400 Subject: [PATCH 4/8] assign the same type_map --- dpdata/system.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dpdata/system.py b/dpdata/system.py index d433b9cf1..ad34c4294 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -1291,7 +1291,7 @@ def predict(self, *args: Any, driver="dp", **kwargs: Any) -> "MultiSystems": """ if not isinstance(driver, Driver): driver = Driver.get_driver(driver)(*args, **kwargs) - new_multisystems = dpdata.MultiSystems() + new_multisystems = dpdata.MultiSystems(type_map=self.atom_names) for ss in self: new_multisystems.append(ss.predict(*args, driver=driver, **kwargs)) return new_multisystems @@ -1316,7 +1316,7 @@ def minimize(self, *args: Any, driver: Union[str, Driver], **kwargs: Any) -> "Mu """ if not isinstance(driver, Driver): driver = Driver.get_driver(driver)(*args, **kwargs) - new_multisystems = dpdata.MultiSystems() + new_multisystems = dpdata.MultiSystems(type_map=self.atom_names) for ss in self: new_multisystems.append(ss.minimize(*args, driver=driver, **kwargs)) return new_multisystems From 6ebe5d4820dda764461d365ecb6eb7f135084a1c Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 27 Sep 2022 17:11:00 -0400 Subject: [PATCH 5/8] refactor --- dpdata/dftbplus/__init__.py | 0 dpdata/dftbplus/out.py | 0 dpdata/driver.py | 100 +++++++++++++++++++++++++----------- dpdata/plugins/amber.py | 20 ++++++-- dpdata/plugins/ase.py | 63 ++++++++++++++++++++++- dpdata/system.py | 36 ++++++------- tests/test_predict.py | 10 ++-- 7 files changed, 173 insertions(+), 56 deletions(-) create mode 100644 dpdata/dftbplus/__init__.py create mode 100644 dpdata/dftbplus/out.py diff --git a/dpdata/dftbplus/__init__.py b/dpdata/dftbplus/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/dpdata/dftbplus/out.py b/dpdata/dftbplus/out.py new file mode 100644 index 000000000..e69de29bb diff --git a/dpdata/driver.py b/dpdata/driver.py index 93c9f45f4..d2fda3a16 100644 --- a/dpdata/driver.py +++ b/dpdata/driver.py @@ -83,35 +83,6 @@ def label(self, data: dict) -> dict: """ return NotImplemented - def minimize(self, data: dict) -> dict: - """Minimize the geometry. - - If not implemented, this method calls ASE to minimize. - - Parameters - ---------- - data : dict - data with coordinates and atom types - - Returns - ------- - dict - labeled data with minimized coordinates, energies, and forces - """ - from ase.optimize import LBFGS - - system = dpdata.System(data=data) - # list[Atoms] - structures = system.to_ase_structure() - labeled_system = dpdata.LabeledSystem() - for atoms in structures: - atoms.calc = self.ase_calculator - dyn = LBFGS(atoms, logfile=None) - dyn.run(fmax=5e-3) - ls = dpdata.LabeledSystem(atoms, fmt="ase/structure", type_map=data['atom_names']) - labeled_system.append(ls) - return labeled_system.data - @property def ase_calculator(self) -> "ase.calculators.calculator.Calculator": """Returns an ase calculator based on this driver.""" @@ -178,3 +149,74 @@ def label(self, data: dict) -> dict: labeled_data['energies'] += lb_data ['energies'] labeled_data['forces'] += lb_data ['forces'] return labeled_data + + +class Minimizer(ABC): + """The base class for a minimizer plugin. A minimizer can + minimize geometry. + """ + __MinimizerPlugin = Plugin() + + @staticmethod + def register(key: str) -> Callable: + """Register a minimizer plugin. Used as decorators. + + Parameter + --------- + key: str + key of the plugin. + + Returns + ------- + Callable + decorator of a class + + Examples + -------- + >>> @Minimizer.register("some_minimizer") + ... class SomeMinimizer(Minimizer): + ... pass + """ + return Minimizer.__MinimizerPlugin.register(key) + + @staticmethod + def get_minimizer(key: str) -> "Minimizer": + """Get a minimizer plugin. + + Parameter + --------- + key: str + key of the plugin. + + Returns + ------- + Minimizer + the specific minimizer class + + Raises + ------ + RuntimeError + if the requested minimizer is not implemented + """ + try: + return Minimizer.__MinimizerPlugin.plugins[key] + except KeyError as e: + raise RuntimeError('Unknown minimizer: ' + key) from e + + def __init__(self, *args, **kwargs) -> None: + """Setup the minimizer.""" + + @abstractmethod + def minimize(self, data: dict) -> dict: + """Minimize the geometry. + + Parameters + ---------- + data : dict + data with coordinates and atom types + + Returns + ------- + dict + labeled data with minimized coordinates, energies, and forces + """ diff --git a/dpdata/plugins/amber.py b/dpdata/plugins/amber.py index 0db8222ae..4fe41c1e4 100644 --- a/dpdata/plugins/amber.py +++ b/dpdata/plugins/amber.py @@ -5,7 +5,7 @@ import dpdata.amber.md import dpdata.amber.sqm from dpdata.format import Format -from dpdata.driver import Driver +from dpdata.driver import Driver, Minimizer @Format.register("amber/md") @@ -122,9 +122,21 @@ def label(self, data: dict) -> dict: ) from e labeled_system.append(dpdata.LabeledSystem(out_fn, fmt="sqm/out")) return labeled_system.data + + +@Minimizer.register("sqm") +class SQMMinimizer(Minimizer): + """SQM minimizer. + Parameters + ---------- + maxcyc : int, default=1000 + maximun cycle to minimize + """ + def __init__(self, maxcyc=1000, *args, **kwargs) -> None: + assert maxcyc > 0, "maxcyc should be more than 0 to minimize" + self.driver = SQMDriver(maxcyc=maxcyc, **kwargs) + def minimize(self, data: dict) -> dict: # sqm has minimize feature - if self.kwargs['maxcyc'] <= 0: - raise RuntimeError("To minimize, maxcyc should be more than 0") - return self.label(data) + return self.driver.label(data) diff --git a/dpdata/plugins/ase.py b/dpdata/plugins/ase.py index 61bc14dc1..f61d46f6c 100644 --- a/dpdata/plugins/ase.py +++ b/dpdata/plugins/ase.py @@ -1,10 +1,13 @@ -from dpdata.driver import Driver +from typing import TYPE_CHECKING, Type +from dpdata.driver import Driver, Minimizer from dpdata.format import Format import numpy as np import dpdata try: import ase.io from ase.calculators.calculator import PropertyNotImplementedError + if TYPE_CHECKING: + from ase.optimize.optimize import Optimizer except ImportError: pass @@ -204,3 +207,61 @@ def label(self, data: dict) -> dict: ls = dpdata.LabeledSystem(atoms, fmt="ase/structure", type_map=data['atom_names']) labeled_system.append(ls) return labeled_system.data + + +@Minimizer.register("ase") +class ASEMinimizer(Minimizer): + """ASE minimizer. + + Parameters + ---------- + driver : Driver + dpdata driver + optimizer : type, optional + ase optimizer class + fmax : float, optional, default=5e-3 + force convergence criterion + optimizer_kwargs : dict, optional + other parameters for optimizer + """ + def __init__(self, + driver: Driver, + optimizer: Type["Optimizer"] = None, + fmax: float = 5e-3, + optimizer_kwargs: dict = {}) -> None: + self.calculator = driver.ase_calculator + if optimizer is None: + from ase.optimize import LBFGS + self.optimizer = LBFGS + else: + self.optimizer = optimizer + self.optimizer_kwargs = { + "logfile": None, + **optimizer_kwargs.copy(), + } + self.fmax = fmax + + def minimize(self, data: dict) -> dict: + """Minimize the geometry. + + Parameters + ---------- + data : dict + data with coordinates and atom types + + Returns + ------- + dict + labeled data with minimized coordinates, energies, and forces + """ + system = dpdata.System(data=data) + # list[Atoms] + structures = system.to_ase_structure() + labeled_system = dpdata.LabeledSystem() + for atoms in structures: + atoms.calc = self.calculator + dyn = self.optimizer(atoms, **self.optimizer_kwargs) + dyn.run(fmax=self.fmax) + ls = dpdata.LabeledSystem(atoms, fmt="ase/structure", type_map=data['atom_names']) + labeled_system.append(ls) + return labeled_system.data \ No newline at end of file diff --git a/dpdata/system.py b/dpdata/system.py index 791d1595b..1717e56da 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -17,7 +17,7 @@ import dpdata.plugins from dpdata.plugin import Plugin from dpdata.format import Format -from dpdata.driver import Driver +from dpdata.driver import Driver, Minimizer from dpdata.utils import ( elements_index_map, @@ -869,26 +869,26 @@ def predict(self, *args: Any, driver: str="dp", **kwargs: Any) -> "LabeledSystem data = driver.label(self.data.copy()) return LabeledSystem(data=data) - def minimize(self, *args: Any, driver: Union[str, Driver], **kwargs: Any) -> "LabeledSystem": + def minimize(self, *args: Any, minimizer: Union[str, Minimizer], **kwargs: Any) -> "LabeledSystem": """Minimize the geometry. Parameters ---------- *args : iterable - Arguments passing to the driver - driver : str or Driver - The assigned driver + Arguments passing to the minimizer + minimizer : str or Minimizer + The assigned minimizer **kwargs : dict - Other arguments passing to the driver + Other arguments passing to the minimizer Returns ------- labeled_sys : LabeledSystem A new labeled system. """ - if not isinstance(driver, Driver): - driver = Driver.get_driver(driver)(*args, **kwargs) - data = driver.minimize(self.data.copy()) + if not isinstance(minimizer, Minimizer): + minimizer = Minimizer.get_minimizer(minimizer)(*args, **kwargs) + data = minimizer.minimize(self.data.copy()) return LabeledSystem(data=data) def pick_atom_idx(self, idx, nopbc=None): @@ -1335,29 +1335,29 @@ def predict(self, *args: Any, driver="dp", **kwargs: Any) -> "MultiSystems": new_multisystems.append(ss.predict(*args, driver=driver, **kwargs)) return new_multisystems - def minimize(self, *args: Any, driver: Union[str, Driver], **kwargs: Any) -> "MultiSystems": + def minimize(self, *args: Any, minimizer: Union[str, Minimizer], **kwargs: Any) -> "MultiSystems": """ - Minimize geometry by a driver. + Minimize geometry by a minimizer. Parameters ---------- *args : iterable - Arguments passing to the driver - driver : str or Driver - The assigned driver + Arguments passing to the minimizer + minimizer : str or Minimizer + The assigned minimizer **kwargs : dict - Other arguments passing to the driver + Other arguments passing to the minimizer Returns ------- MultiSystems A new labeled MultiSystems. """ - if not isinstance(driver, Driver): - driver = Driver.get_driver(driver)(*args, **kwargs) + if not isinstance(minimizer, Minimizer): + minimizer = Minimizer.get_minimizer(minimizer)(*args, **kwargs) new_multisystems = dpdata.MultiSystems(type_map=self.atom_names) for ss in self: - new_multisystems.append(ss.minimize(*args, driver=driver, **kwargs)) + new_multisystems.append(ss.minimize(*args, minimizer=minimizer, **kwargs)) return new_multisystems def pick_atom_idx(self, idx, nopbc=None): diff --git a/tests/test_predict.py b/tests/test_predict.py index 76c29c00c..3ba62ec23 100644 --- a/tests/test_predict.py +++ b/tests/test_predict.py @@ -98,8 +98,9 @@ def setUp (self) : ori_sys = dpdata.LabeledSystem('poscars/deepmd.h2o.md', fmt = 'deepmd/raw', type_map = ['O', 'H']) - self.system_1 = ori_sys.predict(driver="zero") - self.system_2 = ori_sys.minimize(driver="zero") + zero_driver = ZeroDriver() + self.system_1 = ori_sys.predict(driver=zero_driver) + self.system_2 = ori_sys.minimize(driver=zero_driver, minimizer="ase") self.places = 6 self.e_places = 6 self.f_places = 6 @@ -113,8 +114,9 @@ def setUp (self) : fmt = 'deepmd/raw', type_map = ['O', 'H']) multi_sys = dpdata.MultiSystems(ori_sys) - self.system_1 = list(multi_sys.predict(driver="zero").systems.values())[0] - self.system_2 = list(multi_sys.minimize(driver="zero").systems.values())[0] + zero_driver = ZeroDriver() + self.system_1 = list(multi_sys.predict(driver=zero_driver).systems.values())[0] + self.system_2 = list(multi_sys.minimize(driver=zero_driver, minimizer="ase").systems.values())[0] self.places = 6 self.e_places = 6 self.f_places = 6 From e3cb470822a6c9c5b912cd69a10bb09775d739c1 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 27 Sep 2022 17:12:14 -0400 Subject: [PATCH 6/8] typo --- dpdata/dftbplus/__init__.py | 0 dpdata/dftbplus/out.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 dpdata/dftbplus/__init__.py delete mode 100644 dpdata/dftbplus/out.py diff --git a/dpdata/dftbplus/__init__.py b/dpdata/dftbplus/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/dpdata/dftbplus/out.py b/dpdata/dftbplus/out.py deleted file mode 100644 index e69de29bb..000000000 From ebd8b3d81cdd39e6c608799c20eddd0a7f02a0a1 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 27 Sep 2022 17:14:19 -0400 Subject: [PATCH 7/8] remove unused variable --- dpdata/driver.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/dpdata/driver.py b/dpdata/driver.py index d2fda3a16..670b03378 100644 --- a/dpdata/driver.py +++ b/dpdata/driver.py @@ -3,8 +3,6 @@ from .plugin import Plugin from abc import ABC, abstractmethod -import dpdata - if TYPE_CHECKING: import ase From 4a42454c1c0bacea2969140fd0593e211645d80e Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 28 Sep 2022 15:39:21 -0400 Subject: [PATCH 8/8] add examples to minimize --- dpdata/system.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dpdata/system.py b/dpdata/system.py index 1717e56da..a2226d030 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -1352,6 +1352,14 @@ def minimize(self, *args: Any, minimizer: Union[str, Minimizer], **kwargs: Any) ------- MultiSystems A new labeled MultiSystems. + + Examples + -------- + Minimize a system using ASE BFGS along with a DP driver: + >>> from dpdata.driver import Driver + >>> from ase.optimize import BFGS + >>> driver = driver.get_driver("dp")("some_model.pb") + >>> some_system.minimize(minimizer="ase", driver=driver, optimizer=BFGS, fmax=1e-5) """ if not isinstance(minimizer, Minimizer): minimizer = Minimizer.get_minimizer(minimizer)(*args, **kwargs)