From 6257511a4a639d6f893691ade6536722eb3bd3a7 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Thu, 16 Oct 2025 11:51:43 +0200 Subject: [PATCH 1/3] initial version of the documentation --- docs/src/fitting/introduction.rst | 321 +++++++++++++++++++++ docs/src/getting-started/installation.rst | 9 +- docs/src/getting-started/overview.rst | 219 +++++++++++++++ docs/src/index.rst | 161 +++++++++-- docs/src/reference/base.rst | 323 ++++++++++++++++++++-- 5 files changed, 979 insertions(+), 54 deletions(-) diff --git a/docs/src/fitting/introduction.rst b/docs/src/fitting/introduction.rst index 72c572ac..3f019a99 100644 --- a/docs/src/fitting/introduction.rst +++ b/docs/src/fitting/introduction.rst @@ -2,3 +2,324 @@ Fitting in EasyScience ====================== +EasyScience provides a flexible and powerful fitting framework that supports multiple optimization backends. +This guide covers both basic usage for users wanting to fit their data, and advanced patterns for developers building scientific components. + +Overview +-------- + +The EasyScience fitting system consists of: + +* **Parameters**: Scientific values with units, bounds, and fitting capabilities +* **Models**: Objects containing parameters, inheriting from ``ObjBase`` +* **Fitter**: The main fitting engine supporting multiple minimizers +* **Minimizers**: Backend optimization engines (LMFit, Bumps, DFO-LS) + +Quick Start +----------- + +Basic Parameter and Model Setup +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + import numpy as np + from easyscience import ObjBase, Parameter, Fitter + + # Create a simple model with fittable parameters + class SineModel(ObjBase): + def __init__(self, amplitude_val=1.0, frequency_val=1.0, phase_val=0.0): + amplitude = Parameter("amplitude", amplitude_val, min=0, max=10) + frequency = Parameter("frequency", frequency_val, min=0.1, max=5) + phase = Parameter("phase", phase_val, min=-np.pi, max=np.pi) + super().__init__("sine_model", amplitude=amplitude, frequency=frequency, phase=phase) + + def __call__(self, x): + return self.amplitude.value * np.sin(2 * np.pi * self.frequency.value * x + self.phase.value) + +Basic Fitting Example +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + # Create test data + x_data = np.linspace(0, 2, 100) + true_model = SineModel(amplitude_val=2.5, frequency_val=1.5, phase_val=0.5) + y_data = true_model(x_data) + 0.1 * np.random.normal(size=len(x_data)) + + # Create model to fit with initial guesses + fit_model = SineModel(amplitude_val=1.0, frequency_val=1.0, phase_val=0.0) + + # Set which parameters to fit (unfix them) + fit_model.amplitude.fixed = False + fit_model.frequency.fixed = False + fit_model.phase.fixed = False + + # Create fitter and perform fit + fitter = Fitter(fit_model, fit_model) + result = fitter.fit(x=x_data, y=y_data) + + # Access results + print(f"Chi-squared: {result.chi2}") + print(f"Fitted amplitude: {fit_model.amplitude.value} ± {fit_model.amplitude.error}") + print(f"Fitted frequency: {fit_model.frequency.value} ± {fit_model.frequency.error}") + +Available Minimizers +------------------- + +EasyScience supports multiple optimization backends: + +.. code-block:: python + + from easyscience import AvailableMinimizers + + # View all available minimizers + fitter = Fitter(model, model) + print(fitter.available_minimizers) + # Output: ['LMFit', 'LMFit_leastsq', 'LMFit_powell', 'Bumps', 'Bumps_simplex', 'DFO', 'DFO_leastsq'] + +Switching Minimizers +~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + # Use LMFit (default) + fitter.switch_minimizer(AvailableMinimizers.LMFit) + result1 = fitter.fit(x=x_data, y=y_data) + + # Switch to Bumps + fitter.switch_minimizer(AvailableMinimizers.Bumps) + result2 = fitter.fit(x=x_data, y=y_data) + + # Use DFO for derivative-free optimization + fitter.switch_minimizer(AvailableMinimizers.DFO) + result3 = fitter.fit(x=x_data, y=y_data) + +Parameter Management +------------------- + +Setting Bounds and Constraints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + # Parameter with bounds + param = Parameter(name="amplitude", value=1.0, min=0.0, max=10.0, unit="m") + + # Fix parameter (exclude from fitting) + param.fixed = True + + # Unfix parameter (include in fitting) + param.fixed = False + + # Change bounds dynamically + param.min = 0.5 + param.max = 8.0 + +Parameter Dependencies +~~~~~~~~~~~~~~~~~~~~~ + +Parameters can depend on other parameters through expressions: + +.. code-block:: python + + # Create independent parameters + length = Parameter("length", 10.0, unit="m", min=1, max=100) + width = Parameter("width", 5.0, unit="m", min=1, max=50) + + # Create dependent parameter + area = Parameter.from_dependency( + name="area", + dependency_expression="length * width", + dependency_map={"length": length, "width": width}, + unit="m^2" + ) + + # When length or width changes, area updates automatically + length.value = 15.0 + print(area.value) # Will be 75.0 (15 * 5) + +Advanced Fitting Options +----------------------- + +Setting Tolerances and Limits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + fitter = Fitter(model, model) + + # Set convergence tolerance + fitter.tolerance = 1e-8 + + # Limit maximum function evaluations + fitter.max_evaluations = 1000 + + # Perform fit with custom settings + result = fitter.fit(x=x_data, y=y_data) + +Using Weights +~~~~~~~~~~~~ + +.. code-block:: python + + # Define weights (inverse variance) + weights = 1.0 / errors**2 # where errors are your data uncertainties + + # Fit with weights + result = fitter.fit(x=x_data, y=y_data, weights=weights) + +Multidimensional Fitting +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + class AbsSin2D(ObjBase): + def __init__(self, offset_val=0.0, phase_val=0.0): + offset = Parameter("offset", offset_val) + phase = Parameter("phase", phase_val) + super().__init__("sin2D", offset=offset, phase=phase) + + def __call__(self, x): + X, Y = x[:, 0], x[:, 1] # x is 2D array + return np.abs(np.sin(self.phase.value * X + self.offset.value)) * \ + np.abs(np.sin(self.phase.value * Y + self.offset.value)) + + # Create 2D data + x_2d = np.column_stack([x_grid.ravel(), y_grid.ravel()]) + + # Fit 2D model + model_2d = AbsSin2D(offset_val=0.1, phase_val=1.0) + model_2d.offset.fixed = False + model_2d.phase.fixed = False + + fitter = Fitter(model_2d, model_2d) + result = fitter.fit(x=x_2d, y=z_data.ravel()) + +Accessing Fit Results +-------------------- + +The ``FitResults`` object contains comprehensive information about the fit: + +.. code-block:: python + + result = fitter.fit(x=x_data, y=y_data) + + # Fit statistics + print(f"Chi-squared: {result.chi2}") + print(f"Reduced chi-squared: {result.reduced_chi}") + print(f"Number of parameters: {result.n_pars}") + print(f"Success: {result.success}") + + # Parameter values and uncertainties + for param_name, value in result.p.items(): + error = result.errors.get(param_name, 0.0) + print(f"{param_name}: {value} ± {error}") + + # Calculated values and residuals + y_calculated = result.y_calc + residuals = result.residual + + # Plot results + import matplotlib.pyplot as plt + plt.figure(figsize=(10, 4)) + plt.subplot(121) + plt.plot(x_data, y_data, 'o', label='Data') + plt.plot(x_data, y_calculated, '-', label='Fit') + plt.legend() + plt.subplot(122) + plt.plot(x_data, residuals, 'o') + plt.axhline(0, color='k', linestyle='--') + plt.ylabel('Residuals') + +Developer Guidelines +------------------- + +Creating Custom Models +~~~~~~~~~~~~~~~~~~~~~~ + +For developers building scientific components: + +.. code-block:: python + + from easyscience import ObjBase, Parameter + + class CustomModel(ObjBase): + def __init__(self, param1_val=1.0, param2_val=0.0): + # Always create Parameters with appropriate bounds and units + param1 = Parameter("param1", param1_val, min=-10, max=10, unit="m/s") + param2 = Parameter("param2", param2_val, min=0, max=1, fixed=True) + + # Call parent constructor with named parameters + super().__init__("custom_model", param1=param1, param2=param2) + + def __call__(self, x): + # Implement your model calculation + return self.param1.value * x + self.param2.value + + def get_fit_parameters(self): + # This is automatically implemented by ObjBase + # Returns only non-fixed parameters + return super().get_fit_parameters() + +Best Practices +~~~~~~~~~~~~~ + +1. **Always set appropriate bounds** on parameters to constrain the search space +2. **Use meaningful units** for physical parameters +3. **Fix parameters** that shouldn't be optimized +4. **Test with different minimizers** for robustness +5. **Validate results** by checking chi-squared and residuals + +Error Handling +~~~~~~~~~~~~~ + +.. code-block:: python + + from easyscience.fitting.minimizers import FitError + + try: + result = fitter.fit(x=x_data, y=y_data) + if not result.success: + print(f"Fit failed: {result.message}") + except FitError as e: + print(f"Fitting error: {e}") + except Exception as e: + print(f"Unexpected error: {e}") + +Testing Patterns +~~~~~~~~~~~~~~~ + +When writing tests for fitting code: + +.. code-block:: python + + import pytest + from easyscience import global_object + + @pytest.fixture + def clear_global_map(): + """Clear global map before each test""" + global_object.map._clear() + yield + global_object.map._clear() + + def test_model_fitting(clear_global_map): + # Create model and test fitting + model = CustomModel() + model.param1.fixed = False + + # Generate test data + x_test = np.linspace(0, 10, 50) + y_test = 2.5 * x_test + 0.1 * np.random.normal(size=len(x_test)) + + # Fit and verify + fitter = Fitter(model, model) + result = fitter.fit(x=x_test, y=y_test) + + assert result.success + assert model.param1.value == pytest.approx(2.5, abs=0.1) + +This comprehensive guide covers the essential aspects of fitting in EasyScience, from basic usage to advanced developer patterns. +The examples are drawn from the actual test suite and demonstrate real-world usage patterns. + diff --git a/docs/src/getting-started/installation.rst b/docs/src/getting-started/installation.rst index 048f2cd4..4d0cef44 100644 --- a/docs/src/getting-started/installation.rst +++ b/docs/src/getting-started/installation.rst @@ -2,7 +2,7 @@ Installation ************ -**EasyScience** requires Python 3.7 or above. +**EasyScience** requires Python 3.11 or above. Install via ``pip`` ------------------- @@ -17,18 +17,17 @@ Install as an EasyScience developer ----------------------------------- You can obtain the latest development source from our `Github repository -`_.: +`_.: .. code-block:: console - $ git clone https://github.com/easyScience/EasyScience - $ cd EasyScience + $ git clone https://github.com/easyscience/corelib + $ cd corelib And install via pip: .. code-block:: console - $ pip install -r requirements.txt $ pip install -e . .. installation-end-content \ No newline at end of file diff --git a/docs/src/getting-started/overview.rst b/docs/src/getting-started/overview.rst index 2fb0dbd7..c4231ad4 100644 --- a/docs/src/getting-started/overview.rst +++ b/docs/src/getting-started/overview.rst @@ -3,4 +3,223 @@ Overview ======== +EasyScience is a foundational Python library that provides the building blocks for scientific data simulation, analysis, and fitting. +It implements a descriptor-based object system with global state management, making it easy to create scientific models with parameters +that have units, bounds, and dependencies. + +What is EasyScience? +------------------- + +EasyScience serves as the core foundation for the EasyScience family of projects, offering: + +* **Scientific Parameters**: Values with units, uncertainties, bounds, and fitting capabilities +* **Model Building**: Base classes for creating complex scientific models +* **Multi-backend Fitting**: Support for LMFit, Bumps, and DFO-LS optimization engines +* **Parameter Dependencies**: Express relationships between parameters through mathematical expressions +* **Serialization**: Save and load complete model states including parameter relationships +* **Undo/Redo System**: Track and revert changes to model parameters +* **Global State Management**: Unified tracking of all objects and their relationships + +Key Concepts +----------- + +Descriptor-Based Architecture +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +EasyScience uses a hierarchical descriptor system: + +.. code-block:: python + + from easyscience import Parameter, ObjBase + + # Scientific parameter with units and bounds + temperature = Parameter( + name="temperature", + value=300.0, + unit="K", + min=0, + max=1000, + description="Sample temperature" + ) + + # Model containing parameters + class ThermalModel(ObjBase): + def __init__(self, temp_val=300.0, coeff_val=1.0): + temperature = Parameter("temperature", temp_val, unit="K", min=0, max=1000) + coefficient = Parameter("coefficient", coeff_val, min=0, max=10) + super().__init__("thermal_model", temperature=temperature, coefficient=coefficient) + +The hierarchy flows from: + +* ``DescriptorBase`` → ``DescriptorNumber`` → ``Parameter`` (fittable scientific values) +* ``BasedBase`` → ``ObjBase`` (containers for parameters and scientific models) +* ``CollectionBase`` (mutable sequences of scientific objects) + +Units and Physical Quantities +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +EasyScience integrates with `scipp `_ for robust unit handling: + +.. code-block:: python + + # Parameters automatically handle units + length = Parameter("length", 100, unit="cm", min=0, max=1000) + + # Unit conversions are automatic + length.convert_unit("m") + print(length.value) # 1.0 + print(length.unit) # m + + # Arithmetic operations preserve units + area = length * length # Results in m^2 + +Parameter Dependencies +~~~~~~~~~~~~~~~~~~~~~ + +Parameters can depend on other parameters through mathematical expressions: + +.. code-block:: python + + # Independent parameters + radius = Parameter("radius", 5.0, unit="m", min=0, max=100) + height = Parameter("height", 10.0, unit="m", min=0, max=200) + + # Dependent parameter using mathematical expression + volume = Parameter.from_dependency( + name="volume", + dependency_expression="3.14159 * radius**2 * height", + dependency_map={"radius": radius, "height": height}, + unit="m^3" + ) + + # Automatic updates + radius.value = 10.0 + print(volume.value) # Automatically recalculated + +Global State Management +~~~~~~~~~~~~~~~~~~~~~~ + +All EasyScience objects register with a global map for dependency tracking: + +.. code-block:: python + + from easyscience import global_object + + # All objects are automatically tracked + param = Parameter("test", 1.0) + print(param.unique_name) # Automatically generated unique identifier + + # Access global registry + all_objects = global_object.map.vertices() + + # Clear for testing (important in unit tests) + global_object.map._clear() + +Fitting and Optimization +~~~~~~~~~~~~~~~~~~~~~~~ + +EasyScience provides a unified interface to multiple optimization backends: + +.. code-block:: python + + from easyscience import Fitter, AvailableMinimizers + + # Create fitter with model + fitter = Fitter(model, model) # model serves as both object and function + + # Switch between different optimizers + fitter.switch_minimizer(AvailableMinimizers.LMFit) # Levenberg-Marquardt + fitter.switch_minimizer(AvailableMinimizers.Bumps) # Bayesian inference + fitter.switch_minimizer(AvailableMinimizers.DFO) # Derivative-free + + # Perform fit + result = fitter.fit(x=x_data, y=y_data, weights=weights) + +Serialization and Persistence +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Complete model states can be saved and restored: + +.. code-block:: python + + # Save model to dictionary + model_dict = model.as_dict() + + # Save to JSON + import json + with open('model.json', 'w') as f: + json.dump(model_dict, f, indent=2, default=str) + + # Restore model + with open('model.json', 'r') as f: + loaded_dict = json.load(f) + + new_model = Model.from_dict(loaded_dict) + + # Resolve parameter dependencies after loading + from easyscience.variable.parameter_dependency_resolver import resolve_all_parameter_dependencies + resolve_all_parameter_dependencies(new_model) + +Use Cases +-------- + +EasyScience is designed for: + +Scientific Modeling +~~~~~~~~~~~~~~~~~~ + +* Creating physics-based models with parameters that have physical meaning +* Handling units consistently throughout calculations +* Managing complex parameter relationships and constraints + +Data Fitting and Analysis +~~~~~~~~~~~~~~~~~~~~~~~~ + +* Fitting experimental data to theoretical models +* Comparing different optimization algorithms +* Uncertainty quantification and error propagation + +Software Development +~~~~~~~~~~~~~~~~~~~ + +* Building domain-specific scientific applications +* Creating reusable model components +* Implementing complex scientific workflows + +Research and Education +~~~~~~~~~~~~~~~~~~~~~ + +* Reproducible scientific computing +* Teaching scientific programming concepts +* Collaborative model development + +Architecture Benefits +------------------- + +**Type Safety**: Strong typing with unit checking prevents common errors + +**Flexibility**: Multiple optimization backends allow algorithm comparison + +**Extensibility**: Descriptor pattern makes it easy to add new parameter types + +**Reproducibility**: Complete serialization enables exact state restoration + +**Performance**: Efficient observer pattern minimizes unnecessary recalculations + +**Testing**: Global state management with cleanup utilities supports robust testing + +Getting Started +-------------- + +The best way to learn EasyScience is through examples: + +1. **Basic Usage**: Start with simple parameters and models +2. **Fitting Tutorial**: Learn the fitting system with real data +3. **Advanced Features**: Explore parameter dependencies and serialization +4. **Development Guide**: Build your own scientific components + +See the :doc:`installation` guide to get started, then explore the :doc:`../fitting/introduction` for practical examples. + +EasyScience forms the foundation for more specialized packages in the EasyScience ecosystem, providing the core abstractions that make scientific computing more accessible and reliable. + diff --git a/docs/src/index.rst b/docs/src/index.rst index ca99dda5..4e329b24 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -2,68 +2,177 @@ Welcome to EasyScience's documentation! ========================================= -**EasyScience** is the foundation of the EasyScience universe, providing the building blocks for libraries and applications which aim to make scientific data simulation and analysis easier. +**EasyScience** is a foundational Python library that provides the building blocks for scientific data simulation, analysis, and fitting. +It implements a descriptor-based object system with global state management, making it easier to create scientific models with parameters +that have units, bounds, and dependencies. +.. code-block:: python -Features of EasyScience -========================= + from easyscience import Parameter, ObjBase, Fitter + + # Create a model with scientific parameters + class SineModel(ObjBase): + def __init__(self, amplitude=1.0, frequency=1.0, phase=0.0): + amp = Parameter("amplitude", amplitude, min=0, max=10, unit="V") + freq = Parameter("frequency", frequency, min=0.1, max=5, unit="Hz") + phase = Parameter("phase", phase, min=-3.14, max=3.14, unit="rad") + super().__init__("sine_model", amplitude=amp, frequency=freq, phase=phase) + + def __call__(self, x): + return self.amplitude.value * np.sin(2*np.pi*self.frequency.value*x + self.phase.value) + + # Fit to experimental data + model = SineModel() + model.amplitude.fixed = False # Allow fitting + fitter = Fitter(model, model) + result = fitter.fit(x=x_data, y=y_data) -Free and open-source -Anyone is free to use EasyScience and the source code is openly shared on GitHub. +Key Features +============ -* *Cross-platform* - EasyScience is written in Python and available for all platforms. +**Scientific Parameters with Units** + Parameters automatically handle physical units, bounds, and uncertainties using `scipp `_ integration. -* *Various techniques* - EasyScience has been used to build various libraries such as easyDiffraction and easyReflectometry. +**Parameter Dependencies** + Express mathematical relationships between parameters that update automatically when dependencies change. -* *Advanced built-in features* - EasyScience provides features such as model minimization, automatic script generation, undo/redo, and more. +**Multi-Backend Fitting** + Unified interface to LMFit, Bumps, and DFO-LS optimization engines with easy algorithm comparison. +**Complete Serialization** + Save and restore entire model states including parameter relationships and dependencies. -Projects using EasyScience +**Global State Management** + Automatic tracking of all objects and their relationships with built-in undo/redo capabilities. + +**Developer-Friendly** + Clean APIs, comprehensive testing utilities, and extensive documentation for building scientific applications. + +Why EasyScience? +================ + +**Type Safety & Units** + Prevent common scientific computing errors with automatic unit checking and strong typing. + +**Reproducible Research** + Complete state serialization ensures exact reproducibility of scientific analyses. + +**Algorithm Flexibility** + Compare different optimization approaches without changing your model code. + +**Extensible Architecture** + Descriptor pattern makes it easy to create new parameter types and model components. + +Open Source & Cross-Platform ============================ -EasyScience is currently being used in the following projects: +EasyScience is free and open-source software with the source code openly shared on `GitHub `_. + +* **Cross-platform** - Written in Python and available for Windows, macOS, and Linux +* **Well-tested** - Comprehensive test suite ensuring reliability across platforms +* **Community-driven** - Open to contributions and feature requests +* **Production-ready** - Used in multiple scientific applications worldwide + + +Projects Built with EasyScience +=============================== + +EasyScience serves as the foundation for several scientific applications: + +**easyDiffraction** + .. image:: https://raw.githubusercontent.com/easyScience/easyDiffractionWww/master/assets/img/card.png + :target: https://easydiffraction.org + :width: 300px + + Scientific software for modeling and analysis of neutron diffraction data, providing an intuitive interface for crystallographic refinement. + +**easyReflectometry** + .. image:: https://raw.githubusercontent.com/easyScience/easyReflectometryWww/master/assets/img/card.png + :target: https://easyreflectometry.org + :width: 300px + + Scientific software for modeling and analysis of neutron reflectometry data, enabling detailed study of thin film structures. + +**Your Project Here** + EasyScience's flexible architecture makes it ideal for building domain-specific scientific applications. The comprehensive API and documentation help you get started quickly. + +Quick Start +=========== + +Ready to begin? Here's how to get started: -.. image:: https://raw.githubusercontent.com/easyScience/easyDiffractionWww/master/assets/img/card.png - :target: https://easydiffraction.org +1. **Install EasyScience**: ``pip install easyscience`` +2. **Read the Overview**: Understand the core concepts and architecture +3. **Try the Examples**: Work through practical fitting examples +4. **Explore the API**: Dive into the comprehensive reference documentation -Scientific software for modelling and analysis of neutron diffraction data. +.. code-block:: bash -.. image:: https://raw.githubusercontent.com/easyScience/easyReflectometryWww/master/assets/img/card.png - :target: https://easyreflectometry.org + pip install easyscience -Scientific software for modelling and analysis of neutron reflectometry data. +Then explore the tutorials and examples to learn the key concepts! -Documentation ------------------------------------------- +Documentation Guide +================== .. toctree:: :caption: Getting Started - :maxdepth: 3 + :maxdepth: 2 + :titlesonly: getting-started/overview getting-started/installation +New to EasyScience? Start with the :doc:`getting-started/overview` to understand the core concepts, then follow the :doc:`getting-started/installation` guide. .. toctree:: - :caption: Base Classes - :maxdepth: 3 + :caption: User Guides + :maxdepth: 2 + :titlesonly: - reference/base + fitting/introduction +Learn how to use EasyScience for scientific modeling and data fitting with comprehensive examples and best practices. .. toctree:: - :caption: Fitting - :maxdepth: 3 + :caption: API Reference + :maxdepth: 2 + :titlesonly: - fitting/introduction + reference/base + +Complete API documentation for all classes, methods, and functions in EasyScience. .. toctree:: + :caption: Examples :maxdepth: 2 - :caption: Example galleries + :titlesonly: base_examples/index fitting_examples/index +Practical examples and tutorials demonstrating real-world usage patterns. + +Need Help? +========== + +* **GitHub Issues**: Report bugs or request features on `GitHub `_ +* **Discussions**: Ask questions in `GitHub Discussions `_ +* **API Reference**: Complete documentation of all classes and methods +* **Examples**: Practical tutorials and code samples + +Contributing +============ + +EasyScience is developed openly and welcomes contributions! Whether you're fixing bugs, adding features, improving documentation, or sharing usage examples, your contributions help make scientific computing more accessible. + +Visit our `GitHub repository `_ to: + +* Report issues or suggest features +* Submit pull requests +* Join discussions about development +* Help improve documentation + Indices and tables ================== diff --git a/docs/src/reference/base.rst b/docs/src/reference/base.rst index ed3d05de..f3c277e0 100644 --- a/docs/src/reference/base.rst +++ b/docs/src/reference/base.rst @@ -1,38 +1,315 @@ -====================== -Parameters and Objects -====================== +============== +API Reference +============== -Descriptors -=========== +This reference provides detailed documentation for all EasyScience classes and functions. -.. autoclass:: easyscience.variable.Descriptor - :members: +Core Variables and Descriptors +============================== + +Descriptor Base Classes +----------------------- + +.. autoclass:: easyscience.variable.DescriptorBase + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: easyscience.variable.DescriptorNumber + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: easyscience.variable.DescriptorArray + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: easyscience.variable.DescriptorStr + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: easyscience.variable.DescriptorBool + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: easyscience.variable.DescriptorAnyType + :members: + :inherited-members: + :show-inheritance: Parameters -========== +---------- .. autoclass:: easyscience.variable.Parameter - :members: - :inherited-members: + :members: + :inherited-members: + :show-inheritance: -============================= -Super Classes and Collections -============================= + The Parameter class extends DescriptorNumber with fitting capabilities, bounds, and dependency relationships. -Super Classes -============= + **Key Methods:** + + .. automethod:: from_dependency + .. automethod:: make_dependent_on + .. automethod:: make_independent + .. automethod:: resolve_pending_dependencies + +Base Classes for Models +======================= + +BasedBase +--------- .. autoclass:: easyscience.base_classes.BasedBase - :members: - :inherited-members: + :members: + :inherited-members: + :show-inheritance: + + Base class providing serialization, global object registration, and interface management. + +ObjBase +------- .. autoclass:: easyscience.base_classes.ObjBase - :members: +_add_component - :inherited-members: + :members: + :inherited-members: + :show-inheritance: + + Container class for creating scientific models with parameters. All user-defined models should inherit from this class. + + **Key Methods:** + + .. automethod:: get_fit_parameters + .. automethod:: get_parameters + .. automethod:: _add_component Collections -=========== +----------- + +.. autoclass:: easyscience.base_classes.CollectionBase + :members: + :inherited-members: + :show-inheritance: + + Mutable sequence container for scientific objects with automatic parameter tracking. + +Fitting and Optimization +======================== + +Fitter +------ + +.. autoclass:: easyscience.fitting.Fitter + :members: + :show-inheritance: + + Main fitting engine supporting multiple optimization backends. + + **Key Methods:** + + .. automethod:: fit + .. automethod:: switch_minimizer + .. automethod:: make_model + .. automethod:: evaluate + +Available Minimizers +-------------------- + +.. autoclass:: easyscience.fitting.AvailableMinimizers + :members: + :show-inheritance: + + Enumeration of available optimization backends. + +Fit Results +----------- + +.. autoclass:: easyscience.fitting.FitResults + :members: + :show-inheritance: + + Container for fitting results including parameters, statistics, and diagnostics. + +Minimizer Base Classes +--------------------- + +.. autoclass:: easyscience.fitting.minimizers.MinimizerBase + :members: + :show-inheritance: + + Abstract base class for all minimizer implementations. + +.. autoclass:: easyscience.fitting.minimizers.LMFit + :members: + :show-inheritance: + + LMFit-based minimizer implementation. + +.. autoclass:: easyscience.fitting.minimizers.Bumps + :members: + :show-inheritance: + + Bumps-based minimizer implementation. + +.. autoclass:: easyscience.fitting.minimizers.DFO + :members: + :show-inheritance: + + DFO-LS-based minimizer implementation. + +Global State Management +======================= + +Global Object +------------- + +.. autoclass:: easyscience.global_object.GlobalObject + :members: + :show-inheritance: + + Singleton managing global state, logging, and object tracking. + +Object Map +---------- + +.. autoclass:: easyscience.global_object.Map + :members: + :show-inheritance: + + Graph-based registry for tracking object relationships and dependencies. + +Undo/Redo System +---------------- + +.. autoclass:: easyscience.global_object.UndoStack + :members: + :show-inheritance: + + Stack-based undo/redo system for parameter changes. + +Serialization and I/O +===================== + +Serializer Components +-------------------- + +.. autoclass:: easyscience.io.SerializerComponent + :members: + :show-inheritance: + + Base class providing serialization capabilities. + +.. autoclass:: easyscience.io.SerializerDict + :members: + :show-inheritance: + + Dictionary-based serialization implementation. + +.. autoclass:: easyscience.io.SerializerBase + :members: + :show-inheritance: + + Base serialization functionality. + +Models and Examples +================== + +Polynomial Model +--------------- + +.. autoclass:: easyscience.models.Polynomial + :members: + :show-inheritance: + + Built-in polynomial model for demonstration and testing. + +Job Management +============= + +Analysis and Experiments +------------------------ + +.. autoclass:: easyscience.job.Analysis + :members: + :show-inheritance: + +.. autoclass:: easyscience.job.Experiment + :members: + :show-inheritance: + +.. autoclass:: easyscience.job.Job + :members: + :show-inheritance: + +.. autoclass:: easyscience.job.TheoreticalModel + :members: + :show-inheritance: + +Utility Functions +================ + +Decorators +---------- + +.. autofunction:: easyscience.global_object.undo_redo.property_stack + + Decorator for properties that should be tracked in the undo/redo system. + +Class Tools +----------- + +.. autofunction:: easyscience.utils.classTools.addLoggedProp + + Utility for adding logged properties to classes. + +String Utilities +--------------- + +.. automodule:: easyscience.utils.string + :members: + +Parameter Dependencies +--------------------- + +.. autofunction:: easyscience.variable.parameter_dependency_resolver.resolve_all_parameter_dependencies + + Resolve all pending parameter dependencies after deserialization. + +.. autofunction:: easyscience.variable.parameter_dependency_resolver.get_parameters_with_pending_dependencies + + Find parameters that have unresolved dependencies. + +Constants and Enumerations +========================== + +.. autodata:: easyscience.global_object + :annotation: GlobalObject + + Global singleton instance managing application state. + +Exception Classes +================ + +.. autoclass:: easyscience.fitting.minimizers.FitError + :show-inheritance: + + Exception raised when fitting operations fail. + +.. autoclass:: scipp.UnitError + :show-inheritance: + + Exception raised for unit-related errors (from scipp dependency). + +Usage Examples +============= + +For practical usage examples and tutorials, see: + +* :doc:`../getting-started/overview` - Introduction and key concepts +* :doc:`../fitting/introduction` - Comprehensive fitting guide +* :doc:`../getting-started/installation` - Installation instructions -.. autoclass:: easyscience.CollectionBase - :members: - :inherited-members: +The API reference covers all public classes and methods. For implementation details and advanced usage patterns, refer to the source code and test suites in the repository. From f3bdd27cbdd7f7978aa2323def1563ebbd970557 Mon Sep 17 00:00:00 2001 From: Piotr Rozyczko Date: Thu, 16 Oct 2025 18:59:44 +0200 Subject: [PATCH 2/3] added missing RST --- Examples/fitting/README.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Examples/fitting/README.rst diff --git a/Examples/fitting/README.rst b/Examples/fitting/README.rst new file mode 100644 index 00000000..614960cb --- /dev/null +++ b/Examples/fitting/README.rst @@ -0,0 +1,6 @@ +.. _fitting_examples: + +Fitting Examples +---------------- + +This section gathers examples which demonstrate fitting functionality using EasyScience's fitting capabilities. From fb10a0b3e11537ce1a56de76f07727da60d5e270 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Thu, 23 Oct 2025 09:34:07 +0200 Subject: [PATCH 3/3] updates after CR --- docs/src/fitting/introduction.rst | 41 +++++++++++++++++++++++++-- docs/src/getting-started/overview.rst | 3 +- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/docs/src/fitting/introduction.rst b/docs/src/fitting/introduction.rst index 3f019a99..51155dd9 100644 --- a/docs/src/fitting/introduction.rst +++ b/docs/src/fitting/introduction.rst @@ -131,14 +131,51 @@ Parameters can depend on other parameters through expressions: area = Parameter.from_dependency( name="area", dependency_expression="length * width", - dependency_map={"length": length, "width": width}, - unit="m^2" + dependency_map={"length": length, "width": width} ) # When length or width changes, area updates automatically length.value = 15.0 print(area.value) # Will be 75.0 (15 * 5) +Using make_dependent_on() Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also make an existing parameter dependent on other parameters using the ``make_dependent_on()`` method. This is useful when you want to convert an independent parameter into a dependent one: + +.. code-block:: python + + # Create independent parameters + radius = Parameter("radius", 5.0, unit="m", min=1, max=20) + height = Parameter("height", 10.0, unit="m", min=1, max=50) + volume = Parameter("volume", 100.0, unit="m³") # Initially independent + pi = Parameter("pi", 3.14159, fixed=True) # Constant parameter + + # Make volume dependent on radius and height + volume.make_dependent_on( + dependency_expression="pi * radius**2 * height", + dependency_map={"radius": radius, "height": height, "pi": pi} + ) + + # Now volume automatically updates when radius or height changes + radius.value = 8.0 + print(f"New volume: {volume.value:.2f} m³") # Automatically calculated + + # The parameter becomes dependent and cannot be set directly + try: + volume.value = 200.0 # This will raise an AttributeError + except AttributeError: + print("Cannot set value of dependent parameter directly") + +**What to expect:** + +- The parameter becomes **dependent** and its ``independent`` property becomes ``False`` +- You **cannot directly set** the value, bounds, or variance of a dependent parameter +- The parameter's value is **automatically recalculated** whenever any of its dependencies change +- Dependent parameters **cannot be fitted** (they are automatically fixed) +- The original value, unit, variance, min, and max are **overwritten** by the dependency calculation +- You can **revert to independence** using the ``make_independent()`` method if needed + Advanced Fitting Options ----------------------- diff --git a/docs/src/getting-started/overview.rst b/docs/src/getting-started/overview.rst index c4231ad4..2136bec6 100644 --- a/docs/src/getting-started/overview.rst +++ b/docs/src/getting-started/overview.rst @@ -88,8 +88,7 @@ Parameters can depend on other parameters through mathematical expressions: volume = Parameter.from_dependency( name="volume", dependency_expression="3.14159 * radius**2 * height", - dependency_map={"radius": radius, "height": height}, - unit="m^3" + dependency_map={"radius": radius, "height": height} ) # Automatic updates