Rev 1181 | Rev 1204 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1181 | Rev 1182 | ||
---|---|---|---|
Line 785... | Line 785... | ||
785 | }
|
785 | }
|
786 | *p=1.f; // mark as processed |
786 | *p=1.f; // mark as processed |
787 | } // *p==1 |
787 | } // *p==1 |
788 | } // for() |
788 | } // for() |
789 | }
|
789 | }
|
- | 790 | ||
- | 791 | // because C modulo operation gives negative numbers for negative values, here a fix
|
|
- | 792 | // that always returns positive numbers: http://www.lemoda.net/c/modulo-operator/
|
|
- | 793 | #define MOD(a,b) ((((a)%(b))+(b))%(b))
|
|
790 | 794 | ||
791 | void SeedDispersal::distributeSeeds(Grid<float> *seed_map) |
795 | void SeedDispersal::distributeSeeds(Grid<float> *seed_map) |
792 | {
|
796 | {
|
793 | Grid<float> &sourcemap = seed_map ? *seed_map : mSourceMap; // switch to extra seed map if provided |
797 | Grid<float> &sourcemap = seed_map ? *seed_map : mSourceMap; // switch to extra seed map if provided |
794 | Grid<float> &kernel = mKernelSeedYear; |
798 | Grid<float> &kernel = mKernelSeedYear; |
- | 799 | ||
- | 800 | // *** estimate seed production (based on leaf area) ***
|
|
795 | // calculate number of seeds; the source map holds now m2 leaf area on 20x20m pixels
|
801 | // calculate number of seeds; the source map holds now m2 leaf area on 20x20m pixels
|
796 | // after this step, each source cell has a value between 0 (no source) and 1 (fully covered cell)
|
802 | // after this step, each source cell has a value between 0 (no source) and 1 (fully covered cell)
|
797 | float fec = species()->fecundity_m2(); |
803 | float fec = species()->fecundity_m2(); |
798 | if (!species()->isSeedYear()) |
804 | if (!species()->isSeedYear()) |
799 | fec *= mNonSeedYearFraction; |
805 | fec *= mNonSeedYearFraction; |
Line 804... | Line 810... | ||
804 | }
|
810 | }
|
805 | }
|
811 | }
|
806 | 812 | ||
807 | // sink mode
|
813 | // sink mode
|
808 | 814 | ||
809 | // // now look for each pixel in the targetmap and sum up seeds*kernel
|
- | |
810 | // int idx=0;
|
- | |
811 | // int offset = kernel.sizeX() / 2; // offset is the index of the center pixel
|
- | |
812 | // //const Grid<ResourceUnit*> &ru_map = GlobalSettings::instance()->model()->RUgrid();
|
- | |
813 | // DebugTimer tsink("seed_sink"); {
|
- | |
814 | // for (float *t=mSeedMap.begin(); t!=mSeedMap.end(); ++t, ++idx) {
|
- | |
815 | // // skip out-of-project areas
|
- | |
816 | // //if (!ru_map.constValueAtIndex(mSeedMap.index5(idx)))
|
- | |
817 | // // continue;
|
- | |
818 | // // apply the kernel
|
- | |
819 | // QPoint sm=mSeedMap.indexOf(t)-QPoint(offset, offset);
|
- | |
820 | // for (int iy=0;iy<kernel.sizeY();++iy) {
|
- | |
821 | // for (int ix=0;ix<kernel.sizeX();++ix) {
|
- | |
822 | // if (sourcemap.isIndexValid(sm.x()+ix, sm.y()+iy))
|
- | |
823 | // *t+=sourcemap(sm.x()+ix, sm.y()+iy) * kernel(ix, iy);
|
- | |
824 | // }
|
- | |
825 | // }
|
- | |
826 | // }
|
- | |
827 | // } // debugtimer
|
- | |
828 | // mSeedMap.initialize(0.f); // just for debugging...
|
- | |
- | 815 | // // now look for each pixel in the targetmap and sum up seeds*kernel
|
|
- | 816 | // int idx=0;
|
|
- | 817 | // int offset = kernel.sizeX() / 2; // offset is the index of the center pixel
|
|
- | 818 | // //const Grid<ResourceUnit*> &ru_map = GlobalSettings::instance()->model()->RUgrid();
|
|
- | 819 | // DebugTimer tsink("seed_sink"); {
|
|
- | 820 | // for (float *t=mSeedMap.begin(); t!=mSeedMap.end(); ++t, ++idx) {
|
|
- | 821 | // // skip out-of-project areas
|
|
- | 822 | // //if (!ru_map.constValueAtIndex(mSeedMap.index5(idx)))
|
|
- | 823 | // // continue;
|
|
- | 824 | // // apply the kernel
|
|
- | 825 | // QPoint sm=mSeedMap.indexOf(t)-QPoint(offset, offset);
|
|
- | 826 | // for (int iy=0;iy<kernel.sizeY();++iy) {
|
|
- | 827 | // for (int ix=0;ix<kernel.sizeX();++ix) {
|
|
- | 828 | // if (sourcemap.isIndexValid(sm.x()+ix, sm.y()+iy))
|
|
- | 829 | // *t+=sourcemap(sm.x()+ix, sm.y()+iy) * kernel(ix, iy);
|
|
- | 830 | // }
|
|
- | 831 | // }
|
|
- | 832 | // }
|
|
- | 833 | // } // debugtimer
|
|
- | 834 | // mSeedMap.initialize(0.f); // just for debugging...
|
|
829 | 835 | ||
830 | int offset = kernel.sizeX() / 2; // offset is the index of the center pixel |
836 | int offset = kernel.sizeX() / 2; // offset is the index of the center pixel |
831 | // source mode
|
837 | // source mode
|
832 | 838 | ||
- | 839 | // *** seed distribution (Kernel + long distance dispersal) ***
|
|
- | 840 | if (GlobalSettings::instance()->model()->settings().torusMode==false) { |
|
- | 841 | // ** standard case (no torus) **
|
|
- | 842 | for (float *src=sourcemap.begin(); src!=sourcemap.end(); ++src) { |
|
- | 843 | if (*src>0.f) { |
|
- | 844 | QPoint sm=sourcemap.indexOf(src)-QPoint(offset, offset); |
|
- | 845 | int sx = sm.x(), sy=sm.y(); |
|
- | 846 | for (int iy=0;iy<kernel.sizeY();++iy) { |
|
- | 847 | for (int ix=0;ix<kernel.sizeX();++ix) { |
|
- | 848 | if (mSeedMap.isIndexValid(sx+ix, sy+iy)) |
|
- | 849 | mSeedMap.valueAtIndex(sx+ix, sy+iy)+= *src * kernel(ix, iy); |
|
- | 850 | }
|
|
- | 851 | }
|
|
- | 852 | // long distance dispersal
|
|
- | 853 | if (!mLDDDensity.isEmpty()) { |
|
- | 854 | QPoint pt=sourcemap.indexOf(src); |
|
833 | 855 | ||
834 | for (float *src=sourcemap.begin(); src!=sourcemap.end(); ++src) { |
- | |
835 | if (*src>0.f) { |
- | |
836 | QPoint sm=sourcemap.indexOf(src)-QPoint(offset, offset); |
- | |
837 | int sx = sm.x(), sy=sm.y(); |
- | |
838 | for (int iy=0;iy<kernel.sizeY();++iy) { |
- | |
839 | for (int ix=0;ix<kernel.sizeX();++ix) { |
- | |
840 | if (mSeedMap.isIndexValid(sx+ix, sy+iy)) |
- | |
841 | mSeedMap.valueAtIndex(sx+ix, sy+iy)+= *src * kernel(ix, iy); |
- | |
- | 856 | for (int r=0;r<mLDDDensity.size(); ++r) { |
|
- | 857 | float ldd_val = mLDDSeedlings / fec; // pixels will have this probability [note: fecundity will be multiplied below] |
|
- | 858 | int n; |
|
- | 859 | if (mLDDDensity[r]<1) |
|
- | 860 | n = drandom()<mLDDDensity[r] ? 1 : 0; |
|
- | 861 | else
|
|
- | 862 | n = round( mLDDDensity[r] ); // number of pixels to activate |
|
- | 863 | for (int i=0;i<n;++i) { |
|
- | 864 | // distance and direction:
|
|
- | 865 | double radius = nrandom(mLDDDistance[r], mLDDDistance[r+1]) / mSeedMap.cellsize(); // choose a random distance (in pixels) |
|
- | 866 | double phi = drandom()*2.*M_PI; // choose a random direction |
|
- | 867 | QPoint ldd(pt.x() + radius*cos(phi), pt.y() + radius*sin(phi)); |
|
- | 868 | if (mSeedMap.isIndexValid(ldd)) { |
|
- | 869 | float &val = mSeedMap.valueAtIndex(ldd); |
|
- | 870 | _debug_ldd++; |
|
- | 871 | val += ldd_val; |
|
- | 872 | }
|
|
- | 873 | }
|
|
- | 874 | }
|
|
842 | }
|
875 | }
|
- | 876 | ||
843 | }
|
877 | }
|
844 | // long distance dispersal
|
- | |
845 | if (!mLDDDensity.isEmpty()) { |
- | |
846 | QPoint pt=sourcemap.indexOf(src); |
- | |
- | 878 | }
|
|
- | 879 | } else { |
|
- | 880 | // **** seed distribution in torus mode ***
|
|
- | 881 | int seedmap_offset = sourcemap.indexAt(QPointF(0., 0.)).x(); // the seed maps have x extra rows/columns |
|
- | 882 | QPoint torus_pos;
|
|
- | 883 | int seedpx_per_ru = static_cast<int>((cRUSize/sourcemap.cellsize())); |
|
- | 884 | for (float *src=sourcemap.begin(); src!=sourcemap.end(); ++src) { |
|
- | 885 | if (*src>0.f) { |
|
- | 886 | QPoint sm=sourcemap.indexOf(src); |
|
- | 887 | // get the origin of the resource unit *on* the seedmap in *seedmap-coords*:
|
|
- | 888 | QPoint offset_ru( ((sm.x()-seedmap_offset) / seedpx_per_ru) * seedpx_per_ru + seedmap_offset, |
|
- | 889 | ((sm.y()-seedmap_offset) / seedpx_per_ru) * seedpx_per_ru + seedmap_offset); // coords RU origin |
|
- | 890 | ||
- | 891 | QPoint offset_in_ru((sm.x()-seedmap_offset) % seedpx_per_ru, (sm.y()-seedmap_offset) % seedpx_per_ru ); // offset of current point within the RU |
|
- | 892 | ||
- | 893 | //QPoint sm=sourcemap.indexOf(src)-QPoint(offset, offset);
|
|
- | 894 | for (int iy=0;iy<kernel.sizeY();++iy) { |
|
- | 895 | for (int ix=0;ix<kernel.sizeX();++ix) { |
|
- | 896 | torus_pos = offset_ru + QPoint(MOD((offset_in_ru.x() - offset + ix), seedpx_per_ru), MOD((offset_in_ru.y() - offset + iy), seedpx_per_ru)); |
|
- | 897 | ||
- | 898 | if (mSeedMap.isIndexValid(torus_pos)) |
|
- | 899 | mSeedMap.valueAtIndex(torus_pos)+= *src * kernel(ix, iy); |
|
- | 900 | }
|
|
- | 901 | }
|
|
- | 902 | // long distance dispersal
|
|
- | 903 | if (!mLDDDensity.isEmpty()) { |
|
- | 904 | ||
- | 905 | for (int r=0;r<mLDDDensity.size(); ++r) { |
|
- | 906 | float ldd_val = mLDDSeedlings / fec; // pixels will have this probability [note: fecundity will be multiplied below] |
|
- | 907 | int n; |
|
- | 908 | if (mLDDDensity[r]<1) |
|
- | 909 | n = drandom()<mLDDDensity[r] ? 1 : 0; |
|
- | 910 | else
|
|
- | 911 | n = round( mLDDDensity[r] ); // number of pixels to activate |
|
- | 912 | for (int i=0;i<n;++i) { |
|
- | 913 | // distance and direction:
|
|
- | 914 | double radius = nrandom(mLDDDistance[r], mLDDDistance[r+1]) / mSeedMap.cellsize(); // choose a random distance (in pixels) |
|
- | 915 | double phi = drandom()*2.*M_PI; // choose a random direction |
|
- | 916 | QPoint ldd( radius*cos(phi), + radius*sin(phi)); // destination (offset) |
|
- | 917 | torus_pos = offset_ru + QPoint(MOD((offset_in_ru.x()+ldd.x()),seedpx_per_ru), MOD((offset_in_ru.y()+ldd.y()),seedpx_per_ru) ); |
|
847 | 918 | ||
848 | for (int r=0;r<mLDDDensity.size(); ++r) { |
- | |
849 | float ldd_val = mLDDSeedlings / fec; // pixels will have this probability [note: fecundity will be multiplied below] |
- | |
850 | int n; |
- | |
851 | if (mLDDDensity[r]<1) |
- | |
852 | n = drandom()<mLDDDensity[r] ? 1 : 0; |
- | |
853 | else
|
- | |
854 | n = round( mLDDDensity[r] ); // number of pixels to activate |
- | |
855 | for (int i=0;i<n;++i) { |
- | |
856 | // distance and direction:
|
- | |
857 | double radius = nrandom(mLDDDistance[r], mLDDDistance[r+1]) / mSeedMap.cellsize(); // choose a random distance (in pixels) |
- | |
858 | double phi = drandom()*2.*M_PI; // choose a random direction |
- | |
859 | QPoint ldd(pt.x() + radius*cos(phi), pt.y() + radius*sin(phi)); |
- | |
860 | if (mSeedMap.isIndexValid(ldd)) { |
- | |
861 | float &val = mSeedMap.valueAtIndex(ldd); |
- | |
862 | _debug_ldd++; |
- | |
863 | val += ldd_val; |
- | |
- | 919 | if (mSeedMap.isIndexValid(torus_pos)) { |
|
- | 920 | float &val = mSeedMap.valueAtIndex(torus_pos); |
|
- | 921 | _debug_ldd++; |
|
- | 922 | val += ldd_val; |
|
- | 923 | }
|
|
864 | }
|
924 | }
|
865 | }
|
925 | }
|
866 | }
|
926 | }
|
- | 927 | ||
867 | }
|
928 | }
|
868 | - | ||
869 | }
|
929 | }
|
870 | }
|
- | |
- | 930 | } // torus |
|
871 | 931 | ||
872 | 932 | ||
873 | 933 | ||
874 | // now the seed sources (0..1) are spatially distributed by the kernel (and LDD) without altering the magnitude;
|
934 | // now the seed sources (0..1) are spatially distributed by the kernel (and LDD) without altering the magnitude;
|
875 | // now we include the fecundity (=seedling potential per m2 crown area), and convert to the establishment probability p_seed.
|
935 | // now we include the fecundity (=seedling potential per m2 crown area), and convert to the establishment probability p_seed.
|