FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
marenv::wake::WakeField Class Referenceabstract

#include <WakeField.h>

+ Inheritance diagram for marenv::wake::WakeField:
+ Collaboration diagram for marenv::wake::WakeField:

Public Member Functions

virtual Status Sample (double t, const double pos[3], WakeSample &out) const =0
 
virtual WakeSampleParts SampleParts (double t, const double pos[3]) const
 
virtual bool MayReach (const WakeQueryRegion &region) const
 
virtual Status SampleExcluding (double t, const double pos[3], std::span< const int > excludedTags, WakeSample &out) const
 
virtual WakeSampleParts SamplePartsExcluding (double t, const double pos[3], std::span< const int > excludedTags) const
 
virtual std::uint64_t Revision () const
 
virtual bool StaticFrom (double t) const
 
virtual void SampleMany (double t, std::span< const std::array< double, 3 > > positions, std::span< WakeSample > out, std::span< Status > status) const
 
virtual void Sketch (double t, FieldSketch &out) const
 

Detailed Description

Models the effect of objects (net panels, structures, vessels) on the surrounding flow field.

A wake field is defined in the frame of its source. At a query point it returns a velocity deficit d in [0, 1] and the source velocity u_s (WakeSample). The waked velocity is u = u_amb + d (u_s - u_amb): d = 0 leaves the ambient flow undisturbed and d = 1 moves the water with the source. The velocity ratio of the KF2012 and MF2022 screen models is r = 1 - d. Because the deficit acts on the velocity relative to the source, a source towed through still water drags water along at d u_s, and a source drifting with the current casts no wake (Galilean invariance).

The field carries its own orientation (the relative-flow direction at the source), so the query takes no current direction.

When several wake fields are registered in marenv::EnvironmentFacade, their deficits compose by the momentum-flux rule, d_tot (1 - d_tot) = sum d_i (1 - d_i) (owner ruling R95, MomentumFluxSum in Superposition.h), and the combined source velocity is the deficit-weighted mean of the u_s,i. The wake acts on the current only, not on the wave particle velocity.

Example usage:

auto wake = std::make_shared<SimpleWake>();
env.AddWakeField("cage_wake", wake);
double pos[3] = {0.0, 0.0, 5.0};
env.GetWakedFlow(0.0, pos, flow); // flow.waked = flow.ambient + flow.deficit * (u_s - flow.ambient)
Definition EnvironmentFacade.h:49
Definition EnvironmentFacade.h:33

Member Function Documentation

◆ MayReach()

virtual bool marenv::wake::WakeField::MayReach ( const WakeQueryRegion &  region) const
inlinevirtual

Returns false only if the field, as published now, contributes nothing in a region (owner decision R47).

Parameters
[in]regionThe sphere and time interval of the queries, and the cutoff.
Returns
False only if Sample(t, pos) gives d = 0 (region.cutoff = 0) or d < region.cutoff (region.cutoff > 0), or a status other than OK, for every pos in the sphere and every t in [region.tBegin, region.tEnd]; true otherwise, or when the field cannot tell.

A blending field counts the snapshot it blends to from the publish instant on, though its weight is 0 there, so the answer also covers SampleParts() taken in the interval and composed at a later time (R136). The answer holds for the state published at the call; a later Publish() voids it. The default returns true, so a field without a reach test is never culled. SourceSetWake implements it. Const and thread-safe, as Sample().

◆ Revision()

virtual std::uint64_t marenv::wake::WakeField::Revision ( ) const
inlinevirtual

Returns a number that changes whenever the field is published again (the change signal of a visualiser).

Returns
0 before the first publish, then a count that grows with every publish; a field that cannot tell returns 0 and false from StaticFrom(), so a caller never relies on it.

Between two changes of the revision Sample() may still change with t: during a blend, and for a field whose frame moves (StaticFrom()). SourceSetWake and GriddedWake count their publishes. Const and thread-safe, as Sample().

◆ Sample()

virtual Status marenv::wake::WakeField::Sample ( double  t,
const double  pos[3],
WakeSample &  out 
) const
pure virtual

Returns the wake deficit and source velocity at a given position and time (contract C4).

Parameters
[in]tSimulation time, s.
[in]posPosition (x,y,z) to query, m, NED.
[out]outDeficit in [0, 1] and source velocity at pos.
Returns
marenv::Status::OK on success; Status::ERROR_NOT_SET, which means d = 0, before the first Publish() and, for a field with an extent (GriddedWake), outside it. The direct field (SourceSetWake, after its first blend has started) has no extent and returns OK with d = 0 far from its sources (MENV-0014). See marenv::Status for other values.

Threading contract, for every implementation:

  • Registration (EnvironmentFacade::AddWakeField, RemoveWakeField) happens during setup only; the facade's registry is not synchronised.
  • After registration, one writer thread may update the field (Publish()) concurrently with any number of reader threads calling Sample().
  • Sample() is const and thread-safe. It reads one immutable snapshot, so a query that runs during an update returns the old or the new state, never a mix. It takes no mutex.

Known caveat: the snapshot fields hold their snapshot in std::atomic<std::shared_ptr<const ...>>, as marenv::wave::LinearWaveTheory does. libstdc++ implements it with a spin bit in the control pointer (is_lock_free() is false), held while load() or store() updates the reference count, so a query can spin briefly against another thread's load or store. Test W8 (tests/WakeThreading_Test.cpp) checks the contract under the MARENV_TSAN build.

Implemented in environment::NetCageWakeField.

◆ SampleExcluding()

virtual Status marenv::wake::WakeField::SampleExcluding ( double  t,
const double  pos[3],
std::span< const int >  excludedTags,
WakeSample &  out 
) const
inlinevirtual

Returns the sample at a position and time with the sources of the given tags left out (ENV-0107; contract C4).

Parameters
[in]tSimulation time, s.
[in]posPosition (x,y,z) to query, m, NED.
[in]excludedTagsThe ElementarySource::tag values of the sources to leave out; a negative tag (kUntaggedSource) leaves out nothing.
[out]outAs Sample().
Returns
As Sample().

A caster's own sample point uses it to leave out its own sources of the caster's private field, which it may have overtaken since the field was built (fhsim_environment ENV-0107, "direct-only exclusion"). Only a field that evaluates its tagged sources directly (SourceSetWake) can leave one out; with no tag to leave out it is Sample() bit for bit. The default, for every other field, is Sample(): it ignores the tags. A GriddedWake holds only the summed log ratio of its sources at the nodes, so it cannot take one source out (fhsim_environment ENV-0107, ENV-0108). Const and thread-safe, as Sample().

◆ SampleMany()

virtual void marenv::wake::WakeField::SampleMany ( double  t,
std::span< const std::array< double, 3 > >  positions,
std::span< WakeSample >  out,
std::span< Status >  status 
) const
inlinevirtual

Samples many points at one time: as Sample() at each, out[i] and status[i] for positions[i].

Parameters
[in]tSimulation time, s.
[in]positionsThe points, m, NED.
[out]outOne sample per point; as many as positions.
[out]statusOne status per point; as many as positions.

The default calls Sample() at each point. SourceSetWake, GriddedWake and PropellerJet load their published state once for all the points, which is what makes sampling a grid from several threads scale: per point, every thread would update the same reference count. Const and thread-safe, as Sample().

◆ SampleParts()

virtual WakeSampleParts marenv::wake::WakeField::SampleParts ( double  t,
const double  pos[3] 
) const
inlinevirtual

Returns the sample at a position and time split into the parts its blend weighs, to compose at a later time (owner ruling R136; contract C4).

Parameters
[in]tSample time, s.
[in]posPosition (x,y,z) to query, m, NED.
Returns
The parts; WakeSampleParts::At(t2) for t2 >= t gives the deficit and source velocity of the snapshots at (t, pos) with the blend weight of t2. Where the field does not blend at t or later, At(t2) is Sample(t, pos) bit for bit for every t2.

The default holds Sample(t, pos), for a field without a blend. SourceSetWake and GriddedWake return the samples of the snapshot blended to and of the state blended from while they blend. Const and thread-safe, as Sample(); it reads one snapshot of the published state.

◆ SamplePartsExcluding()

virtual WakeSampleParts marenv::wake::WakeField::SamplePartsExcluding ( double  t,
const double  pos[3],
std::span< const int >  excludedTags 
) const
inlinevirtual

Returns SampleParts() with the sources of the given tags left out, as SampleExcluding() (ENV-0107; contract C4).

The default, for a field that cannot leave a source out, is SampleParts(): it ignores the tags.

◆ Sketch()

virtual void marenv::wake::WakeField::Sketch ( double  t,
FieldSketch &  out 
) const
inlinevirtual

Appends where the field's sources are at t, or how far its grid reaches, for a visualiser (FieldSketch).

Only the snapshot blended to is sketched. SourceSetWake sketches its point and line sources, GriddedWake its grid; the default, for a field that cannot tell, appends nothing, and so does a field before its first publish. Const and thread-safe, as Sample().

◆ StaticFrom()

virtual bool marenv::wake::WakeField::StaticFrom ( double  t) const
inlinevirtual

Returns true only if Sample(t2, pos) is the same for every t2 >= t and every pos until Revision() changes.

True when no blend runs at t or later and every snapshot sampled from t on is at rest (frame velocity 0); also before the first publish, which changes the revision. The default, for a field that cannot tell, returns false. Const and thread-safe, as Sample().


The documentation for this class was generated from the following file: