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. diff --git a/docs/src/fitting/introduction.rst b/docs/src/fitting/introduction.rst index 72c572ac..51155dd9 100644 --- a/docs/src/fitting/introduction.rst +++ b/docs/src/fitting/introduction.rst @@ -2,3 +2,361 @@ 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} + ) + + # 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 +----------------------- + +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..2136bec6 100644 --- a/docs/src/getting-started/overview.rst +++ b/docs/src/getting-started/overview.rst @@ -3,4 +3,222 @@ 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} + ) + + # 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.