flexcompute / tidy3d

Fast electromagnetic solver (FDTD) at scale.
https://docs.flexcompute.com/projects/tidy3d/en/latest/
GNU Lesser General Public License v2.1
181 stars 41 forks source link

Issue on page /_autosummary/tidy3d.FieldProjectionAngleMonitor.html #677

Closed chenyudong92 closed 1 year ago

chenyudong92 commented 1 year ago

When I try to use function: tidy3d.FieldProjectionAngleMonitor for far field distribution.

It shows: AttributeError: module 'tidy3d' has no attribute 'FieldProjectionAngleMonitor'.

Could you help me figure it out?

below is all my code:

%%

standard python imports

import numpy as np import matplotlib.pyplot as plt

tidy3d imports

import tidy3d as td import tidy3d.web as web

%%

radius and location of the sphere

radius = 10 center = [0, 0, 0]

permittivity of the sphere

epsr = 4

free space central wavelength

wavelength = (2.0 * radius) / 2.0

wavelength = 0.94 f0 = td.C_0 / wavelength

distance between the surface of the sphere and the start of the PML layers along each cartesian direction

buffer_PML = 3 * wavelength

distance between the sphere and the near field monitor along each cartesian direction

buffer_mon = 1 * wavelength

Define material properties

air = td.Medium(permittivity=1) diel = td.Medium(permittivity=epsr)

resolution control

min_steps_per_wvl = 24

create the sphere

sphere = td.Structure(geometry=td.Sphere(center=center, radius=radius), medium=diel) geometry = []

define PML layers on all sides

boundary_spec = td.BoundarySpec.all_sides(boundary=td.PML())

set the domain size in x, y, and z

domain_size = buffer_PML + 2 * radius + buffer_PML

construct simulation size array

sim_size = (domain_size, domain_size, domain_size)

Bandwidth in Hz

fwidth = f0 / 10.0

Gaussian source offset; the source peak is at time t = offset/fwidth

offset = 4.0

time dependence of source

gaussian = td.GaussianPulse(freq0=f0, fwidth=fwidth, offset=offset)

place the source below the sphere, propagating in the +z direction

source = td.PlaneWave(

center=(0, 0, -(radius + 3 * buffer_PML / 4)),

size=(td.inf, td.inf, 0),

source_time=gaussian,

direction="+",

pol_angle=0,

)

source = td.GaussianBeam( source_time=gaussian, direction='+', size=(td.inf, td.inf, 0), center=(0, 0, -(radius + 3 * buffer_PML / 4)),

pol_angle=0.0, ##### 0 for p-lolarization, np.pi/2 specifies S-polarization

# angle_theta=0, angle_phi=0,
# direction="+",
pol_angle=0,
waist_radius=5.4, 
waist_distance= 8,

name='GaussianBeam')

Simulation run time past the source decay (around t=2*offset/fwidth)

run_time = 100 / fwidth

create a set of surface monitors around the sphere for local computation of far fields

mon_size = 2 radius + 2 buffer_mon monitors_near = td.FieldMonitor.surfaces( center=center, size=[mon_size, mon_size, mon_size], freqs=[f0], name="near_field" )

set the far-field observation angles of interest

num_theta = 300 num_phi = 2 thetas = np.linspace(0, np.pi, num_theta) phis = np.linspace(0, np.pi / 2, num_phi)

create the far field monitor for server-side computation of far fields

monitor_far = td.FieldProjectionAngleMonitor( center=center, size=[mon_size, mon_size, mon_size], freqs=[f0], name="far_field", custom_origin=center, phi=list(phis), theta=list(thetas), far_field_approx=True, # we leave this to its default value of 'True' because we are interested in fields sufficiently

far away that the far field approximations can be invoked to speed up the calculation

)

create a set of surface monitors around the sphere

monitors_downsampled = td.FieldMonitor.surfaces( center=center, size=[mon_size, mon_size, mon_size], freqs=[f0], name="near_field_downsampled", interval_space=( 2, 2, 3, ), # these are the (x, y, z) factors by which fields are downsampled ) monitors = monitors_near + [monitor_far] + monitors_downsampled

sim = td.Simulation( size=sim_size, grid_spec=td.GridSpec.auto(min_steps_per_wvl=min_steps_per_wvl), structures=geometry, sources=[source], monitors=monitors, run_time=run_time, boundary_spec=boundary_spec, symmetry=(-1, 1, 0), )

Here, we add the sphere as an override structure for the messhing such

that the grids of the two simulations match.

sim_empty = td.Simulation( size=sim_size, grid_spec=td.GridSpec.auto( min_steps_per_wvl=min_steps_per_wvl, override_structures=geometry, ), structures=[], sources=[source], monitors=monitors, run_time=run_time, boundary_spec=boundary_spec, symmetry=(-1, 1, 0), ) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 3)) sim.plot(y=0, ax=ax1) sim_empty.plot(y=0, ax=ax2)

Run simulation

import tidy3d.web as web

sim_data = web.run(sim, task_name="sphereRCS", path="data/sphereRCS.hdf5") sim_empty_data = web.run( sim_empty, task_name="sphereRCS_empty", path="data/sphereRCS_empty.hdf5" ) import time

first, we construct the classes which compute far fields locally on your machine

n2f = td.FieldProjector.from_near_field_monitors( sim_data=sim_data, near_monitors=monitors_near, # only supply the non-downsampled surface monitors as sources normal_dirs=["-", "+", "-", "+", "-", "+"], pts_per_wavelength=10, )

do the same for the downsampled monitors

n2f_downsampled = td.FieldProjector.from_near_field_monitors( sim_data=sim_data, near_monitors=monitors_downsampled, # only supply the downsampled surface monitors as sources normal_dirs=["-", "+", "-", "+", "-", "+"], pts_per_wavelength=10, )

we'll also project the fields from the empty simulation into the far field to get the scattered far field

n2f_empty = td.FieldProjector.from_near_field_monitors( sim_data=sim_empty_data, near_monitors=monitors_near, # only supply the non-downsampled surface monitors as sources normal_dirs=["-", "+", "-", "+", "-", "+"], pts_per_wavelength=10, )

now, we retrieve the far fields in all three cases by passing in our far field monitor from before

start = time.time() far_fields = n2f.project_fields(monitor_far) end = time.time() n2f_time = end - start

start = time.time() far_fields_downsampled = n2f_downsampled.project_fields(monitor_far) end = time.time() n2f_downsampled_time = end - start

start = time.time() far_fields_empty = n2f_empty.project_fields(monitor_far) end = time.time() n2f_empty_time = end - start

use the simulation log to find the time taken for server-side computations

n2f_server_time = float( sim_data.log.split("Field projection time (s): ", 1)[1].split("\n", 1)[0] )

print(f"Local near-to-far: {n2f_time} s") print(f"Local near-to-far with downsampling: {n2f_downsampled_time} s") print(f"Server-side near-to-far: {n2f_server_time} s") far_fields_server = sim_data[monitor_far.name] far_fields_empty_server = sim_empty_data[monitor_far.name]

scattered fields for client-side projections

for field, field_empty in zip( far_fields.field_components.values(), far_fields_empty.field_components.values() ): field.values -= field_empty.values

scattered fields for server-side projections

for field, field_empty in zip( far_fields_server.field_components.values(), far_fields_empty_server.field_components.values(), ): field.values -= field_empty.values

get the RCS for the local, local downsampled and server-side cases

RCS = far_fields.radar_cross_section.sel(f=f0).values RCS_downsampled = far_fields_downsampled.radar_cross_section.sel(f=f0).values RCS_server = far_fields_server.radar_cross_section.sel(f=f0).values

def to_db(val): val = np.abs(val) / np.max(np.abs(val)) return 10.0 * np.log10(val)

RCS_phi0 = RCS[0, :, 0] RCS_phi90 = RCS[0, :, 1]

RCS_downsampled_phi0 = RCS_downsampled[0, :, 0] RCS_downsampled_phi90 = RCS_downsampled[0, :, 1]

RCS_server_phi0 = RCS_server[0, :, 0] RCS_server_phi90 = RCS_server[0, :, 1]

------ import analytical data from disk ------

mie_file_id = "2lambda_epsr4"

mie_filename_phi0 = "./data/mie_bRCSphi0" + mie_file_id + ".txt"

mie_filename_phi90 = "./data/mie_bRCSphi90" + mie_file_id + ".txt"

mie_data_phi0 = np.loadtxt(mie_filename_phi0, delimiter="\t", skiprows=2)

mie_theta_phi0 = np.squeeze(mie_data_phi0[:, [0]])

mie_phi0 = np.squeeze(mie_data_phi0[:, [1]])

mie_data_phi90 = np.loadtxt(mie_filename_phi90, delimiter="\t", skiprows=2)

mie_theta_phi90 = np.squeeze(mie_data_phi90[:, [0]])

mie_phi90 = np.squeeze(mie_data_phi90[:, [1]])

------ plot for phi = 0 ------

fig, ax = plt.subplots(figsize=(7.5, 5))

ax.plot(mie_theta_phi0, to_db(mie_phi0), "-k", label="$\phi = 0$, Mie")

ax.plot(thetas, to_db(RCS_phi0), "--b", label="$\phi = 0$, near2far local") ax.plot( thetas, to_db(RCS_downsampled_phi0), "--r", label="$\phi = 0$, near2far local downsampled", ) ax.plot(thetas, to_db(RCS_server_phi0), "--g", label="$\phi = 0$, near2far server") ax.set( xlabel="$\theta$ (degrees)", ylabel="Bistatic RCS (dBsm)", yscale="linear", xscale="linear", ) ax.grid(visible=True, which="both", axis="both", linewidth=0.4) plt.legend(loc="best", prop={"size": 14}) plt.tight_layout()

------ plot for phi = pi/2 ------

fig, ax = plt.subplots(figsize=(7.5, 5))

ax.plot(mie_theta_phi90, to_db(mie_phi90), "-k", label="$\phi = \pi/2$, Mie")

ax.plot(thetas, to_db(RCS_phi90), "--b", label="$\phi = \pi/2$, near2far local") ax.plot( thetas, to_db(RCS_downsampled_phi90), "--r", label="$\phi = \pi/2$, near2far local downsampled", ) ax.plot( thetas, to_db(RCS_server_phi90), "--g", label="$\phi = \pi/2$, near2far server" ) ax.set( xlabel="$\theta$ (degrees)", ylabel="Bistatic RCS (dBsm)", yscale="linear", xscale="linear", ) ax.grid(visible=True, which="both", axis="both", linewidth=0.4) plt.legend(loc="best", prop={"size": 14}) plt.tight_layout()

%%

tylerflex commented 1 year ago

Hi @chenyudong92 what version of tidy3d are you using? If you do

import tidy3d

in a python shell, what version number gets displayed? With the most recent release (1.8.3) I am able to import FieldProjectionAngleMonitor

image

To upgrade to version 1.8.3, you can do

pip install --upgrade tidy3d
chenyudong92 commented 1 year ago

when I upgrade, the issue solved. Thanks for your help!

Sincerely, Yudong Chen M.S. of Electrical Engineering at SMU Ph.D. Student of Electrical Engineering at UTA Office at 2nd floor of NanoFab at UTA


发件人: Tyler Hughes @.> 发送时间: Thursday, February 2, 2023 7:32:28 PM 收件人: flexcompute/tidy3d @.> 抄送: Chen, Yudong @.>; Mention @.> 主题: Re: [flexcompute/tidy3d] Issue on page /_autosummary/tidy3d.FieldProjectionAngleMonitor.html (Issue #677)

[External]

Hi @chenyudong92https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fchenyudong92&data=05%7C01%7Cyudong.chen%40mavs.uta.edu%7Cf86a7d612a8b4ed2a7da08db058682e0%7C5cdc5b43d7be4caa8173729e3b0a62d9%7C0%7C0%7C638109847502560143%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=3zYtGSJQ8rBtr22%2BR0HKcf03Yy2WhjNRNMXQGVZZWe8%3D&reserved=0 what version of tidy3d are you using? If you do

import tidy3d

in a python shell, what version number gets displayed? With the most recent release (1.8.3) I am able to import FieldProjectionAngleMonitor [image]https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fuser-images.githubusercontent.com%2F92756888%2F216489677-7461052b-86a6-40de-9d08-7e26c0c771f5.png&data=05%7C01%7Cyudong.chen%40mavs.uta.edu%7Cf86a7d612a8b4ed2a7da08db058682e0%7C5cdc5b43d7be4caa8173729e3b0a62d9%7C0%7C0%7C638109847502560143%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=RBfX5IchWnFDzx9MvzkLwGlVPz6%2Bw4rQVGELm0uooZg%3D&reserved=0

To upgrade to version 1.8.3, you can do

pip install --upgrade tidy3d

― Reply to this email directly, view it on GitHubhttps://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fflexcompute%2Ftidy3d%2Fissues%2F677%23issuecomment-1414590806&data=05%7C01%7Cyudong.chen%40mavs.uta.edu%7Cf86a7d612a8b4ed2a7da08db058682e0%7C5cdc5b43d7be4caa8173729e3b0a62d9%7C0%7C0%7C638109847502560143%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=omElU7j6DVbg7zU4RxUB30PdXxIH43qH575HnEIYCuw%3D&reserved=0, or unsubscribehttps://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FANXYTVZZ3HMF54TA77DCUKTWVRN2ZANCNFSM6AAAAAAUPVS424&data=05%7C01%7Cyudong.chen%40mavs.uta.edu%7Cf86a7d612a8b4ed2a7da08db058682e0%7C5cdc5b43d7be4caa8173729e3b0a62d9%7C0%7C0%7C638109847502560143%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=iRETwRVeDm9pNBCAIDg1QQkFyIBpt1hlEQ8nqYfrLhE%3D&reserved=0. You are receiving this because you were mentioned.Message ID: @.***>

tylerflex commented 1 year ago

great!