@@ -34,6 +34,9 @@ namespace ParticleProperties{
3434 Vector<Real> Vx{}, Vy{}, Vz{};
3535 Vector<Real> Ox{}, Oy{}, Oz{};
3636 Vector<Real> _radius;
37+ Vector<Real> _radius2;
38+ Vector<Real> _radius3;
39+ Vector<int > _geometry_type;
3740 Real rd{0.0 };
3841 Vector<int > TLX{}, TLY{},TLZ{},RLX{},RLY{},RLZ{};
3942 int euler_finest_level{0 };
@@ -107,7 +110,8 @@ void calculate_phi_nodal(MultiFab& phi_nodal, kernel& current_kernel)
107110 amrex::Real Xp = current_kernel.location [0 ];
108111 amrex::Real Yp = current_kernel.location [1 ];
109112 amrex::Real Zp = current_kernel.location [2 ];
110- amrex::Real Rp = current_kernel.radius ;
113+ amrex::Real a = current_kernel.radius ;
114+ int geometry_type = current_kernel.geometry_type ;
111115
112116 // Only set the valid cells of phi_nodal
113117 for (MFIter mfi (phi_nodal,TilingIfNotGPU ()); mfi.isValid (); ++mfi)
@@ -116,19 +120,69 @@ void calculate_phi_nodal(MultiFab& phi_nodal, kernel& current_kernel)
116120 auto const & pnfab = phi_nodal.array (mfi);
117121 auto dx = ParticleProperties::dx;
118122 auto plo = ParticleProperties::plo;
119- amrex::ParallelFor (bx, [=]
120- AMREX_GPU_DEVICE (int i, int j, int k) noexcept
121- {
122- Real Xn = i * dx[0 ] + plo[0 ];
123- Real Yn = j * dx[1 ] + plo[1 ];
124- Real Zn = k * dx[2 ] + plo[2 ];
123+
124+ if (geometry_type == 1 ) {
125+ // Sphere geometry
126+ amrex::ParallelFor (bx, [=]
127+ AMREX_GPU_DEVICE (int i, int j, int k) noexcept
128+ {
129+ Real Xn = i * dx[0 ] + plo[0 ];
130+ Real Yn = j * dx[1 ] + plo[1 ];
131+ Real Zn = k * dx[2 ] + plo[2 ];
125132
126- pnfab (i,j,k) = std::sqrt ( (Xn - Xp)*(Xn - Xp)
127- + (Yn - Yp)*(Yn - Yp) + (Zn - Zp)*(Zn - Zp)) - Rp ;
128- pnfab (i,j,k) = pnfab (i,j,k) / Rp ;
133+ pnfab (i,j,k) = std::sqrt ( (Xn - Xp)*(Xn - Xp)
134+ + (Yn - Yp)*(Yn - Yp) + (Zn - Zp)*(Zn - Zp)) - a ;
135+ pnfab (i,j,k) = pnfab (i,j,k) / a ;
129136
130- }
131- );
137+ }
138+ );
139+ } else if (geometry_type == 2 ) {
140+ // Ellipsoid geometry
141+ Real b = current_kernel.radius2 ; // semi-axis b
142+ Real c = current_kernel.radius3 ; // semi-axis c
143+ amrex::ParallelFor (bx, [=]
144+ AMREX_GPU_DEVICE (int i, int j, int k) noexcept
145+ {
146+ Real Xn = i * dx[0 ] + plo[0 ];
147+ Real Yn = j * dx[1 ] + plo[1 ];
148+ Real Zn = k * dx[2 ] + plo[2 ];
149+
150+ // Relative coordinates to ellipsoid center
151+ Real xp = Xn - Xp;
152+ Real yp = Yn - Yp;
153+ Real zp = Zn - Zp;
154+
155+ // Compute ellipsoid level set function using the formula:
156+ // d ≈ (x'^2/a^2 + y'^2/b^2 + z'^2/c^2 - 1) / (2 * sqrt(x'^4/a^4 + y'^4/b^4 + z'^4/c^4))
157+ Real xp2 = xp * xp;
158+ Real yp2 = yp * yp;
159+ Real zp2 = zp * zp;
160+
161+ Real a2 = a * a;
162+ Real b2 = b * b;
163+ Real c2 = c * c;
164+
165+ Real numerator = (xp2 / a2 + yp2 / b2 + zp2 / c2) - 1.0 ;
166+
167+ Real xp4 = xp2 * xp2;
168+ Real yp4 = yp2 * yp2;
169+ Real zp4 = zp2 * zp2;
170+
171+ Real a4 = a2 * a2;
172+ Real b4 = b2 * b2;
173+ Real c4 = c2 * c2;
174+
175+ Real denominator = 2.0 * std::sqrt (xp4 / a4 + yp4 / b4 + zp4 / c4);
176+
177+ // Do not normalize here!
178+ pnfab (i,j,k) = numerator / (denominator + 1 .e -12 );
179+
180+ }
181+ );
182+ } else if (geometry_type > 2 ) {
183+ amrex::Print () << " Particle (" << current_kernel.id << " ) has unsupported geometry_type: " << geometry_type << " \n " ;
184+ amrex::Abort (" Unsupported geometry type. Only geometry_type = 1 (sphere) and 2 (ellipsoid) are supported." );
185+ }
132186 }
133187}
134188
@@ -195,9 +249,36 @@ void CalculateSumT_cir (RealVect& sum,
195249}
196250
197251[[nodiscard]] AMREX_FORCE_INLINE
198- Real cal_momentum (Real rho, Real radius)
252+ Real cal_momentum (Real rho, Real radius, int geometry_type = 1 , int idir = 0 , Real radius2 = 0.0 , Real radius3 = 0.0 )
199253{
200- return 8.0 * Math::pi<Real>() * rho * Math::powi<5 >(radius) / 15.0 ;
254+ if (geometry_type == 1 ) {
255+ // Sphere: I = (2/5) * m * r² = (8/15) * π * ρ * r⁵
256+ return 8.0 * Math::pi<Real>() * rho * Math::powi<5 >(radius) / 15.0 ;
257+ } else if (geometry_type == 2 ) {
258+ // Ellipsoid: I = (1/5) * m * (sum of squares of perpendicular semi-axes)
259+ // m = (4/3) * π * a * b * c * ρ
260+ Real a = radius;
261+ Real b = (radius2 > 0.0 ) ? radius2 : radius;
262+ Real c = (radius3 > 0.0 ) ? radius3 : radius;
263+ Real m = 4.0 * Math::pi<Real>() * rho * a * b * c / 3.0 ;
264+
265+ // Moment of inertia depends on rotation axis
266+ Real I;
267+ if (idir == 0 ) {
268+ // Rotation around x-axis (a-axis): I_x = (1/5) * m * (b² + c²)
269+ I = m * (b * b + c * c) / 5.0 ;
270+ } else if (idir == 1 ) {
271+ // Rotation around y-axis (b-axis): I_y = (1/5) * m * (a² + c²)
272+ I = m * (a * a + c * c) / 5.0 ;
273+ } else {
274+ // Rotation around z-axis (c-axis): I_z = (1/5) * m * (a² + b²)
275+ I = m * (a * a + b * b) / 5.0 ;
276+ }
277+ return I;
278+ } else {
279+ // Default to sphere for unsupported geometry types
280+ return 8.0 * Math::pi<Real>() * rho * Math::powi<5 >(radius) / 15.0 ;
281+ }
201282}
202283
203284AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
@@ -298,6 +379,9 @@ void mParticle::InitParticles(const Vector<Real>& x,
298379 const Vector<int >& RLYt,
299380 const Vector<int >& RLZt,
300381 const Vector<Real>& radius,
382+ const Vector<Real>& radius2,
383+ const Vector<Real>& radius3,
384+ const Vector<int >& geometry_type,
301385 Real h,
302386 Real gravity,
303387 int _verbose)
@@ -347,7 +431,26 @@ void mParticle::InitParticles(const Vector<Real>& x,
347431 mKernel .RL [1 ] = RLYt[real_index];
348432 mKernel .RL [2 ] = RLZt[real_index];
349433 mKernel .rho = rho_s[real_index];
434+ // geometry type
435+ if (geometry_type.size () > 0 && real_index < geometry_type.size ()) {
436+ mKernel .geometry_type = geometry_type[real_index];
437+ } else {
438+ mKernel .geometry_type = 1 ; // default to sphere if not provided
439+ }
350440 mKernel .radius = radius[real_index];
441+ // ellipsoid particle need
442+ // Check if radius2 is provided and has enough elements
443+ if (radius2.size () > 0 && real_index < radius2.size ()) {
444+ mKernel .radius2 = radius2[real_index];
445+ } else {
446+ mKernel .radius2 = radius[real_index]; // default to radius if not provided
447+ }
448+ // Check if radius3 is provided and has enough elements
449+ if (radius3.size () > 0 && real_index < radius3.size ()) {
450+ mKernel .radius3 = radius3[real_index];
451+ } else {
452+ mKernel .radius3 = radius[real_index]; // default to radius if not provided
453+ }
351454 mKernel .Vp = Math::pi<Real>() * 4 / 3 * Math::powi<3 >(radius[real_index]);
352455
353456 // int Ml = static_cast<int>( Math::pi<Real>() / 3 * (12 * Math::powi<2>(mKernel.radius / h)));
@@ -378,7 +481,7 @@ void mParticle::InitParticles(const Vector<Real>& x,
378481 if (verbose) amrex::Print () << " h: " << h << " , Ml: " << Ml << " , D: " << Math::powi<3 >(h) << " gravity : " << gravity << " \n "
379482 << " Kernel : " << index << " : Location (" << x[index] << " , " << y[index] << " , " << z[index]
380483 << " ), Velocity : (" << mKernel .velocity [0 ] << " , " << mKernel .velocity [1 ] << " , " << mKernel .velocity [2 ]
381- << " ), Radius: " << mKernel .radius << " , Ml: " << Ml << " , dv: " << dv << " , Rho: " << mKernel .rho << " \n " ;
484+ << " ), Radius: " << mKernel .radius << " , Radius2: " << mKernel . radius2 << " , Radius3: " << mKernel . radius3 << " , Ml: " << Ml << " , dv: " << dv << " , Rho: " << mKernel .rho << " \n " ;
382485 }
383486 // collision box generate
384487 m_Collision.SetGeometry (RealVect (ParticleProperties::GLO), RealVect (ParticleProperties::GHI),particle_kernels[0 ].radius , h);
@@ -791,12 +894,12 @@ void mParticle::UpdateParticles(int iStep,
791894 kernel.omega [idir] = kernel.omega_old [idir]
792895 + ((kernel.sum_t_new [idir] - kernel.sum_t_old [idir]) * ParticleProperties::euler_fluid_rho / dt
793896 - kernel.ib_moment [idir] * ParticleProperties::euler_fluid_rho
794- + kernel.Tcp [idir]) * dt / cal_momentum (kernel.rho , kernel.radius );
897+ + kernel.Tcp [idir]) * dt / cal_momentum (kernel.rho , kernel.radius , kernel. geometry_type , idir, kernel. radius2 , kernel. radius3 );
795898 }else {
796899 // Uhlmann
797900 kernel.omega [idir] = kernel.omega_old [idir]
798901 + ParticleProperties::euler_fluid_rho /(ParticleProperties::euler_fluid_rho - kernel.rho ) * kernel.ib_moment [idir] * kernel.dv
799- / cal_momentum (kernel.rho , kernel.radius ) * kernel.rho * dt;
902+ / cal_momentum (kernel.rho , kernel.radius , kernel. geometry_type , idir, kernel. radius2 , kernel. radius3 ) * kernel.rho * dt;
800903 }
801904 }
802905 else {
@@ -1035,6 +1138,9 @@ void Particles::init_particle(Real gravity, Real h)
10351138 ParticleProperties::RLY,
10361139 ParticleProperties::RLZ,
10371140 ParticleProperties::_radius,
1141+ ParticleProperties::_radius2,
1142+ ParticleProperties::_radius3,
1143+ ParticleProperties::_geometry_type,
10381144 h,
10391145 gravity,
10401146 ParticleProperties::verbose);
@@ -1067,6 +1173,9 @@ void Particles::Restart(Real gravity, Real h, int iStep)
10671173 ParticleProperties::RLY,
10681174 ParticleProperties::RLZ,
10691175 ParticleProperties::_radius,
1176+ ParticleProperties::_radius2,
1177+ ParticleProperties::_radius3,
1178+ ParticleProperties::_geometry_type,
10701179 h,
10711180 gravity,
10721181 ParticleProperties::verbose);
@@ -1164,6 +1273,9 @@ void Particles::Initialize()
11641273 p_file.getarr (" RLY" , ParticleProperties::RLY);
11651274 p_file.getarr (" RLZ" , ParticleProperties::RLZ);
11661275 p_file.getarr (" radius" , ParticleProperties::_radius);
1276+ p_file.queryarr (" radius2" , ParticleProperties::_radius2);
1277+ p_file.queryarr (" radius3" , ParticleProperties::_radius3);
1278+ p_file.queryarr (" geometry_type" , ParticleProperties::_geometry_type);
11671279 p_file.query (" RD" , ParticleProperties::rd);
11681280 p_file.query (" LOOP_NS" , ParticleProperties::loop_ns);
11691281 p_file.query (" LOOP_SOLID" , ParticleProperties::loop_solid);
0 commit comments