Skip to content

Commit

Permalink
bug fix: hard-coded the attributes of scatterer in experiment module …
Browse files Browse the repository at this point in the history
…as the previous method based on dataclass attribute order was messing the medium_properties of scatterers
  • Loading branch information
MartinPdeS committed Dec 16, 2024
1 parent 0e2da10 commit 437fa8c
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 43 deletions.
4 changes: 2 additions & 2 deletions PyMieSim/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
__version_tuple__: VERSION_TUPLE
version_tuple: VERSION_TUPLE

__version__ = version = '3.1.0.1'
__version_tuple__ = version_tuple = (3, 1, 0, 1)
__version__ = version = '3.1.0.6'
__version_tuple__ = version_tuple = (3, 1, 0, 6)
5 changes: 2 additions & 3 deletions PyMieSim/cpp/experiment/includes/experiment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

typedef std::complex<double> complex128;


#define DEFINE_SCATTERER_FUNCTION(scatterer, SCATTERER, dtype, name) \
pybind11::array_t<dtype> get_##scatterer##_##name() const { return get_scatterer_data<double, SCATTERER::Set>(scatterer##Set, &SCATTERER::Scatterer::get_##name); } \
pybind11::array_t<dtype> get_##scatterer##_##name##_sequential() const { return get_scatterer_data_sequential<double, SCATTERER::Set>(scatterer##Set, &SCATTERER::Scatterer::get_##name); }
Expand All @@ -24,9 +25,6 @@ typedef std::complex<double> complex128;
pybind11::array_t<double> get_##scatterer##_coupling() const { return get_scatterer_coupling<SCATTERER::Set>(scatterer##Set); } \
pybind11::array_t<double> get_##scatterer##_coupling_sequential() const { return get_scatterer_coupling_sequential<SCATTERER::Set>(scatterer##Set); }



#include <iostream>
class Experiment
{
public:
Expand Down Expand Up @@ -118,6 +116,7 @@ class Experiment
return _vector_to_numpy(output_array, {full_size});
}


template<typename ScattererSet>
pybind11::array_t<double> get_scatterer_coupling(const ScattererSet& scattererSet) const {
std::vector<size_t> array_shape = concatenate_vector(sourceSet.shape, scattererSet.shape, detectorSet.shape);
Expand Down
5 changes: 2 additions & 3 deletions PyMieSim/experiment/scatterer/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from pydantic import field_validator
from typing import List
from pydantic.dataclasses import dataclass
from dataclasses import fields
from pydantic import ConfigDict
from PyMieSim.units import Quantity, meter, RIU
from pint_pandas import PintArray
Expand Down Expand Up @@ -98,8 +97,7 @@ def _generate_mapping(self) -> None:
list
A list of visual representations for each property in the `mapping` dictionary that has been populated.
"""

for attr in [f.name for f in fields(self) if f.name != 'source']:
for attr in self.attributes:
values = getattr(self, attr)
if values is None:
continue
Expand All @@ -108,3 +106,4 @@ def _generate_mapping(self) -> None:
self.mapping["scatterer:" + attr] = PintArray(values.magnitude, dtype=values.units)
else:
self.mapping["scatterer:" + attr] = [repr(m) for m in values]

2 changes: 2 additions & 0 deletions PyMieSim/experiment/scatterer/core_shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class CoreShell(BaseScatterer):
'a2', 'a3', 'b1', 'b2', 'b3', 'g', 'coupling',
]

attributes = ['core_diameter', 'shell_thickness', 'core_property', 'shell_property', 'medium_property']

def __post_init__(self) -> None:
"""
Assembles the keyword arguments necessary for C++ binding, tailored for core-shell scatterers.
Expand Down
2 changes: 2 additions & 0 deletions PyMieSim/experiment/scatterer/cylinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Cylinder(BaseScatterer):
'b22', 'b13', 'b23', 'coupling',
]

attributes = ['diameter', 'property', 'medium_property']

def __post_init__(self) -> None:
"""
Constructs the keyword arguments necessary for the C++ binding interface, specifically tailored for spherical scatterers.
Expand Down
2 changes: 2 additions & 0 deletions PyMieSim/experiment/scatterer/sphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class Sphere(BaseScatterer):
'a2', 'a3', 'b1', 'b2', 'b3', 'g', 'coupling',
]

attributes = ['diameter', 'property', 'medium_property']

def __post_init__(self) -> None:
"""
Constructs the keyword arguments necessary for the C++ binding interface, specifically tailored for spherical scatterers.
Expand Down
49 changes: 43 additions & 6 deletions PyMieSim/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,49 @@ def plot_with_std(dataframe: pd.DataFrame, ax, x: str, std: str, alpha: float =
plt.show()


def plot_without_std(dataframe: pd.DataFrame, ax: plt.Axes, x: str, show: bool = True, **kwargs) -> None:
def plot_without_std(
dataframe: pd.DataFrame,
ax: plt.Axes,
x: str,
y: str = None,
show: bool = True,
log_scale_x: bool = False,
log_scale_y: bool = False,
**kwargs) -> plt.Axes:
"""
Plots the data without standard deviation shading. Handles real and imaginary parts if the data is complex.
Plots data without standard deviation shading, handling both real and imaginary parts for complex data.
Parameters
----------
df_unstacked : pd.DataFrame
The DataFrame after unstacking.
dataframe : pd.DataFrame
The DataFrame containing the data to plot. If the DataFrame includes
multi-index columns, it will handle stacked levels for plotting.
ax : plt.Axes
The matplotlib axis on which to plot.
The matplotlib axis on which to plot the data.
x : str
The index level for the x-axis.
The column or index level to use as the x-axis.
y : str, optional
The column to use as the y-axis. If not specified, the first column is used.
show : bool, default=True
Whether to display the plot immediately.
log_scale_x : bool, default=False
Whether to apply logarithmic scaling to the x-axis.
log_scale_y : bool, default=False
Whether to apply logarithmic scaling to the y-axis.
**kwargs : dict, optional
Additional keyword arguments passed to `matplotlib.pyplot.plot`,
such as line styles, colors, markers, etc.
Returns
-------
plt.Axes
The matplotlib axis with the plotted data.
Notes
-----
- If the `dataframe` contains complex data, the function plots the real part by default.
- The `kwargs` can be used to customize the appearance of the plot.
- For multi-indexed DataFrames, groups are automatically handled and labeled.
"""
if 'type' in dataframe.columns.names:
dataframe = dataframe.stack('type', future_stack=True)
Expand Down Expand Up @@ -150,6 +181,12 @@ def plot_without_std(dataframe: pd.DataFrame, ax: plt.Axes, x: str, show: bool =
**kwargs
)

# Apply log scaling if specified
if log_scale_x:
ax.set_xscale('log')
if log_scale_y:
ax.set_yscale('log')

ax.legend(title=" : ".join(groupby_levels))

if show:
Expand Down
39 changes: 10 additions & 29 deletions development/dev1.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
"""
Sphere: Qsca vs diameter
========================

"""

# %%
# Importing the package dependencies: numpy, PyMieSim
import numpy as np

from PyMieSim.experiment.scatterer import Sphere
Expand All @@ -14,45 +7,33 @@
from PyMieSim.experiment import Setup
from PyMieSim.units import nanometer, degree, watt, AU, RIU

# %%
# Defining the source to be employed.
source = Gaussian(
wavelength=[500] * nanometer,
polarization=30 * degree,
wavelength=488 * nanometer,
polarization=0 * degree,
optical_power=1e-3 * watt,
NA=0.2 * AU
)
# %%
# Defining the ranging parameters for the scatterer distribution

scatterer = Sphere(
diameter=np.linspace(10, 1000, 1000) * nanometer,
medium_property=1.33 * RIU,
property=[1.40, 1.45, 1.50] * RIU,
diameter=np.linspace(30, 300, 200) * nanometer,
medium_property=[1.33, 1.3299] * RIU,
property=[1.42] * RIU,
source=source
)

# %%
# Defining the detector to be employed.
detector = Photodiode(
NA=1.2 * AU,
NA=0.2 * AU,
phi_offset=[0.0] * degree,
gamma_offset=0.0 * degree,
sampling=600 * AU,
polarization_filter=None
)



# %%
# Defining the experiment setup
experiment = Setup(scatterer=scatterer, source=source, detector=detector)

# %%
# Measuring the properties
dataframe = experiment.get('coupling', scale_unit=True, drop_unique_level=True)

dataframe = experiment.get('coupling', scale_unit=True)


print(dataframe[280:])
# %%
# Plotting the results
# dataframe.plot_data(x='scatterer:diameter')
dataframe.plot_data(x='scatterer:diameter', log_scale_y=False)

0 comments on commit 437fa8c

Please sign in to comment.