This commit is contained in:
2025-09-12 15:20:28 +08:00
commit 3257a14c32
449 changed files with 388780 additions and 0 deletions

View File

@@ -0,0 +1,255 @@
# ****************************************************************************
# CUI
#
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
#
# The use, dissemination or disclosure of data in this file is subject to
# limitation or restriction. See accompanying README and LICENSE for details.
# ****************************************************************************
behavior create_clustering_jobs
script_debug_writes off
script_variables
##########################################################################
## user parameters, change these at will
##########################################################################
bool mDrawClusters = false;
int mMaxJobWinners = 1;
string mClusterMethod = "H_TREE_MAX"; //valid: K_MEANS, H_TREE_MIN, H_TREE_MAX
string mDistanceFunction = "POSITION_VELOCITY"; //valid: POSITION_VELOCITY, POSITION_ONLY, 2D_POSITION
double mClusterDistanceLimit = 50*1852; // ~50 nautical miles
int mNumClusters = -1; //not used unless positive (over-rides distance limit)
double mClusterJobPriority = 1; //if set to zero or less, then number of cluster occupants will be the priority
bool mRequireKnownCategory = false; //if set to true, only threats of a known category will be clustered
##########################################################################
## script variables, used by methods below, do not change
##########################################################################
Array<WsfTrack> trackArray = Array<WsfTrack>();
Map<int, int> mJobToWinnerMap = Map<int, int>();
WsfDraw draw = WsfDraw();
WsfClusterManager cManager;
end_script_variables
on_init
cManager = WsfClusterManager.Create(); // creates a cluster manager owned by this script
cManager.SetClusterMethod(mClusterMethod);
cManager.SetDistanceLimit(mClusterDistanceLimit);
if (mNumClusters > 0)
{
cManager.SetNumClustersToCreate(mNumClusters);
}
else
{
cManager.SetDistanceFunction(mDistanceFunction);
}
end_on_init
precondition
writeln_d("precondition create_clustering_jobs");
draw.SetDuration(PROCESSOR.UpdateInterval());
##########################################################################
## only update cluster jobs during a bid window
##########################################################################
if ((!(PROCESSOR.IsBidWindowOpen())) || PROCESSOR.IsJobWindowOpen())
{
writeln_d("GCI agent will not change zone (cluster) jobs unless bid window open & job window closed!");
return Failure("bid window closed or job window open");
}
return true;
end_precondition
############################################################################
## utility method used to draw lines around tracks in a cluster
## lines are drawn according to the convex hull of the cluster members
############################################################################
script void draw_cluster_hull(WsfCluster cluster)
Array<WsfGeoPoint> pts = cluster.ConvexHull();
if (pts.Size() <= 0)
{
return;
}
WsfGeoPoint first = pts.Get(0);
draw.SetColor(1.0,0.5,0.0); //orange?
draw.SetLineStyle("solid");
draw.SetLineSize(2);
draw.BeginPolyline();
for (int j = 0; j < pts.Size(); j = j + 1 )
{
WsfGeoPoint pt = pts.Get(j);
draw.Vertex(pt);
}
draw.Vertex(first);
draw.End();
end_script
############################################################################
## utility method used to add a cluster job
############################################################################
script void add_cluster_job(WsfCluster cluster)
#new cluster, job not created yet, so create one
int occupants = cluster.Count();
int clusterId = cluster.Id();
string jobName = "cluster_" + (string)clusterId;
double ClusterPriority = mClusterJobPriority;
if (ClusterPriority <= 0)
{
ClusterPriority = (double)occupants;
}
WsfRIPRJob temp = WsfRIPRJob.Create( PROCESSOR,
"zone",
jobName,
ClusterPriority,
mMaxJobWinners );
temp.SetData( "clusterId", clusterId );
temp.SetData( "ZoneName", jobName );
temp.SetData( "ZonePoint", WsfGeoPoint(cluster.MeanLocation()) );
temp.SetData( "ZoneBearing", cluster.Bearing() );
temp.SetData( "ZoneBearingValid", cluster.BearingValid() );
temp.SetData( "ZoneNumThreats", occupants );
temp.SetData( "for_air", 1 );
Array<string> arr = Array<string>();
for (int i = 0; i < occupants; i = i + 1 )
{
arr.PushBack(cluster.Entry(i).TargetName());
writeln_d("job cluster member: ", cluster.Entry(i).TargetName());
}
temp.SetData( "ZoneThreatNameArray", arr );
PROCESSOR.AddJob(temp);
writeln_d("+++ ", PLATFORM.Name(), " job change, ADD: ", temp.Name(), ", id: ", clusterId);
end_script
############################################################################
## utility method used to remove a cluster job
############################################################################
script void remove_cluster_job(WsfRIPRJob aJob)
int clusterId = (int)aJob.GetData("clusterId");
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", aJob.GetDescription(), ", id: ", clusterId);
PROCESSOR.RemoveJob( aJob );
end_script
############################################################################
## utility method used to update a cluster job
## returns true if job exists & was updated
## returns false if job by that name does not exist
############################################################################
script bool update_cluster_job(WsfCluster cluster)
int clusterId = cluster.Id();
WsfRIPRJob aJob = PROCESSOR.GetJobByData("clusterId", clusterId);
if (aJob.IsValid())
{
//if we are here, the cluster job is identified as having same list of threats
//so these data are the same: job priority, ZoneNumThreats, ZoneThreatNameArray,
aJob.SetData( "ZonePoint", WsfGeoPoint(cluster.MeanLocation()) );
aJob.SetData( "ZoneBearing", cluster.Bearing() );
aJob.SetData( "ZoneBearingValid", cluster.BearingValid() );
return true;
}
return false;
end_script
execute
writeln_d(PLATFORM.Name(), " executing create_clustering_jobs, T=", TIME_NOW);
##########################################################################
## update the cluster manager with the current master track list
##########################################################################
extern bool TestTrackCategory( WsfTrack, string );
WsfLocalTrackList localTracks = PLATFORM.MasterTrackList();
trackArray.Clear();
foreach (WsfTrack track in localTracks)
{
if (!mRequireKnownCategory || !TestTrackCategory(track, "unknown"))
{
track.SetBearing( track.Heading() ); #useful for the cluster processing
trackArray.PushBack(track);
}
}
cManager.UpdateClusters(TIME_NOW,trackArray);
##########################################################################
## update or add jobs for all the clusters
##########################################################################
Map<int, int> updatedJobs = Map<int, int>();
int NumClusters = cManager.Count();
for (int i = 0; i < NumClusters; i = i + 1 )
{
WsfCluster cluster = cManager.Entry(i);
int clusterId = cluster.Id();
if (mDrawClusters == true)
{
draw_cluster_hull(cluster);
}
if( cluster.Count() > 0 )
{
if (update_cluster_job(cluster))
{
//writeln_d("cluster already exists & was updated!");
}
else
{
add_cluster_job(cluster);
}
updatedJobs.Set(clusterId, 1);
}
}
##########################################################################
## remove any old jobs for clusters that have gone away
##########################################################################
Array<WsfRIPRJob> jobs = PROCESSOR.GetJobs();
foreach( WsfRIPRJob aJob in jobs )
{
if (aJob.Name() == "zone")
{
int clusterId = (int)aJob.GetData("clusterId");
if (updatedJobs.Get(clusterId) != 1)
{
remove_cluster_job( aJob );
}
}
}
##########################################################################
## print out a message if there are any new winners of jobs
##########################################################################
jobs = PROCESSOR.GetJobs();
foreach( WsfRIPRJob aJob in jobs )
{
if( ! mJobToWinnerMap.Exists( aJob.GetId() ) )
{
mJobToWinnerMap.Set( aJob.GetId(), 0 );
}
else
{
int currWinners = aJob.GetNumWinners();
int lastWinners = mJobToWinnerMap.Get( aJob.GetId() );
if( currWinners != lastWinners )
{
string NewComment = "AIGCI - Sub took a job: " + aJob.Name() + " - " + aJob.GetDescription();
PLATFORM.Comment(NewComment);
mJobToWinnerMap.Set( aJob.GetId(), currWinners );
}
}
}
end_execute
end_behavior

View File

@@ -0,0 +1,259 @@
# ****************************************************************************
# CUI
#
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
#
# The use, dissemination or disclosure of data in this file is subject to
# limitation or restriction. See accompanying README and LICENSE for details.
# ****************************************************************************
behavior create_flank_jobs
script_debug_writes off
script_variables
WsfDraw draw = WsfDraw();
Array<Vec3> mBowTieZonePoints = Array<Vec3>();
Map<int, int> mFlankToClusterMap = Map<int, int>();
Map<int, int> mClusterToFlankMap = Map<int, int>();
Array<string> mCompletedFlanks = Array<string>();
Map<string, double> mFlankNameToTimeCompleteMap = Map<string, double>();
int mMaxTotalFlankJobsEverToCreate = 1;
int mMaxJobWinnersForFlank = 2;
double mFlankJobPriorityScale = 1.5; // make > 1 for more important than clusters
double cFLANK_DISTANCE = 60.0; // flank towards a point approximately this many nm to the side of target
int mFlankJobsCreated = 0; // utility variable, not a constant to set
int mFlankJobsCompleted = 0; // utility variable, not a constant to set
//after a completed flank on a cluster, don't do another on that same cluster until this time passes
double mFlankRepeatDelay = 300.0; //in units of seconds
end_script_variables
on_init
double FlankDistanceMeters = cFLANK_DISTANCE * MATH.M_PER_NM();
//create simple bowtie shape, based on specified size parameters
double w1 = 2.0 * FlankDistanceMeters; //Bow Tie Width (meters)
double h2 = 0.75 * FlankDistanceMeters; //Bow Tie Outter Thickness (meters)
double h1 = 0.5 * h2; //Bow Tie Inner Thickness (meters)
mBowTieZonePoints.PushBack(Vec3.Construct( h1, 0, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( h2, w1, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( -h2, w1, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( -h1, 0, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( -h2, -w1, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( h2, -w1, 0));
end_on_init
# #
# # script callback method for when a flank job is completed
# # the job board calls this when a flank job that it owns has been marked as complete
# #
# script void aigci_flank_complete(int jobID)
# //save job in completed array
# //remove job from created array
# WsfRIPRJob aJob = PROCESSOR.GetJobById( jobID );
# writeln_d("~~~ Flank Job Completed: ", aJob.GetDescription());
# mCompletedFlanks.PushBack( aJob.Name() );
#
# mFlankNameToTimeCompleteMap.Set( aJob.Name(), TIME_NOW );
#
# int clusterId = mFlankToClusterMap.Get( jobID );
# mFlankToClusterMap.Erase( jobID );
# mClusterToFlankMap.Erase( clusterId );
#
# mFlankJobsCompleted = mFlankJobsCompleted + 1;
# end_script
precondition
writeln_d("precondition create_flank_jobs");
//check if this gci is done creating & updating the flank jobs
if( mFlankJobsCompleted >= mMaxTotalFlankJobsEverToCreate )
{
writeln_d( "~~~ aiGCI - Max Flank Jobs Completed, return now!" );
return Failure("max number of flank jobs already created and completed");
}
draw.SetDuration(PROCESSOR.UpdateInterval());
return true;
end_precondition
execute
writeln_d("executing create_flank_jobs");
########################################################################
## check for clusters that went away & we can't flank them anymore
## otherwise, update any existing flank jobs
########################################################################
foreach( int flankJobId : int clusterJobId in mFlankToClusterMap )
{
WsfRIPRJob flankJob = PROCESSOR.GetJobById( flankJobId );
WsfRIPRJob clusterJob = PROCESSOR.GetJobById( clusterJobId );
if( clusterJob.IsValid() )
{
if( flankJob.IsValid() )
{
if (flankJob.GetBestProgress() >= 1.0 )
{
writeln("GCI removing completed flank job!!!");
mCompletedFlanks.PushBack( flankJob.Name() );
mFlankNameToTimeCompleteMap.Set( flankJob.Name(), TIME_NOW );
int flankId = flankJob.GetId();
int clusterId = mFlankToClusterMap.Get( flankId );
mFlankToClusterMap.Erase( flankId );
mClusterToFlankMap.Erase( clusterId );
mFlankJobsCompleted = mFlankJobsCompleted + 1;
mFlankToClusterMap.Remove( flankId );
mClusterToFlankMap.Remove( clusterId );
PROCESSOR.RemoveJob( flankJob );
}
else
{
writeln_d( "~~~ aiGCI - updating flank job ", flankJob.Name(), " with cluster ", clusterJob.Name(), "!!!" );
writeln_d("best flank progress: ", flankJob.GetBestProgress());
WsfGeoPoint point = (WsfGeoPoint)clusterJob.GetData("ZonePoint");
double bearing = (double)clusterJob.GetData("ZoneBearing");
bool bearingValid = (bool)clusterJob.GetData("ZoneBearingValid");
//writeln_d( "~~~ aiGCI - flank job BEARING: ", bearing );
string flankZoneName = "flank" + clusterJob.Name();
//writeln(PLATFORM.Name(), " UpdateFlankZone( ", TIME_NOW, ", ", flankZoneName, ", ", point.ToString(), ", ", bearing, ", ", cFLANK_DISTANCE);
//now the wsfzone can be treated as a relative zone, and doesn't need updating
//UpdateFlankZone( TIME_NOW, flankZoneName, point, bearing, cFLANK_DISTANCE );
//update the flank job with relevant cluster information
flankJob.Priority( (mFlankJobPriorityScale * clusterJob.GetPriority()) );
flankJob.SetData( "FlankZoneName", flankZoneName );
flankJob.SetData( "ZonePoint", WsfGeoPoint(point) );
flankJob.SetData( "ZoneBearing", bearing );
flankJob.SetData( "ZoneBearingValid", bearingValid );
flankJob.SetData( "ZoneNumThreats", (int)clusterJob.GetData("ZoneNumThreats") );
}
}
else
{
writeln_d( "~~~ aiGCI - cluster valid, but flank not valid!" );
}
}
else
{
//remove flank job, cluster went away
if (flankJob.IsValid())
{
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", flankJob.Name() );
PROCESSOR.RemoveJob( flankJob );
if( mFlankJobsCreated > 0 )
{
mFlankJobsCreated = mFlankJobsCreated - 1;
}
}
mFlankToClusterMap.Remove( flankJobId );
mClusterToFlankMap.Remove( clusterJobId );
}
}
//check if only the updates were needed, or if we can create more flank jobs
if( mFlankJobsCreated >= mMaxTotalFlankJobsEverToCreate )
{
writeln_d( "~~~ aiGCI - max flank jobs created, no need for more!" );
return;
}
########################################################################
## create a new flank job if a cluster exists that never had one
## locate the nearest available cluster
########################################################################
double DistClosestCluster = MATH.DOUBLE_MAX();
WsfRIPRJob JobWithClusterToFlank;
Array<WsfRIPRJob> jobs = PROCESSOR.GetJobs();
foreach (WsfRIPRJob aJob in jobs)
{
//if job is a cluster job (not a flank job) & is not being flanked already
//then consider it as a candidate for flanking, else continue
if( mFlankToClusterMap.Exists( aJob.GetId() ) || mClusterToFlankMap.Exists( aJob.GetId() ) )
{
//writeln_d( "~~~ aiGCI - job ", aJob.Name(), " is either a flank job or a zone thats already being flanked!" );
continue;
}
//if enough time hasn't elapsed since the last flank performed on this cluster, then continue
//this prevents the agent from re-creating flank jobs that were just completed and removed
string newFlankName = "flank" + aJob.Name();
if( mFlankNameToTimeCompleteMap.Exists( newFlankName ) )
{
double lastFlankTime = mFlankNameToTimeCompleteMap.Get( newFlankName );
if( TIME_NOW < (lastFlankTime + mFlankRepeatDelay) )
{
continue;
}
}
WsfGeoPoint cPoint = (WsfGeoPoint)aJob.GetData("ZonePoint");
double dist = PLATFORM.GroundRangeTo(cPoint);
if( dist < DistClosestCluster )
{
JobWithClusterToFlank = aJob;
}
}
if( JobWithClusterToFlank.IsValid() )
{
WsfGeoPoint clusterPoint = (WsfGeoPoint)JobWithClusterToFlank.GetData("ZonePoint");
double clusterBearing = (double)JobWithClusterToFlank.GetData("ZoneBearing");
bool clusterBearingValid = (bool)JobWithClusterToFlank.GetData("ZoneBearingValid");
int clusterOccupants = (int)JobWithClusterToFlank.GetData("ZoneNumThreats");
string clusterZoneName = (string)JobWithClusterToFlank.GetData("ZoneName");
string flankZoneName = "flank" + JobWithClusterToFlank.Name();
WsfRIPRJob NewFlankJob = WsfRIPRJob.Create( PROCESSOR,
"flank",
flankZoneName,
(mFlankJobPriorityScale * JobWithClusterToFlank.GetPriority()),
mMaxJobWinnersForFlank );
NewFlankJob.SetData( "ZoneName", clusterZoneName );
NewFlankJob.SetData( "FlankZoneName", flankZoneName );
NewFlankJob.SetData( "ZonePoint", WsfGeoPoint(clusterPoint) );
NewFlankJob.SetData( "ZoneBearing", clusterBearing );
NewFlankJob.SetData( "ZoneBearingValid", clusterBearingValid );
NewFlankJob.SetData( "ZoneNumThreats", clusterOccupants );
double FlankDistanceMeters = cFLANK_DISTANCE * MATH.M_PER_NM();
NewFlankJob.SetData( "FlankDistance", (1.8 * FlankDistanceMeters) ); //pursue a point 10% inside the flank zone, the flank width is 2*FlankDist
#NewFlankJob.SetData( "OnJobComplete", "aigci_flank_complete" );
NewFlankJob.SetData( "for_air", 1 );
WsfZone flankZone = WsfZone.CreatePolygonal(PLATFORM, mBowTieZonePoints); //creates a relative zone
NewFlankJob.SetData( "FlankZone", flankZone );
PROCESSOR.AddJob(NewFlankJob);
writeln_d("+++ ", PLATFORM.Name(), " job change, ADD: ", NewFlankJob.Name() );
mFlankJobsCreated = mFlankJobsCreated + 1;
//save link between the flank & the cluster thats being flanked
mFlankToClusterMap.Set( NewFlankJob.GetId(), JobWithClusterToFlank.GetId() );
mClusterToFlankMap.Set( JobWithClusterToFlank.GetId(), NewFlankJob.GetId() );
}
end_execute
end_behavior

View File

@@ -0,0 +1,294 @@
# ****************************************************************************
# CUI
#
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
#
# The use, dissemination or disclosure of data in this file is subject to
# limitation or restriction. See accompanying README and LICENSE for details.
# ****************************************************************************
#it is assumed that all weapons on the platform this agent is on... are alert-5 aircraft
#when it launches an alert-5 aircraft, it will find the first one available & fire
behavior launch_alert-5_aircraft
script_debug_writes off
script_variables
//public
string mFlightLeadToSupport = "fighter_flight_lead";
int mSalvoCount = 2;
//private
bool mLaunched = false;
end_script_variables
#on_init
#end_on_init
script WsfWeapon GetNextAlert5()
WsfWeapon empty;
for(int i=0; i<PLATFORM.WeaponCount(); i=i+1)
{
WsfWeapon test = PLATFORM.WeaponEntry(i);
if (test.QuantityRemaining() >= 1)
{
return test;
}
}
return empty;
end_script
script WsfRIPRProcessor GetRIPR(string platformName)
WsfRIPRProcessor empty;
WsfPlatform plat = WsfSimulation.FindPlatform(platformName);
if (plat.IsValid())
{
for (int i=0; i<plat.ProcessorCount(); i=i+1)
{
WsfProcessor proc = plat.ProcessorEntry(i);
if (proc.IsA_TypeOf("WSF_RIPR_PROCESSOR"))
{
WsfRIPRProcessor rProc = (WsfRIPRProcessor)proc;
return rProc;
}
}
}
return empty;
end_script
script bool LaunchAlert_5(WsfWeapon alert5Weapon, int salvo)
WsfGeoPoint pt = PLATFORM.Location();
pt.Offset(PLATFORM.Heading(), 9260, 0.0, -9260);
WsfTrack tgt = WsfTrack();
tgt.SetLocation(pt);
return alert5Weapon.FireSalvo(tgt, salvo);
end_script
precondition
writeln_d("precondition launch_alert-5_aircraft");
if (mLaunched==true)
{
writeln_d("already launched alert5 aircraft!");
return Failure("already launched alert5 aircraft!");
}
WsfWeapon test = GetNextAlert5();
if (!test.IsValid())
{
writeln_d("no alert5 aircraft available to launch!");
return Failure("no alert5 aircraft available to launch!");
}
WsfRIPRProcessor proc = GetRIPR(mFlightLeadToSupport);
if (proc.IsValid())
{
WsfRIPRJob job = proc.GetRIPRCommanderProcessor().GetJobFor(TIME_NOW, proc);
if( job.IsValid())
{
return true;
}
}
else
{
writeln_d("flight lead not found: ", mFlightLeadToSupport);
return Failure("flight lead not found!");
}
writeln_d("flight lead does not need support yet!");
return Failure("flight lead does not need support yet!");
end_precondition
execute
writeln_d("executing launch_alert-5_aircraft");
mLaunched = LaunchAlert_5(GetNextAlert5(), mSalvoCount);
end_execute
end_behavior
#it is assumed that all weapons on the platform this agent is on... are alert-5 aircraft
#when it launches an alert-5 aircraft, it will find the first one available & fire
behavior launch_alert-5_aircraft2
script_debug_writes off
script_variables //public
#string mFlightLeadToSupport = "fighter flightjlead";
int mSalvoCount = 2;
double mFlightLaunchDelay = 120.0; # 30 sec per a/c, 2 a/c per flight
bool mFirstLaunch = true;
double mFirstFlightLaunchDelay = 420.0; #account for 5 minute delay of first launch //private
double mLastLaunchedTime = -9999.0;
int mNumberOfAirThreats = 0;
int mNumberOfSubsInAir = 0;
bool mCheckPeers = true;
string mProtectZoneName = "";
double mProtectRange = 1852 * 100; //100nm (in meters)
end_script_variables
# #on init #end on init
# script bool ValidType(WsfTrack track)
# if (track.Target().IsValid())
# {
# if (track.Target().Type() == "STRIKER" || track.Target().Type() == "SWEEPER" || track.Target().Type() == "CAPPER" || track.Target().IsATypeOf("E-3C"))
# {
# return true;
# }
# }
# return false;
# end_script
script WsfWeapon GetNextAlert5()
WsfWeapon empty;
for(int i=0; i<PLATFORM.WeaponCount(); i=i+l)
{
WsfWeapon test = PLATFORM.WeaponEntry(i);
if (test.QuantityRemaining() >= 1)
{
return test;
}
}
return empty;
end_script
script bool AnyActiveRequests()
for(int i=0; i<PLATFORM.WeaponCount(); i=i+l)
{
WsfWeapon test = PLATFORM.WeaponEntry(i);
if (test.ActiveRequestCount() > 0)
{
return true;
}
}
return false;
end_script
# script WsfRIPRProcessor GetRIPR(string platformName)
# WsfRIPRProcessor empty;
# WsfPlatform plat = WsfSimulation.FindPlatform(platformName);
# if (plat.IsValid())
# {
# for (int i=0; i<plat.ProcessorCount(); i=i+l)
# {
# WsfProcessor proc = plat.ProcessorEntry(i);
# if (proc.IsA TypeOf("WSFRIPRPROCESSOR"))
# {
# WsfRIPRProcessor rProc = (WsfRIPRProcessor)proc;
# return rProc;
# }
# }
# }
# return empty;
precondition
writelnd("T= ",TIME NOW,", ", PLATFORM.Name()," precondition launch_alert-5 aircraft");
WsfWeapon test = GetNextAlert5();
if (!test.IsValid())
{
writelnd("T= ", TIME NOW," no alert5 aircraft available to launch!");
return Failure("no alert5 aircraft available to launch!");
}
if (AnyActiveRequests())
{
writeln_d("currently launching something");
return Failure("currently launching something");
}
mNumberOfAirThreats = 0; //check num threats every time foreach (WsfTrack track in PLATFORM.MasterTrackList())
if ((track.TimeSinceUpdated() < 60.0) &&
(track.LocationValid() || (track.RangeValid() && track.BearingValid())) &&
#(ValidType(track)) &&
((mProtectZoneName != "" || track.WithinZoneOf(PLATFORM, mProtectZoneName)) || PLATFORM.GroundRangeTo(track) < mProtectRange))
{
mNumberOfAirThreats = mNumberOfAirThreats + 1;
writeln_d("threat: ", track.TargetName());
}
if (mCheckPeers == true)
{
mNumberOfSubsInAir = 0; //reset here, & then count
WsfPlatform commander = PLATFORM.Commander();
if (!commander.IsValid())
{
writeln_d("no commander!");
return Failure("no commander!");
}
foreach (WsfPlatform sub in commander.Subordinates())
{
if (sub.Type() == "FLIGHT_LEAD_RED") # for each flight lead
{
foreach (WsfPlatform airInt in sub.Subordinates()) # for each airborne interceptor
{
if (airInt.AuxDataExists("ENGAGING") && airInt.AuxDataBool("ENGAGING"))
{
mNumberOfSubsInAir = mNumberOfSubsInAir + 1;
writeln_d("subordinate: ", airInt.Name());
}
else
{
writeln_d("not engaging: ", airInt.Name());
}
}
}
}
}
else
{
mNumberOfSubsInAir = 0; //reset here, & then count
foreach (WsfPlatform airInt in PLATFORM.Subordinates()) # for each airborne interceptor
{
if (airInt.AuxDataExists("ENGAGING") && airInt.AuxDataBool("ENGAGING"))
{
mNumberOfSubsInAir = mNumberOfSubsInAir + 1;
writeln_d("subordinate: ", airInt.Name());
}
else
{
writeln_d("not engaging: ", airInt.Name());
}
}
}
if (mNumberOfAirThreats <= mNumberOfSubsInAir)
{
writeln_d("T= ",TIME_N0W," ", PLATFORM.Name(),", enough subordinates in air already for threats!");
return Failure("enough subordinates in air already for threats!");
}
double delay = mFlightLaunchDelay;
if (mFirstLaunch == true)
{
delay = mFirstFlightLaunchDelay;
}
if ((TIME_NOW-mLastLaunchedTime) < delay)
{
writeln_d("T= ",TIME NOW," Still launching previous flight!");
return Failure("Still launching previous flight!");
}
return true;
end_precondition
execute
writeln_d("T= ", TIME_NOW," executing launch_alert-5_aircraft");
WsfGeoPoint pt = PLATFORM.Location();
pt.Offset(PLATFORM.Heading(), 9260, 0.0, -9260);
WsfTrack tgt = WsfTrack();
tgt.SetLocation(pt);
WsfWeapon alert5Weapon = GetNextAlert5();
if (alert5Weapon.FireSalvo(tgt, mSalvoCount))
{
if (mLastLaunchedTime > 0)
{
mFirstLaunch = false;
}
mLastLaunchedTime = TIME_NOW;
PLATFORM.Comment("Launch Alert 5");
}
end_execute
end_behavior

View File

@@ -0,0 +1,206 @@
# ****************************************************************************
# CUI
#
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
#
# The use, dissemination or disclosure of data in this file is subject to
# limitation or restriction. See accompanying README and LICENSE for details.
# ****************************************************************************
processor GCI_QUANTUM_TASKER WSF_QUANTUM_TASKER_PROCESSOR
update_interval 10.0 sec
script_variables
##########################################################################
## user parameters, change these at will
##########################################################################
bool mDrawClusters = false;
bool mRequireTasking = false;
int mMaxTaskPerformers = 1;
string mClusterMethod = "H_TREE_MAX"; //valid: K_MEANS, H_TREE_MIN, H_TREE_MAX
string mDistanceFunction = "POSITION_VELOCITY"; //valid: POSITION_VELOCITY, POSITION_ONLY, 2D_POSITION
double mClusterDistanceLimit = 50*1852; // ~50 nautical miles
int mNumClusters = -1; //not used unless positive (over-rides distance limit)
double mClusterJobPriority = 1; //if set to zero or less, then number of cluster occupants will be the priority
##########################################################################
## script variables, used by methods below, do not change
##########################################################################
WsfDraw draw = WsfDraw();
WsfClusterManager cManager;
end_script_variables
on_initialize
cManager = WsfClusterManager.Create(); // creates a cluster manager owned by this script
cManager.SetClusterMethod(mClusterMethod);
cManager.SetDistanceLimit(mClusterDistanceLimit);
if (mNumClusters > 0)
{
cManager.SetNumClustersToCreate(mNumClusters);
}
else
{
cManager.SetDistanceFunction(mDistanceFunction);
}
end_on_initialize
############################################################################
## utility method used to draw lines around tracks in a cluster
## lines are drawn according to the convex hull of the cluster members
############################################################################
script void draw_cluster_hull(WsfCluster cluster)
Array<WsfGeoPoint> pts = cluster.ConvexHull();
if (pts.Size() <= 0)
{
return;
}
WsfGeoPoint first = pts.Get(0);
draw.SetDuration(PROCESSOR.UpdateInterval());
draw.SetColor(1.0,0.5,0.0); //orange?
draw.SetLineStyle("solid");
draw.SetLineSize(2);
draw.BeginPolyline();
for (int j = 0; j < pts.Size(); j = j + 1 )
{
WsfGeoPoint pt = pts.Get(j);
draw.Vertex(pt);
}
draw.Vertex(first);
draw.End();
end_script
script Array<WsfQuantumTask> GciCommanderTaskGeneration (Array<WsfLocalTrack> TRACKS, Array<WsfAssetPerception> ASSETS )
//create weapon tasks for enemy track groups (clusters)
Array<WsfQuantumTask> tasks = Array<WsfQuantumTask>();
writeln_d(PLATFORM.Name(), " executing GciCommanderTaskGeneration(), T=", TIME_NOW);
##########################################################################
## update the cluster manager with the current master track list
##########################################################################
WsfLocalTrackList localTracks = PLATFORM.MasterTrackList();
Array<WsfTrack> trackArray = Array<WsfTrack>();
foreach (WsfLocalTrack lt in localTracks)
{
if (mRequireTasking == true && TasksReceivedForTarget(lt.TrackId()).Count() <= 0)
{
continue;
}
if (lt.IsValid() && (!lt.SideValid() || lt.Side() != PLATFORM.Side()))
{
lt.SetBearing( lt.Heading() ); #useful for the cluster processing
trackArray.PushBack(lt);
}
}
cManager.UpdateClusters(TIME_NOW,trackArray);
##########################################################################
## generate a task for each clusters
##########################################################################
int NumClusters = cManager.Count();
for (int i = 0; i < NumClusters; i = i + 1 )
{
WsfCluster cluster = cManager.Entry(i);
int clusterId = cluster.Id();
if (mDrawClusters == true)
{
draw_cluster_hull(cluster);
}
if( cluster.Count() > 0 )
{
double ClusterPriority = mClusterJobPriority;
if (ClusterPriority <= 0)
{
ClusterPriority = (double)cluster.Count();
}
WsfQuantumTask qt = WsfQuantumTask.Construct(ClusterPriority, "CLUSTER", cluster.Entry(0)); //include a track with the task
qt.SetTaskType("CLUSTER");
qt.UniqueId(cluster.Id());
qt.SetAuxData( "clusterIndex", i ); //for evaluation below
//TODO local tracks in the quantum task???
qt.SetAuxData( "maxPerformers", mMaxTaskPerformers );
qt.SetAuxData( "clusterId", cluster.Id() );
qt.SetAuxData( "ClusterMeanPoint", WsfGeoPoint(cluster.MeanLocation()) );
qt.SetAuxData( "ClusterBearing", cluster.Bearing() );
qt.SetAuxData( "ClusterBearingValid", cluster.BearingValid() );
qt.SetAuxData( "ClusterNumMembers", cluster.Count() );
Array<string> arr = Array<string>();
for (int i = 0; i < cluster.Count(); i = i + 1 )
{
arr.PushBack(cluster.Entry(i).TargetName());
writeln_d("job cluster member: ", cluster.Entry(i).TargetName());
}
qt.SetAuxData( "ClusterMemberNames", arr );
tasks.PushBack(qt);
writeln_d("cluster task generated for: ", cluster.Id());
}
}
return tasks;
end_script
script double GciCommanderEvaluation ( WsfQuantumTask TASK, WsfAssetPerception ASSET)
//simplistic evaluation for now
//TODO : iterate over all perceived assets that are subordinates of this lead and...
// evaluate each entry separately & make a composite value
writeln_d("evaluating ", ASSET.Name(), " and task type ", TASK.TaskType());
if (ASSET.Type() == "FLIGHT_LEAD")
{
WsfPlatform lead = WsfSimulation.FindPlatform(ASSET.Index());
if (lead.IsValid())
{
writeln_d("calculating value");
WsfGeoPoint subCentroid = lead.SubordinatesCentroid(); //cheating, TODO: use asset perception
int clusterIndex = TASK.AuxDataInt("clusterIndex");
WsfCluster cluster = cManager.Entry(clusterIndex);
double dist = cluster.MeanLocation().GroundRangeTo(subCentroid);
#double count = (double)lead.Subordinates().Count();
//count available weapons
double weaponCount = 0;
Array<WsfAssetPerception> assets = PLATFORM.PerceivedAssets();
WsfPlatformList subs = lead.Subordinates();
foreach(WsfPlatform sub in subs)
{
foreach (WsfAssetPerception asset in assets)
{
if (asset.Index()==sub.Index())
{
for (int j=0; j<asset.SystemCount(); j+=1)
{
if (asset.SystemKind(j) == "weapon")
{
weaponCount += asset.SystemQuantityRemaining(j);
}
}
break;
}
}
}
writeln_d("T=", TIME_NOW, ", ", lead.Name(), " evaluation: ", (weaponCount/dist));
#return (count/dist);
return (weaponCount/dist);
}
}
return 0.0;
end_script
#show_task_messages
script_debug_writes off
update_interval 10.0 sec
reallocation_strategy dynamic
generator custom GciCommanderTaskGeneration
evaluator custom GciCommanderEvaluation
allocator optimal_profit
#allocator_extra_tasks optimal_profit
#allocator greedy_isolated
#allocator_extra_tasks greedy_isolated
end_processor