Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 88 additions & 34 deletions src/Reproduction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,24 @@ public static class Delegates
private static ISiteVar<bool> noEstablish;
private static IPlanting planting;

// We must synchronize access to each site's cohort list: while one
// worker thread adds/removes cohorts at a site, another thread may be
// reading (iterating) that same site's cohort list during seed
// dispersal, which would otherwise crash with a "collection was
// modified during enumeration" error.
//
// Instead of one lock object per active site (about 128 MB of lock
// objects on a 4-million-cell landscape, spent even when running with a
// single thread), we use a small fixed set of "striped" locks. Each
// site maps to a stripe via "data index % SiteLockCount" (see
// GetSiteLock below), so memory stays O(1).
//
// SiteLockCount only needs to be comfortably larger than the number of
// worker threads (ThreadCount). Collisions are then rare and harmless.
private const int SiteLockCount = 1024;

private static readonly object[] siteLocks = CreateSiteLocks();

private static Delegates.AddNewCohort addNewCohort;
private static Delegates.SufficientResources lightMethod = ReproductionDefaults.SufficientResources;
private static Delegates.Establish estbMethod = ReproductionDefaults.Establish;
Expand Down Expand Up @@ -370,50 +388,81 @@ public static void EnableEstablishment(ActiveSite site)
}
//---------------------------------------------------------------------

/// <summary>
/// Returns the lock object that guards a site's cohort collection.
///
/// IMPORTANT — DO NOT NEST THESE LOCKS.
/// These locks are "striped": many different sites share the same lock
/// object. That is fine as long as each lock is taken on its own and
/// released before the next one is taken (which is how all the current
/// code behaves).
///
/// Never put a GetSiteLock(...) lock INSIDE another GetSiteLock(...)
/// lock. If a future change ever modifies two sites' cohorts at once,
/// take the two locks one after the other, not one inside the other.
/// Nesting them can deadlock: the simulation then freezes silently with
/// no error message, which is very hard to diagnose.
/// </summary>
internal static object GetSiteLock(ActiveSite site)
{
return siteLocks[(int)(site.DataIndex % SiteLockCount)];
}

/// <summary>
/// Creates the fixed, striped set of lock objects.
/// </summary>
private static object[] CreateSiteLocks()
{
var locks = new object[SiteLockCount];
for (int i = 0; i < locks.Length; i++)
locks[i] = new object();
return locks;
}
Comment thread
Klemet marked this conversation as resolved.

/// <summary>
/// Does the appropriate forms of reproduction at a site.
/// </summary>
public static void Reproduce(ActiveSite site, ThreadSafeRandom randomGen = null)
{
if(noEstablish[site])
if (noEstablish[site])
return;

bool plantingOccurred = planting.TryAt(site);
//bool plantingOccurred = false;
//for (int index = 0; index < speciesDataset.Count; ++index)
//{
// if (planting[site].Get(index))
// {
// ISpecies species = speciesDataset[index];
// if (PlantingEstablish(species, site))
// {
// AddNewCohort(species, site);
// plantingOccurred = true;
// }
// }
//}
object siteLock = GetSiteLock(site);

bool plantingOccurred;
lock (siteLock)
{
plantingOccurred = planting.TryAt(site);
}

bool sufficientLight;

bool serotinyOccurred = false;
if (! plantingOccurred) {
for (int index = 0; index < speciesDataset.Count; ++index) {
if (serotiny[site].Get(index)) {
if (!plantingOccurred)
{
for (int index = 0; index < speciesDataset.Count; ++index)
{
if (serotiny[site].Get(index))
{
ISpecies species = speciesDataset[index];
sufficientLight = SufficientResources(species, site);
if (sufficientLight && Establish(species, site)) {
// Temp set propBiomass to 1.0
AddNewCohort(species, site,"serotiny", 1.0);
if (sufficientLight && Establish(species, site))
{
lock (siteLock)
{
AddNewCohort(species, site, "serotiny", 1.0);
}
serotinyOccurred = true;
if (isDebugEnabled)
log.DebugFormat("site {0}: {1} post-fire regenerated",
site.Location, species.Name);
}
else {
else
{
if (isDebugEnabled)
log.DebugFormat("site {0}: {1} post-fire regen failed: {2}",
site.Location, species.Name,
! sufficientLight ? "insufficient light"
!sufficientLight ? "insufficient light"
: "didn't establish");
}
}
Expand All @@ -422,25 +471,32 @@ public static void Reproduce(ActiveSite site, ThreadSafeRandom randomGen = null)
serotiny[site].SetAll(false);

bool speciesResprouted = false;
if (! serotinyOccurred) {
for (int index = 0; index < speciesDataset.Count; ++index) {
if (resprout[site].Get(index)) {
if (!serotinyOccurred)
{
for (int index = 0; index < speciesDataset.Count; ++index)
{
if (resprout[site].Get(index))
{
ISpecies species = speciesDataset[index];
sufficientLight = SufficientResources(species, site);
if (sufficientLight &&
((randomGen == null ? Model.Core.NextDouble() : randomGen.NextDouble()) < species.VegReprodProb)) {
// Temp set propBiomass to 1.0
AddNewCohort(species, site, "resprout",1.0);
((randomGen == null ? Model.Core.NextDouble() : randomGen.NextDouble()) < species.VegReprodProb))
{
lock (siteLock)
{
AddNewCohort(species, site, "resprout", 1.0);
}
speciesResprouted = true;
if (isDebugEnabled)
log.DebugFormat("site {0}: {1} resprouted",
site.Location, species.Name);
}
else {
else
{
if (isDebugEnabled)
log.DebugFormat("site {0}: {1} resprouting failed: {2}",
site.Location, species.Name,
! sufficientLight ? "insufficient light"
!sufficientLight ? "insufficient light"
: "random # >= probability");
}
}
Expand All @@ -449,10 +505,8 @@ public static void Reproduce(ActiveSite site, ThreadSafeRandom randomGen = null)
resprout[site].SetAll(false);

planting.NotTriedAt(site);
if (! plantingOccurred && ! serotinyOccurred && ! speciesResprouted)
if (!plantingOccurred && !serotinyOccurred && !speciesResprouted)
seeding.Do(site, randomGen);


}


Expand Down
45 changes: 13 additions & 32 deletions src/Seeding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,42 +27,23 @@ public Seeding(SeedingAlgorithm seedingAlgorithm)

public void Do(ActiveSite site, ThreadSafeRandom randomGen = null)
{
// Accumulate seedling density if using demographic seeding
//if (seedingAlgorithm.GetType() == typeof(DemographicSeeding.Algorithm))
//{
// for (int i = 0; i < Model.Core.Species.Count; i++)
// {
// ISpecies species = Model.Core.Species[i];
// bool established;
// double seedlingProportion = 1.0;
// seedingAlgorithm(species, site, out established, out seedlingProportion);
// if(established)
// {
// // Temp set propBiomass to 1.0
// Reproduction.AddNewCohort(species, site, seedlingProportion);
// if (isDebugEnabled)
// log.DebugFormat("site {0}: seeded {1}",
// site.Location, species.Name);
// }
// }
//}
//else
//{
for (int i = 0; i < Model.Core.Species.Count; i++)
for (int i = 0; i < Model.Core.Species.Count; i++)
{
ISpecies species = Model.Core.Species[i];
bool established;
double seedlingProportion = 1.0;
seedingAlgorithm(species, site, out established, out seedlingProportion, randomGen);
if (established)
{
ISpecies species = Model.Core.Species[i];
bool established;
double seedlingProportion = 1.0 ;
seedingAlgorithm(species, site, out established, out seedlingProportion, randomGen);
if (established)
lock (Reproduction.GetSiteLock(site))
{
Reproduction.AddNewCohort(species, site,"seed", seedlingProportion);
if (isDebugEnabled)
log.DebugFormat("site {0}: seeded {1}",
site.Location, species.Name);
Reproduction.AddNewCohort(species, site, "seed", seedlingProportion);
}
if (isDebugEnabled)
log.DebugFormat("site {0}: seeded {1}",
site.Location, species.Name);
}
//}
}
}

//---------------------------------------------------------------------
Expand Down
38 changes: 25 additions & 13 deletions src/WardSeedDispersal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public static void Algorithm(ISpecies species,
{
established = false;
seedlingProportion = 1;

if (species.EffectiveSeedDist == Universal)
{
UniversalDispersal.Algorithm(species, site, out established, out seedlingProportion);
Expand Down Expand Up @@ -77,10 +78,13 @@ public static void Algorithm(ISpecies species,
{
Site neighbor = site.GetNeighbor(reloc.Location);
if (neighbor != null && neighbor.IsActive)
if (Reproduction.MaturePresent(species, (ActiveSite)neighbor))
lock (Reproduction.GetSiteLock((ActiveSite)neighbor))
{
established = true;
break;
if (Reproduction.MaturePresent(species, (ActiveSite)neighbor))
{
established = true;
break;
}
}
}

Expand All @@ -91,21 +95,27 @@ public static void Algorithm(ISpecies species,
if (rCol == 0)
neighbor = site.GetNeighbor(new RelativeLocation(0, rRow));
if (neighbor != null && neighbor.IsActive)
if (Reproduction.MaturePresent(species, (ActiveSite)neighbor))
lock (Reproduction.GetSiteLock((ActiveSite)neighbor))
{
established = true;
break;
if (Reproduction.MaturePresent(species, (ActiveSite)neighbor))
{
established = true;
break;
}
}
}

if (dispersalProb > uniformProb)
{
Site neighbor = site.GetNeighbor(new RelativeLocation(rRow * -1, rCol * -1));
if (neighbor != null && neighbor.IsActive)
if (Reproduction.MaturePresent(species, (ActiveSite)neighbor))
lock (Reproduction.GetSiteLock((ActiveSite)neighbor))
{
established = true;
break;
if (Reproduction.MaturePresent(species, (ActiveSite)neighbor))
{
established = true;
break;
}
}
}

Expand All @@ -115,13 +125,15 @@ public static void Algorithm(ISpecies species,
if (rCol == 0)
neighbor = site.GetNeighbor(new RelativeLocation(0, rRow * -1));
if (neighbor != null && neighbor.IsActive)
if (Reproduction.MaturePresent(species, (ActiveSite)neighbor))
lock (Reproduction.GetSiteLock((ActiveSite)neighbor))
{
established = true;
break;
if (Reproduction.MaturePresent(species, (ActiveSite)neighbor))
{
established = true;
break;
}
}
}

} // end foreach relativelocation
}

Expand Down
12 changes: 6 additions & 6 deletions src/library-succession.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
<AssemblyProduct>Landis.Library.Succession-v10</AssemblyProduct>
<AssemblyCompany>LANDIS-II Foundation</AssemblyCompany>
<AssemblyCopyright>LANDIS-II Foundation</AssemblyCopyright>
<!-- AssemblyVersion deliberately held at 10.0 for binary binding compatibility
with existing references; Version/FileVersion carry the human-readable stamp. -->
<AssemblyVersion>10.0</AssemblyVersion>
<Version>10.0</Version>
<FileVersion>10.0</FileVersion>
<Version>10.1.0</Version>
<FileVersion>10.1.0</FileVersion>
<AssemblyDescription>Input Parameters Library for LANDIS-II</AssemblyDescription>
<TargetFramework>netstandard2.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
Expand All @@ -26,19 +28,17 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">


<OutputPath></OutputPath>
<!--<OutputPath>bin\Debug\</OutputPath>-->

</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath></OutputPath>
</PropertyGroup>



Comment thread
Klemet marked this conversation as resolved.
<ItemGroup>
<!--<PackageReference Include="Accord" Version="3.8.0" />-->
<PackageReference Include="Accord.Statistics" Version="3.8.0" />
Expand Down