From 588d1142abfdf51959182f78becce83b353b5f22 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 9 Aug 2019 15:06:09 -0700 Subject: [PATCH 001/115] Updated mechanical stars implementation --- src/enzo/Grid.h | 13 + src/enzo/Grid_MechStarsCreation.C | 204 +++++++ src/enzo/Grid_MechStarsDepositFeedback.C | 518 ++++++++++++++++++ src/enzo/Grid_MechStarsFeedbackRoutine.C | 251 +++++++++ src/enzo/Grid_StarParticleHandler.C | 48 +- src/enzo/MechStars_checkCreationCriteria.C | 153 ++++++ src/enzo/MechStars_determineSN.C | 92 ++++ src/enzo/MechStars_determineWinds.C | 73 +++ .../MechStars_transformComovingWithStar.C | 46 ++ src/enzo/ReadParameterFile.C | 15 +- src/enzo/SetDefaultGlobalValues.C | 12 +- src/enzo/StarParticleData.h | 10 + src/enzo/WriteParameterFile.C | 14 +- src/enzo/macros_and_parameters.h | 1 + 14 files changed, 1444 insertions(+), 6 deletions(-) create mode 100644 src/enzo/Grid_MechStarsCreation.C create mode 100644 src/enzo/Grid_MechStarsDepositFeedback.C create mode 100644 src/enzo/Grid_MechStarsFeedbackRoutine.C create mode 100644 src/enzo/MechStars_checkCreationCriteria.C create mode 100644 src/enzo/MechStars_determineSN.C create mode 100644 src/enzo/MechStars_determineWinds.C create mode 100644 src/enzo/MechStars_transformComovingWithStar.C diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index 6a8023953..d067fe6e7 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2879,6 +2879,19 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle); + +int MechStars_Creation(grid* ParticleArray, float* Temperature, + float *DMField, int level, float* CoolingTime, + int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar); +int MechStars_FeedbackRoutine(int level, float* mu_field); +int MechStars_DepositFeedback(float supernovaEnergy, + float ejectaMass, float ejectaMetal, + float* up, float* vp, float* wp, + float* xp, float* yp, float* zp, + int ip, int jp, int kp, + int size, float* mu_field, int winds); + + //------------------------------------------------------------------------ // Radiative transfer methods that don't fit in the TRANSFER define //------------------------------------------------------------------------ diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C new file mode 100644 index 000000000..c6c1a9f75 --- /dev/null +++ b/src/enzo/Grid_MechStarsCreation.C @@ -0,0 +1,204 @@ +/* + Algorithm creates the stars for Mechanical star maker + Formation follows Hopkins 2017 "How to model supernovae" + + 07/2019: Azton Wells + */ +#include +#include +#include +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "fortran.def" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" +//Prototypes + int checkCreationCriteria(float* Density, + float* Metals, + float* Temperature,float* DMField, + float* Vel1, float* Vel2, float* Vel3, + float* CoolingTime, int* GridDim, + float* shieldedFraction, float* freeFallTime, + float* dynamicalTime, int i, int j, int k, + float Time, float* RefinementField, float CellWidth); + int GetUnits(float *DensityUnits, float *LengthUnits, + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, float *MassUnits, float Time); + int FindField(int field, int farray[], int numfields); + + +/* Creation Routine */ +int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, + float *DMField, int level, float* CoolingTime, + int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar) +{ + if (level < StarMakeLevel) return 0; + float stretchFactor=1.4; + bool debug = true; + // fprintf(stdout, "Preparing to check grids\n"); + // limit creation to level specified in parameter file + + //get field numbers + int DensNum, GENum, Vel1Num, Vel2Num,Vel3Num, TENum; + if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) { + fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); + return FAIL; + } + + int MetallicityField = FALSE, MetalNum; + if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) + != -1) + { + MetallicityField = TRUE; + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { + fprintf(stderr, "Error in GetUnits.\n"); + return FAIL; + } + } + else + MetalNum = 0; + if (!MetalNum){ + fprintf(stderr, "Can only use mechanical star maker routines with metallicity enabled!"); + return FAIL; + } + + + int rank = GridRank; + + + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { + fprintf(stderr, "Error in GetUnits.\n"); + return FAIL; + } + +/* Define MassUnits so that code * mass = physical (Msun) + and physical(Msun) / MassUnits = code */ + MassUnits = DensityUnits*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass; + + float dx = CellWidth[0][0]; + int GZ = int(NumberOfGhostZones); + int nCreated = *NumberOfParticlesSoFar; + fprintf(stdout, "Starting creation with %d prior particles\n",nCreated); + for (int i = GZ; i < GridDimension[0]-GZ; i++){ + for(int j = GZ; j < GridDimension[1]-GZ; j++){ + for (int k = GZ; k< GridDimension[2]-GZ; k++){ + /* + Particle creation has several criteria: + + 1. Density > overdensity + 2. is flow converging by finite differences + 3. is cooling time < dynamical time + 4. is gas mass > jean critical mass + 5. is gas self shielded by Krumholz & Gnedin 2007 criteria + + */ + float shieldedFraction = 0; + float freeFallTime = 0; + float dynamicalTime = 0; + float Time = this->Time; + + int stat = checkCreationCriteria(BaryonField[DensNum], + BaryonField[MetalNum], Temperature, DMField, + BaryonField[Vel1Num], BaryonField[Vel2Num], + BaryonField[Vel3Num], + CoolingTime, GridDimension, &shieldedFraction, + &freeFallTime, &dynamicalTime, i,j,k,Time, + BaryonField[NumberOfBaryonFields], CellWidth[0][0]); + + + + if (stat){ + int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; + + /* Determine Mass of new particle */ + + float MassShouldForm =(shieldedFraction * BaryonField[DensNum][index] + * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13); + + if (MassShouldForm < 0){ + printf("Negative formation mass: %f %f",shieldedFraction, freeFallTime); + continue; + } + float newMass = min(MassShouldForm, + StarMakerMaximumFormationMass); + newMass = newMass/MassUnits; + if (newMass > BaryonField[DensNum][index]) exit(136); + nCreated ++; + float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; + dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); + fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); + ParticleArray->ParticleMass[nCreated] = newMass; + ParticleArray->ParticleAttribute[1][nCreated] = dynamicalTime/TimeUnits; + ParticleArray->ParticleAttribute[0][nCreated] = Time; + ParticleArray->ParticleAttribute[2][nCreated] = BaryonField[MetalNum][index] + /BaryonField[DensNum][index]/0.02; + ParticleArray->ParticleType[nCreated] = PARTICLE_TYPE_STAR; + BaryonField[DensNum][index] -= newMass; + + // type IA metal field isnt here right now + // if (StarMakerTypeIASNe) + // ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIANum]; + int preI = index-1; + int postI = index+1; + int preJ = i+ (j-1)*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; + int postJ = i+ (j+1)*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; + int preK = i+ j*GridDimension[0]+(k-1)*GridDimension[0]*GridDimension[1]; + int postK = i+ j*GridDimension[0]+(k+1)*GridDimension[0]*GridDimension[1]; + if (HydroMethod != 0) + fprintf(stderr,"Mechanical star maker not tested for anything except HydroMethod = 0\n"); + ParticleArray->ParticleVelocity[0][nCreated] = + 0.33*(BaryonField[Vel1Num][preI]+BaryonField[Vel1Num][postI] + +BaryonField[Vel1Num][index]); + ParticleArray->ParticleVelocity[1][nCreated] = + 0.33*(BaryonField[Vel2Num][preI]+BaryonField[Vel2Num][postI] + +BaryonField[Vel2Num][index]); + ParticleArray->ParticleVelocity[2][nCreated] = + 0.33*(BaryonField[Vel3Num][preI]+BaryonField[Vel3Num][postI] + +BaryonField[Vel3Num][index]); + + /* give it position at center of host cell */ + + ParticleArray->ParticlePosition[0][nCreated] = CellLeftEdge[0][0] + +(dx*(float(i)-0.5)); + ParticleArray->ParticlePosition[1][nCreated] = CellLeftEdge[1][0] + +(dx*(float(j)-0.5)); + ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] + +(dx*(float(k)-0.5)); + if (nCreated >= MaximumNumberOfNewParticles) return nCreated; + fprintf(stdout,"Created star: %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", + nCreated, + ParticleArray->ParticleType[nCreated], + ParticleArray->ParticleMass[nCreated]*MassUnits, + ParticleArray->ParticleAttribute[0][nCreated], + ParticleArray->ParticleAttribute[1][nCreated], + ParticleArray->ParticleAttribute[2][nCreated], + ParticleArray->ParticlePosition[0][nCreated], + ParticleArray->ParticlePosition[1][nCreated], + ParticleArray->ParticlePosition[2][nCreated], + ParticleArray->ParticleVelocity[0][nCreated]*VelocityUnits/1e5, + ParticleArray->ParticleVelocity[1][nCreated]*VelocityUnits/1e5, + ParticleArray->ParticleVelocity[2][nCreated]*VelocityUnits/1e5, + index, GridDimension[0]*GridDimension[2]*GridDimension[3], i,j,k); + } + }//end for k + }//end for j + } // end for i + if (nCreated > 0){ + fprintf(stdout, "Created %d star particles\n",nCreated); + } + *NumberOfParticlesSoFar = nCreated; + return nCreated; +} \ No newline at end of file diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C new file mode 100644 index 000000000..9061bb8d4 --- /dev/null +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -0,0 +1,518 @@ +#include +#include +#include +#include "ErrorExceptions.h" +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "fortran.def" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" + + extern "C" void FORTRAN_NAME(cic_deposit)(float* xPosition, float* yPosition, + float* zPosition, int* gridRank, int* nParticles, + float* DepositQuantity, float* FieldToDepositTo, + float* leftEdge, int* xGridDim, int* yGridDim, + int* zGridDim, float* gridDx, float* cloudsize); + int GetUnits(float *DensityUnits, float *LengthUnits, + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, float *MassUnits, float Time); + int transformComovingWithStar(float* Density, float* Metals, + float* Vel1, float* Vel2, float* Vel3, + float up, float vp, float wp, + int sizeX, int sizeY, int sizeZ, int direction); + int FindField(int field, int farray[], int numfields); + + +int grid::MechStars_DepositFeedback(float ejectaEnergy, + float ejectaMass, float ejectaMetal, + float* up, float* vp, float* wp, + float* xp, float* yp, float* zp, + int ip, int jp, int kp, + int size, float* muField, int winds){ + + /* + This routine will create an isocahedron of coupling particles, where we determine + the feedback quantities. The vertices of the isocahedron are ~coupled particles + and all have radius dx from the source particle. + Each vertex particle will then be CIC deposited to the grid! + */ + bool debug = true; + bool criticalDebug = true; + int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + + /* Compute size (in floats) of the current grid. */ + float stretchFactor =1.;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host + // in units of dx + int usePt = 0; + size = 1; + for (int dim = 0; dim < GridRank; dim++) + size *= GridDimension[dim]; + float DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, + HMNum, H2INum, H2IINum, DINum, DIINum, HDINum; + /* Find fields: density, total energy, velocity1-3. */ + + if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) { + fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); + return FAIL; + } + /* Set the units */ + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, + &MassUnits, this->Time) == FAIL) { + fprintf(stderr, "Error in GetUnits.\n"); + return FAIL; + } + FLOAT dx = CellWidth[0][0]; + + if (debug) + fprintf(stdout, "depositing quantities: Energy %e, Mass %e, Metals %e\n", + ejectaEnergy, ejectaMass, ejectaMetal); + + /* + get metallicity field and set flag; assumed true thoughout feedback + since so many quantities are metallicity dependent + */ + int MetallicityField = FALSE, MetalNum; + if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) + != -1) + MetallicityField = TRUE; + else + MetalNum = 0; + + /* set other units that we need */ + MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; + float EnergyUnits = DensityUnits*pow(LengthUnits*dx, 3) + * VelocityUnits*VelocityUnits;//[g cm^2/s^2] -> code_energy + float MomentaUnits = VelocityUnits; + + /* Make copys of fields to work with. These will conatin the added deposition + of all quantities and be coupled to the grid after the cic deposition. */ + float density [size]; + float metals [size]; + float *u = new float [size]; + float *v = new float[size]; + float *w = new float [size]; + float *totalEnergy =new float [size]; + float *gasEnergy =new float[size]; + for (int i=0; i respective momenta. Use -1 to reverse transform after.*/ + /* these temp arrays are implicitly comoving with the star! */ + /* Array of coordinates of the isocahedron vertices scaled by r=dx */ + + float phi = (1.0+sqrt(5))/2.0; //Golden Ratio + float iphi = 1.0/phi; // inverse GR + /* Particle Vectors */ + + + /* A DODECAHEDRON+ISOCAHEDRON */ + + int nCouple = 32; + float A = stretchFactor*dx; + + /* Dodec points followed by isoca points */ + FLOAT CloudParticleVectorX [] = {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, + iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, + 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; + FLOAT CloudParticleVectorY [] = {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, + phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, + phi, -phi, -phi, phi, 0, 0, 0, 0}; + FLOAT CloudParticleVectorZ [] = {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, + 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, + phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; + + /* Set position of feedback cloud particles */ + + FLOAT CloudParticlePositionX [nCouple]; + FLOAT CloudParticlePositionY [nCouple]; + FLOAT CloudParticlePositionZ [nCouple]; + + /*all possible values of x,y,z with origin particle at x=y=z=0.0 */ + for (int cpInd = 0; cpInd < nCouple; cpInd++){ + FLOAT norm = sqrt(CloudParticleVectorX[cpInd]*CloudParticleVectorX[cpInd] + + CloudParticleVectorY[cpInd]*CloudParticleVectorY[cpInd] + + CloudParticleVectorZ[cpInd]*CloudParticleVectorZ[cpInd]); + /* in this cloud, take the coupling particle position as 0.5, 0.5, 0.5 */ + CloudParticlePositionX[cpInd] = *xp-CloudParticleVectorX[cpInd]/norm* + A; + CloudParticlePositionY[cpInd] = *yp-CloudParticleVectorY[cpInd]/norm* + A; + CloudParticlePositionZ[cpInd] = *zp-CloudParticleVectorZ[cpInd]/norm* + A; + /* turn the vectors back into unit-vectors */ + CloudParticleVectorZ[cpInd] /= norm; + CloudParticleVectorY[cpInd] /= norm; + CloudParticleVectorX[cpInd] /= norm; + } + /* Each particle gets 1/12 of energy, momenta, mass, and metal. There + are no varying vector / scalar weights to worry about. The momenta coupled + is simply \hat(r_ba) p/12 for r_ba the vector from source to coupled + particle. */ + + /* transform to comoving with the star and take velocities to momenta */ + + transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], + BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], + *up, *vp, *wp, GridDimension[0], GridDimension[1], + GridDimension[2], 1); + /* Use averaged quantities across multiple cells so that deposition is stable. + vmean is used to determine whether the supernova shell calculation should proceed: + M_shell > 0 iff v_shell > v_gas */ + float zmean=0, dmean=0, nmean=0, vmean; + for (int ind = -1; ind <= 1; ind++){ + zmean += BaryonField[MetalNum][index+ind]*BaryonField[DensNum][index+ind]; + zmean += BaryonField[MetalNum][index+GridDimension[0]*ind]*BaryonField[DensNum][index+GridDimension[0]*ind]; + zmean += BaryonField[MetalNum][index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + + if (debug) fprintf(stdout, "MuField = %f %f %f\nmax = %d ; %d %d %d\n", + muField[index+ind], muField[index+GridDimension[0]*ind], muField[index+ind*GridDimension[0]*GridDimension[1]], GridDimension[0]*GridDimension[1]*GridDimension[2], + index+ind, index+GridDimension[0]*ind, index+ind*GridDimension[0]*GridDimension[1]); + nmean += BaryonField[DensNum][index+ind]*BaryonField[DensNum][index+ind]*DensityUnits/mh/max(0.6,muField[index+ind]); + nmean += BaryonField[DensNum][index+GridDimension[0]*ind]* + BaryonField[DensNum][index+GridDimension[0]*ind]*DensityUnits/mh/max(muField[index+GridDimension[0]*ind],0.6); + nmean += BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind] + *BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]*DensityUnits/mh/max(0.6,muField[index+ind*GridDimension[0]*GridDimension[1]]); + + dmean += BaryonField[DensNum][index+ind]; + dmean += BaryonField[DensNum][index+GridDimension[0]*ind]; + dmean += BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + + vmean += BaryonField[Vel1Num][index+ind]*BaryonField[Vel1Num][index+ind]*VelocityUnits*VelocityUnits; + vmean += BaryonField[Vel1Num][index+GridDimension[0]*ind]*BaryonField[Vel1Num][index+GridDimension[0]*ind]*VelocityUnits*VelocityUnits; + vmean += BaryonField[Vel1Num][index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[Vel1Num][index+GridDimension[0]*GridDimension[1]*ind]*VelocityUnits*VelocityUnits; + + vmean += BaryonField[Vel2Num][index+ind]*BaryonField[Vel2Num][index+ind]*VelocityUnits*VelocityUnits; + vmean += BaryonField[Vel2Num][index+GridDimension[0]*ind]*BaryonField[Vel2Num][index+GridDimension[0]*ind]*VelocityUnits*VelocityUnits; + vmean += BaryonField[Vel2Num][index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[Vel2Num][index+GridDimension[0]*GridDimension[1]*ind]*VelocityUnits*VelocityUnits; + + vmean += BaryonField[Vel3Num][index+ind]*BaryonField[Vel3Num][index+ind]*VelocityUnits*VelocityUnits; + vmean += BaryonField[Vel3Num][index+GridDimension[0]*ind]*BaryonField[Vel3Num][index+GridDimension[0]*ind]*VelocityUnits*VelocityUnits; + vmean += BaryonField[Vel3Num][index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[Vel3Num][index+GridDimension[0]*GridDimension[1]*ind]*VelocityUnits*VelocityUnits; + + } + vmean = sqrt(vmean/dmean/dmean); + zmean /= (dmean*0.02); + nmean /= (dmean); + + dmean /= 9.0; + nmean = max(nmean, 1e-3); + float zZsun = max(zmean, 1e-8); + float fz = (zZsun < 0.01)? (2.0): (pow(zZsun, -0.14)); + + /* conversions */ + float CoolingRadius = 28.4 * + pow(max(0.001,nmean), -3.0/7.0) + *pow(ejectaEnergy/1.0e51, 2.0/7.0)* fz; + if (debug)fprintf(stdout, "cooling radius [pc] = %f\n %f %f %f %e %f \n", + CoolingRadius, nmean, ejectaEnergy/1e51, fz, zmean, dmean); + /* Calculate coupled energy scaled by reduction to account for unresolved + cooling, then use that energy to calculate momenta*/ + float coupledEnergy = ejectaEnergy; + + if (debug)fprintf(stdout, "Dx [pc] = %f\n", dx*LengthUnits/pc_cm); + float dxRatio = stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius; + + float coupledMomenta = 0.0; + float eKinetic = 0.0; + /* Hopkins uses ratio of masses to determine how to couple. + Radius here is well-known and fixed, so we use that instead */ + if (dxRatio > 1.0){ + if (ejectaEnergy < 1e5 || dxRatio > 100){ + coupledEnergy = 0.0; + coupledMomenta = 0.0; + }else{ + coupledEnergy = ejectaEnergy*pow(dxRatio, -6.5); + usePt = 1; + + /* Determine coupled momenta if rc < dx + else couple p_ej*(1+dx/r_cool)**4 */ + if(debug)fprintf(stdout, "Using P_t with Nb = %f, E= %e",nmean, coupledEnergy/1e51); + float Efactor = 1.0; + if (dxRatio > 4) Efactor = coupledEnergy/ejectaEnergy*pow(dxRatio,3); + coupledMomenta = 4.8e5*pow(nmean, -1.0/7.0) + * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; //Msun*km/s + } + } else { + if (debug)fprintf(stdout, "Directly calculating momenta using energy = %e and mass = %e ", + ejectaEnergy, ejectaMass); + coupledMomenta = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5) + * pow(1.0+dxRatio, 3.75*pow(nmean, -1./14.))/SolarMass/1e5; //Msun*km/s + if (debug)fprintf(stdout, "Calculated p = %e ", coupledMomenta); + if (debug)fprintf(stdout, "Ekinetic = %e\n", coupledMomenta*coupledMomenta + /(2.0*ejectaMass)*SolarMass*1e10); + + } + float shellMass = 0.0, shellVelocity = 0.0; + /* If resolution is in a range compared to Rcool and + Analytic SNR shell mass is on, adjust the shell mass + Shell is limited on upper end by 1/1000 mass of + cell with mean density*/ + float maxShellMass = 1.0*DensityUnits*MassUnits/1000; // large shell mass evacuates too efficently... muField-> 0.0 and NaN ensues! + if (dxRatio <= 50 && dxRatio >= 0.1 && coupledEnergy > 0 + && AnalyticSNRShellMass){ + shellVelocity = 413.0 *pow(nmean, 1.0/7.0) + *pow(zZsun, 3.0/14.0)*pow(coupledEnergy/EnergyUnits/1e51, 1.0/14.0) + *pow(dxRatio, -7.0/3.0);//km/s + /* Underdense regions can have large momenta with + low velocity, leading to shell mass instability. + The shell velocity is compared to gas velocity, and + can only contribute to the mass if the shell velocity is + higher than the gas velocity.*/ + if (shellVelocity > vmean){ + shellMass = max(1e3, coupledMomenta/shellVelocity); //Msun + + /* cant let host cells evacuate completely! + Shell mass will be evacuated from central cells by CIC a negative mass, + so have to check that the neighbors can handle it too*/ + for (int ind = -1; ind<=1; ind++){ + float minD = min(BaryonField[DensNum][index+ind],BaryonField[DensNum][index+GridDimension[0]*ind]); + minD = min(minD,BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]); + if (shellMass >= 0.05*minD*MassUnits) + shellMass = 0.05*minD*MassUnits; + } + + + } + + } + + if (shellMass < 0.0){ + fprintf(stdout, "Shell mass = %e Velocity= %e P = %e", + shellMass, shellVelocity, coupledMomenta); + ENZO_FAIL("SM_deposit: 252");} + float coupledMass = shellMass+ejectaMass; + eKinetic = coupledMomenta*coupledMomenta + /(2.0*coupledMass)*SolarMass*1e10; + + /* rescale momenta if it results in too much energy */ + + // if (eKinetic > coupledEnergy && !usePt){ + // float fact = coupledEnergy/eKinetic; + // if (debug)fprintf(stdout, "recalculating momenta: e_k > e_cpl: e_k = %e e_cpl = %e factor = %e ", + // eKinetic, coupledEnergy, fact); + // coupledMomenta = pow(fact*2.0*ejectaEnergy*(coupledMass*SolarMass), 0.5) + // * pow(1.0+dxRatio, 3.75*pow(nmean, -1./14.))/SolarMass/1e5; + // eKinetic = coupledMomenta*coupledMomenta + // /(2.0*coupledMass)*SolarMass*1e10; + // if (debug)fprintf(stdout, "new e_k = %e p = %e\n",eKinetic, coupledMomenta); + // } + + // // // /* If p_t gives too much kinetic energy, reduce it + // // // to preserve energy conservation */ + + // if (eKinetic > coupledEnergy && usePt){ + // float fact = pow(coupledEnergy/eKinetic,14.0/13.0); + // if (debug)fprintf(stdout, "recalculating momenta: e_k > e_cpl e_k = %e e_cpl = %e ", + // eKinetic, coupledEnergy); + // coupledMomenta = pow(dxRatio, -3)*4.8e5*pow(nmean, -1.0/7.0) + // * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; + // eKinetic = coupledMomenta*coupledMomenta + // /(2.0*coupledMass)*SolarMass*1e10; + // if (debug)fprintf(stdout, "new e_k = %e p = %e\n",eKinetic, coupledMomenta); + // } + + float coupledGasEnergy = max(ejectaEnergy-eKinetic, 0); + if (debug)fprintf(stdout, "Coupled Gas Energy = %e\n",coupledGasEnergy); + if (dxRatio > 1.0) + coupledGasEnergy *= pow(dxRatio, -6.5); + /* rescale momentum for new shell */ + float shellMetals = zZsun*0.02 * shellMass; + float coupledMetals = ejectaMetal + shellMetals; + + + + if (debug) fprintf(stdout, "Coupled Momentum: %e\n", coupledMomenta/float(nCouple)); + /* Reduce coupled quantities to per-particle quantity and convert to + code quantities. + Hopkins has complicated weights due to complicated geometry. + This is more simple since our coupled particles are + spherically symmetric about the feedback particle*/ + + coupledEnergy /= float(nCouple); + coupledGasEnergy /= float(nCouple); + coupledMass /= float(nCouple); + coupledMetals /= float(nCouple); + coupledMomenta /= float(nCouple); + /* Transform coupled quantities to code units */ + coupledEnergy /= EnergyUnits; + coupledGasEnergy /= EnergyUnits; + coupledMass /= MassUnits; + coupledMetals /= MassUnits; + coupledMomenta /= MomentaUnits; + /* CIC deposit the particles with their respective quantities */ + float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; + for (int n = 0; n < nCouple; n++){ + + FLOAT pX = coupledMomenta*CloudParticleVectorX[n]; + FLOAT pY = coupledMomenta*CloudParticleVectorY[n]; + FLOAT pZ = coupledMomenta*CloudParticleVectorZ[n]; + int np = 1; + + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np,&coupledMass, &density[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np,&coupledMetals, &metals[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + if (pX != 0.0){ + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np,&pX, u, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + } + if (pY != 0.0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&pY, v, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + if (pZ != 0.0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&pZ, w, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + if (coupledEnergy > 0 && DualEnergyFormalism) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&coupledEnergy, totalEnergy, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + if (coupledGasEnergy > 0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&coupledGasEnergy, gasEnergy, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + } + /* Deposit one negative mass particle centered on star to account for + shell mass leaving host cells */ + int np = 1; + shellMass *= -1/MassUnits; + FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMass, &density[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + shellMetals *= -1/MassUnits; + FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMetals, &metals[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + + + /* transform the grid to comoving with star ; wouldnt recommend this on root grid if its too big...*/ + + float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0; + float dsum = 0.0, zsum=0.0, psum=0.0, psqsum =0.0, tesum=0.0, gesum=0.0, kesum=0.0; + float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0; + if (criticalDebug){ + for (int i=0; i 0)? + (u[i]*u[i]+v[i]*v[i]+w[i]*w[i])*MomentaUnits*MomentaUnits + /(2*density[i]*MassUnits)*SolarMass*1e10 + : 0; + + } + + fprintf(stdout, "Sum Mass = %e ", dsum*MassUnits); + fprintf(stdout, "Metals = %e ", zsum*MassUnits); + fprintf(stdout, " momenta magnitude = %e ", sqrt(psqsum)); + + fprintf(stdout, " momenta error = %e ", psum*MomentaUnits); + fprintf(stdout, " KE deposit = %e", kesum); + fprintf(stdout, " Gas energy = %e ", gesum * EnergyUnits); + fprintf(stdout, " TE = %e\n", tesum*EnergyUnits); + /* Break out if something went wrong */ + if (isnan(dsum) || isnan(zsum) || isnan(psqsum)|| isnan(tesum)){ + fprintf(stdout, "MechStars_depositFeedback [370]: Found a nan: %e %f %e %e\n",dsum, zsum, psqsum, tesum); + ENZO_FAIL("MechStars_depositFeedback NaN in grid field!"); + } + } + if (criticalDebug){ + for (int i = 0; i< size ; i++){ + postMass += BaryonField[DensNum][i]; + postZ += BaryonField[MetalNum][i]; + postP += BaryonField[Vel1Num][i]+BaryonField[Vel2Num][i]+BaryonField[Vel3Num][i]; + postPmag += pow(BaryonField[Vel1Num][i]*MomentaUnits,2)+ + pow(BaryonField[Vel2Num][i]*MomentaUnits,2) + +pow(BaryonField[Vel3Num][i]*MomentaUnits,2); + postTE += BaryonField[TENum][i]; + postGE += BaryonField[GENum][i]; + } + fprintf(stderr, "Difference quantities: dxRatio = %f dMass = %e dZ = %e P = %e |P| = %e TE = %e GE = %e coupledGE = %e Ej = %e\n", + dxRatio, (postMass-preMass)*MassUnits, (postZ-preZ)*MassUnits, + (postP - preP)*MomentaUnits, + (sqrt(postPmag) - sqrt(prePmag)), + (postTE-preTE)*EnergyUnits, (postGE-preGE)*EnergyUnits, + coupledGasEnergy*EnergyUnits*nCouple, ejectaEnergy); + if(isnan(postMass) || isnan(postTE) || isnan(postPmag) || isnan(postZ)){ + fprintf(stderr, "NAN IN GRID: %e %e %e %e\n", postMass, postTE, postZ, postP); + ENZO_FAIL("MechStars_depositFeedback.C: 395\n") + if (postGE-preGE < 0.0) + ENZO_FAIL("471"); + } + } + + /* Transform the grid back */ + + transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], + BaryonField[Vel1Num],BaryonField[Vel2Num], + BaryonField[Vel3Num],*up, *vp, *wp, + GridDimension[0], GridDimension[1], + GridDimension[2], -1); + + + delete [] u,v,w, gasEnergy, totalEnergy; + return SUCCESS; +} \ No newline at end of file diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C new file mode 100644 index 000000000..0f1f1fe4e --- /dev/null +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -0,0 +1,251 @@ +/* + Routine to determine feedback quantities and couple them to the + Grid. Coupling follows the implementation of Hopkins 2017 with + modification for Enzo's fixed grid + + 07/2019: Azton Wells + */ +#include +#include +#include +#include "ErrorExceptions.h" +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "fortran.def" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" + + + int determineSN(float age, int* nSNII, int* nSNIA, float massMsun, + float TimeUnits, float dtFixed); + int determineWinds(float age, float* eWinds, float* zWinds, float* mWinds, + float massMsun, float zZsun, float TimeUnits, float dtFixed); + int checkCreationCriteria(float* Density, float* Metals, + float* Temperature,float* DMField, + float* Vel1, float* Vel2, float* Vel3, + float* CoolingTime, int GridDim, + float* shieldedFraction, float* freeFallTime, + float* dynamicalTime, int i, int j, int k, + float Time, float* RefinementField, float CellWidth); + int FindField(int field, int farray[], int numfields); + int GetUnits(float *DensityUnits, float *LengthUnits, + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, float *MassUnits, FLOAT Time); + + + + + +int grid::MechStars_FeedbackRoutine(int level, float* mu_field) +{ + + // fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", + // SingleSN, StellarWinds, UnrestrictedSN); + float stretchFactor = 1.4;//1/sqrt(2) to cover cell diagonal + /* Get units to use */ + + int dim, i, j, k, index, size, field, GhostZones = NumberOfGhostZones; + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + + /* Compute size (in floats) of the current grid. */ + + size = 1; + for (dim = 0; dim < GridRank; dim++) + size *= GridDimension[dim]; + int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, + HMNum, H2INum, H2IINum, DINum, DIINum, HDINum; + /* Find fields: density, total energy, velocity1-3. */ + + if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) { + fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); + return FAIL; + } + /* Set the units */ + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { + fprintf(stderr, "Error in GetUnits.\n"); + return FAIL; + } + double dx = CellWidth[0][0]; + MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; + /* + get metallicity field and set flag; assumed true thoughout feedback + since so many quantities are metallicity dependent + */ + int MetallicityField = FALSE, MetalNum; + if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) + != -1) + MetallicityField = TRUE; + else + MetalNum = 0; + + int numSN = 0; + + /* Begin Iteration of all particles */ + // printf("\nIterating all particles "); + for (int pIndex=0; pIndex < NumberOfParticles; pIndex++){ + // if (ParticleType[pIndex] != 1 && debug) + // fprintf(stdout,"PARTICLE: %d %d %e %f\n", ParticleType[pIndex], + // ParticleNumber[pIndex], + // ParticleMass[pIndex], + // ParticleAttribute[0][pIndex]); + /* Selection criteria */ + + if (ParticleType[pIndex] == PARTICLE_TYPE_STAR + && ParticleMass[pIndex] > 0.0 + && ParticleAttribute[0][pIndex] > 0.0){ + + // if (StarMakerAgeCutoff) + // if ((Time-ParticleAttribute[0][pIndex]) + // *TimeUnits/(150*3.1557e7) > 150) + // continue; + + /* get index of cell hosting particle */ + float xp = ParticlePosition[0][pIndex]; + float yp = ParticlePosition[1][pIndex]; + float zp = ParticlePosition[2][pIndex]; + + int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; + int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; + int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; + + + + /* error check particle position; Cant be on the border or outside grid + If on border, reposition to within grid for CIC deposit */ + FLOAT age = (Time-ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13;// Myr + + float gridDx = GridDimension[0]*dx; + float gridDy = GridDimension[1]*dx; + float gridDz = GridDimension[2]*dx; + /* Keep particle 2 cells from edge since we cant transfer to + neighboring grids */ + float borderDx = (stretchFactor+1)*dx; + if (xp > CellLeftEdge[0][0]+gridDx + || xp < CellLeftEdge[0][0] + || yp > CellLeftEdge[1][0]+gridDy + || yp < CellLeftEdge[1][0] + || zp > CellLeftEdge[2][0]+gridDz + || zp < CellLeftEdge[2][0]){ + fprintf(stderr, "Particle %d out of grid!\nage: %d, pos: %f, %f, %f GridEdge: %f %f %f", pIndex, + age, xp, yp, zp, CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0] + ); + EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); + } + int shifted = 0; + + if (xp < CellLeftEdge[0][0]+borderDx){ + xp = CellLeftEdge[0][0]+borderDx+0.5*dx; + shifted ++; + } + if (xp > CellLeftEdge[0][0]+gridDx-borderDx){ + xp = CellLeftEdge[0][0]+gridDx-borderDx-0.5*dx; + shifted = 1; + } + if (yp < CellLeftEdge[1][0]+borderDx){ + yp = CellLeftEdge[1][0]+borderDx+0.5*dx; + shifted = 1; + } + if (yp > CellLeftEdge[1][0]+gridDx-borderDx){ + yp = CellLeftEdge[1][0]+gridDx-borderDx-0.5*dx; + shifted = 1; + } + if (zp < CellLeftEdge[2][0]+borderDx){ + zp = CellLeftEdge[2][0]+borderDx+0.5*dx; + shifted = 1; + } + if (zp > CellLeftEdge[2][0]+gridDx-borderDx){ + zp = CellLeftEdge[2][0]+gridDx-borderDx-0.5*dx; + shifted = 1; + } + if (shifted > 0){ + if (debug) + fprintf(stderr, "Particle position shifted away from edge: %e: %f %f %f\n%f %f %f\n", + age,xp, yp, zp, CellLeftEdge[0][0]+borderDx, CellLeftEdge[1][0]+borderDx, CellLeftEdge[2][0]+borderDx); + int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; + int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; + int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; + } + /* REMOVED: Check for continual formation, i guess. Only really done because + Hopkins did it. We can just make more stars next timestep I guess. + On the other hand, the function is already written... */ + /* create some stuff. This is a lot of overhead for something + optional... */ + + /* Start actual feedback: Supernova calculations */ + index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; + int nSNII = 0; + int nSNIA = 0; + float SNMassEjected = 0, SNMetalEjected = 0; + // printf("Checking particle: %f %e \n", age, ParticleMass[pIndex]*MassUnits); + /* determine how many supernova events */ + if (SingleSN) + { + fprintf(stdout,"Checking for SN\n"); + determineSN(age, &nSNII, &nSNIA, ParticleMass[pIndex]*MassUnits, + TimeUnits, dtFixed); + numSN += nSNII+nSNIA; + if (true) if (nSNII > 0 || nSNIA > 0) + fprintf(stdout,"\n\nSUPERNOVAE!!!! %d %d level = %d\n\n", nSNII, nSNIA, level); + if (nSNII > 0 || nSNIA > 0){ + /* set feedback qtys based on number and types of events */ + /* 1e51 erg per sn */ + float energySN = (nSNII + nSNIA)*1e51; + + /*10.5 Msun ejecta for type II and IA*/ + SNMassEjected = (nSNII+nSNIA)*10.5; + /* Metal yeilds from starburst 99 */ + float zZsun = min(BaryonField[MetalNum][index]/BaryonField[DensNum][index]/0.02, 1e-4); + SNMetalEjected = nSNII*(1.91+0.0479*max(zZsun, 1.65)); + SNMetalEjected += nSNIA*(1.4); + MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, + &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], + &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], + ip, jp, kp, size, mu_field, 0); + } + } + + float windEnergy=0, windMass=0, windMetals=0; + /* Do the same for winds. Cooling Radius is very small, + So almost no energy is coupled, but some mass may be. */ + + + if (StellarWinds) + { + // printf("Checking Winds\n"); + float zZsun = min(BaryonField[MetalNum][index]/BaryonField[DensNum][index]/0.02, 1e-8); + determineWinds(age, &windEnergy, &windMass, &windMetals, + ParticleMass[pIndex]*MassUnits, zZsun, + TimeUnits, dtFixed); + + if (windMass > 1e-5 && windEnergy > 1e10){ + MechStars_DepositFeedback(windEnergy, windMass, windMetals, + &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], + &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], + ip, jp, kp, size, mu_field, 1); + } else { + windMass = 0.0; + windEnergy= 0.0; + windMetals = 0.0; + } + + } + if (windMass > 0.0 || SNMassEjected > 0){ + if (debug) printf("Subtracting off mass %e\n",(windMass+SNMassEjected)); + ParticleMass[pIndex] -= (windMass+SNMassEjected)/MassUnits; + } + // printf("Post-feedback MP = %e\n", ParticleMass[pIndex]*MassUnits); + } + }// end iteration over particles + + return SUCCESS; +} \ No newline at end of file diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index ef121bcb5..857231bdd 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -830,7 +830,18 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, for (i = NumberOfNewParticlesSoFar; i < NumberOfNewParticles; i++) tg->ParticleType[i] = NormalStarType; } + if (STARMAKE_METHOD(MECHANICAL)){ + NumberOfNewParticlesSoFar = NumberOfParticles; + NumberOfNewParticles = MechStars_Creation(tg, temperature, + dmfield, level, cooling_time, MaximumNumberOfNewParticles, + &NumberOfNewParticles); + + for (i = NumberOfNewParticlesSoFar; i < NumberOfNewParticles; i++) + tg->ParticleType[i] = NormalStarType; + + + } if (STARMAKE_METHOD(MOM_STAR)) { //---- UNIGRID ALGORITHM (NO JEANS MASS) @@ -1430,11 +1441,9 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, /* Move any new particles into their new homes. */ - if (NumberOfNewParticles > 0) { if (debug) - printf("Grid_StarParticleHandler: New StarParticles = %"ISYM"\n", NumberOfNewParticles); /* Set the particle numbers. The correct indices will be assigned in CommunicationUpdateStarParticleCount in StarParticleFinalize later.*/ @@ -1544,7 +1553,40 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, ParticleAttribute[2], ParticleType, &RadiationData.IntegratedStarFormation); } // end: if NORMAL_STAR - + if (STARFEED_METHOD(MECHANICAL)){ + float mu_field [size]; + for (k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { + for (j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { + for (i = GridStartIndex[0]; i <= GridEndIndex[0]; i++) { + + index = i + j*GridDimension[0] + k*GridDimension[0]*GridDimension[1]; + mu_field[index] = 0.0; + // calculate mu + + if (MultiSpecies == 0) { + mu_field[index] = Mu; + } else { + + if (IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, + HMNum, H2INum, H2IINum, DINum, DIINum, HDINum) == FAIL) { + ENZO_FAIL("Error in grid->IdentifySpeciesFields.\n"); + } + + mu_field[index] = BaryonField[DeNum][index] + BaryonField[HINum][index] + BaryonField[HIINum][index] + + (BaryonField[HeINum][index] + BaryonField[HeIINum][index] + BaryonField[HeIIINum][index])/4.0; + if (MultiSpecies > 1) { + mu_field[index] += BaryonField[HMNum][index] + (BaryonField[H2INum][index] + BaryonField[H2IINum][index])/2.0; + } + if (MultiSpecies > 2) { + mu_field[index] += (BaryonField[DINum][index] + BaryonField[DIINum][index])/2.0 + (BaryonField[HDINum][index]/3.0); + } + + } + } + } + } + MechStars_FeedbackRoutine(level, &mu_field[0]); + } if (STARFEED_METHOD(MOM_STAR)) { //---- UNIGRID (NON-JEANS MASS) VERSION WITH MOMENTUM diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C new file mode 100644 index 000000000..cbbe67545 --- /dev/null +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -0,0 +1,153 @@ +/* + Routine actually checks to see whether the input grid + is capable of star formation + + 07/2019: Azton Wells + */ +#include +#include +#include +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "fortran.def" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" + + int GetUnits(float *DensityUnits, float *LengthUnits, + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, float *MassUnits, float Time); +#define PASS 1; +int checkCreationCriteria(float* Density, float* Metals, + float* Temperature,float* DMField, + float* Vel1, float* Vel2, float* Vel3, + float* CoolingTime, int* GridDim, + float* shieldedFraction, float* freeFallTime, + float* dynamicalTime, int i, int j, int k, + float Time, float* RefinementField, float CellWidth) +{ + bool status = PASS; + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, &MassUnits, Time) == FAIL) { + fprintf(stderr, "Error in GetUnits.\n"); + return FAIL; + } + int index = i+j*GridDim[0]+k*GridDim[0]*GridDim[1]; + int iminus = index-1; + int iplus = index+1; + int jminus =i+(j-1)*GridDim[0]+k*GridDim[0]*GridDim[1]; + int jplus = i+(j+1)*GridDim[0]+k*GridDim[0]*GridDim[1]; + int kminus = i+j*GridDim[0]+(k-1)*GridDim[0]*GridDim[1]; + int kplus = i+j*GridDim[0]+(k+1)*GridDim[0]*GridDim[1]; + /* + Checking creation criteria! + */ + // if this isnt finest grid in this space, continue + //if (RefinementField[index] != 0) return FAIL; + /* Baryon overdensity. Take a local mean, but + weight the central cell more*/ + float dmean = (Density[index]*10.0+Density[iminus] + + Density[iplus]+Density[jplus] + + Density[jminus]+Density[kminus] + + Density[kplus])/17.0; + if (dmean < StarMakerOverDensityThreshold) + { + status = FAIL; + } + if (debug && status) fprintf(stdout, "Passed Density: %e: %e\n", + dmean,StarMakerOverDensityThreshold); + /* in addition to the converging flow check, we check + the virial parameter of the gas to see if it is + locally gravitationally bound*/ + + + float div = 0.0; //divergence + float alpha = 0.0; //virial parameter + float vfactor= 0.0; //norm of velocity gradient tensor + float cSound = 0.0; //sound speed + float dxvx, dxvy, dxvz, dyvx, dyvy, dyvz, dzvx, dzvy, dzvz; + dxvx = (Vel1[iplus] - Vel1[iminus])/2.0; + dxvy = (Vel2[iplus] - Vel2[iminus])/2.0; + dxvz = (Vel3[iplus] - Vel3[iminus])/2.0; + + dyvx = (Vel1[jplus] - Vel1[jminus])/2.0; + dyvy = (Vel2[jplus] - Vel2[jminus])/2.0; + dyvz = (Vel3[jplus] - Vel3[jminus])/2.0; + + dzvx = (Vel1[kplus] - Vel1[kminus])/2.0; + dzvy = (Vel2[kplus] - Vel2[kminus])/2.0; + dzvz = (Vel3[kplus] - Vel3[kminus])/2.0; + + /* Chck for converging flow */ + + div = dxvx+dyvy+dzvz; + if (div > 0.0) status = FAIL; + + /* check for virial parameter */ + + vfactor = (dxvx*dxvx+dxvy*dxvy+dxvz*dxvz + +dyvx*dyvx+dyvy*dyvy+dyvz*dyvz + +dzvx*dzvx+dzvy*dzvy+dzvz*dzvz); + + /* approximate taking gas as monatomic and mu = 0.6*/ + float Gcode = GravConst*DensityUnits*pow(TimeUnits,2); + float KBcode = kboltz*MassUnits/(LengthUnits*CellWidth)/pow(TimeUnits,2); + cSound = sqrt(5/3*kboltz*Temperature[index]/mh/0.6)/VelocityUnits; + alpha = ((vfactor) + pow(cSound/(CellWidth), 2.0)) + / (8.0 * M_PI* Gcode * Density[index]); + + // printf("CreationCriteria vf = %e cs = %e Gcode = %e Alpha = %e\n", vfactor, cSound, Gcode, alpha); + + if (alpha > 1.0) status = FAIL; + /* Is cooling time < dynamical time or temperature < 1e4 */ + + if (Temperature[index] > 1e4) + { + float totalDensity = Density[index] + +DMField[index]*DensityUnits; + float Tdyn = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); + if (Tdyn/TimeUnits < CoolingTime[index]) status = FAIL; + } + /* is gas mass > critical jeans mass? */ + + float baryonMass = Density[index]*DensityUnits + *LengthUnits*LengthUnits*LengthUnits + *CellWidth*CellWidth*CellWidth + /SolarMass; + float IsoSndSpeed = 1.3095e8 * Temperature[index]; + float jeansMass = pi/(6.0*pow(Density[index]*DensityUnits, 0.5)) + *pow(pi*IsoSndSpeed/GravConst, 1.5)/SolarMass; + if (jeansMass > max(baryonMass, 1e3)) status = FAIL; + /* Is self Shielded fraction > 0.0 by Krumholz & Gnedin */ + + float gradRho = (Density[index+1]-Density[index-1]) + *(Density[index+1]-Density[index-1]); + gradRho += (Density[jplus]-Density[jminus]) + *(Density[jplus]-Density[jminus]); + gradRho += (Density[kplus]-Density[kminus]) + *(Density[kplus]-Density[kminus]); + gradRho = pow(gradRho, 0.5); + // factors were given in physical units + float TauFactor = 434.8 *LengthUnits*LengthUnits / MassUnits; + float Tau = TauFactor * Density[index] *(CellWidth+Density[index]/gradRho); + + float Phi = 0.756*pow(1+3.1*Metals[index]/0.02, 0.365); + + float Psi = 0.6*Tau*(0.01+Metals[index]/0.02)/ + log(1+0.6*Phi+0.01*Phi*Phi); + + *shieldedFraction = 1 - 3/(1+4*Psi); + if (*shieldedFraction < 0) status = FAIL; + + *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; + if (status) fprintf(stdout, "passed creation criteria\n"); + return status; + +} \ No newline at end of file diff --git a/src/enzo/MechStars_determineSN.C b/src/enzo/MechStars_determineSN.C new file mode 100644 index 000000000..dc86dfed0 --- /dev/null +++ b/src/enzo/MechStars_determineSN.C @@ -0,0 +1,92 @@ +/* + Probabilistically determines supernova based on analytic + starburst99 simulations. fits taken from Hopkins 2017 + + 07/2019: Azton Wells + */ + +#include +#include +#include +#include +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "StarParticleData.h" +#include "phys_constants.h" + +int determineSN(float age, int* nSNII, int* nSNIA, + float massMsun, float TimeUnits, float dt){ + + if (NEvents > 0){ + *nSNII = 1; + NEvents -= 1; + return SUCCESS; + } + /* else, calculate SN rate, probability and determine number of events */ + int seed = clock(); + float RII=0, RIA=0, PII=0, PIA=0, random = 0; + if (SingleSN == 1 && NEvents < 0) + { + // printf("Calculating rates\n"); + /* age-dependent rates */ + if (age < 3.401) + { + RII = 0.0; + RIA = 0.0; + } + if (3.401 <= age < 10.37) + { + RII = 5.408e-4; + RIA = 0.0; + } + if (10.37 <= age < 37.53) + { + RII = 2.516e-4; + RIA = 0.0; + } + if (37.52 <= age) + { + RII = 0.0; + RIA = 5.2e-8+1.6e-5*exp(-1.0*pow((age-50.0)/10.0, 2)/2.0); + } + // printf("Rates: %f %f %f\n", age, RII, RIA); + /* rates -> probabilities */ + if (RII > 0){ + srand(seed); + PII = RII * massMsun / 3.1557e13 *TimeUnits*dt; + // printf("PII =%f\n %f %e %f\n", PII, RII, massMsun, age); + random = float(rand())/float(RAND_MAX); + if (PII > 1.0 && UnrestrictedSN == TRUE){ + int round = (int)PII; + *nSNII = round; + PII -= round; + } + int psn = *nSNII; + if (random < PII){ + *nSNII = psn+1; + } + } + // printf("RANDOM = %f\n", random); + // printf("N SNII=%d\n",*nSNII); + + if (RIA > 0){ + srand(seed); + PIA = RIA*massMsun/3.1557e13*TimeUnits*dt; + float random = float(rand())/float(RAND_MAX); + + if (PIA > 1.0 && UnrestrictedSN == TRUE) + { + int round = int(PIA); + *nSNIA = round; + PIA -= round; + } + int psn = *nSNIA; + + if (random < PIA) + *nSNIA = psn+1; + } + } + return SUCCESS; + +} \ No newline at end of file diff --git a/src/enzo/MechStars_determineWinds.C b/src/enzo/MechStars_determineWinds.C new file mode 100644 index 000000000..1ba23dd71 --- /dev/null +++ b/src/enzo/MechStars_determineWinds.C @@ -0,0 +1,73 @@ +/* + Determines wind feedback parameters according to fits in Hopkins 2017: + These fits are known to be erroneous, need to re-run and fit using SB99 sims. + + 07/2019: Azton Wells + */ + +#include +#include +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" + +int determineWinds(float age, float* eWinds, float* mWinds, float* zWinds, + float massMsun, float zZsun, float TimeUnits, float dtFixed){ + + bool oldEnough = (age < 0.01)?(false):(true); + float windE = 0, windM = 0, windZ = 0.0; + float wind_factor = 0.0; + float e_factor = 0.0; + // I dont want to deal with new particles + // printf("Computing Winds for age = %f, Msun = %e\n", age, massMsun); + if (StellarWinds && oldEnough && massMsun > 100){ + + if (0.01 < age < 1.0){ + wind_factor =4.763 * min((0.01 + zZsun), 1.0) ; + } + if (1 <= age < 3.5){ + wind_factor = 4.763*min(0.01+zZsun, 1.0)* + pow(age, 1.45+0.08*min(log(zZsun), 1.0)); + } + if (3.5 <= age <= 100){ + wind_factor = 29.4*pow(age/3.5, -3.25)+0.0042; + + } + if (100 < age){ + wind_factor = 0.42*pow(age/1000, -1.1)/(19.81/log(age)); + e_factor = 4.83; + } + if (age <= 100){ + float d = powl(1+age/2.5, 1.4); + float a50 = powl(double(age)/50.0, 5.0); + e_factor = 5.94e4 / d + a50 +4.83; + if (isnan(e_factor)) + printf("efactor nan d = %d a50 = %f age/50 = %f\n", + d, a50, double(age)*1.0/50.0); + } + windM = massMsun * wind_factor; //Msun/Gyr + windM = windM*dtFixed/TimeUnits/3.1557e16; //Msun/Gyr + //printf("First winds mass = %e\n", windM); + //printf("eFactor = %f age = %f\n", e_factor, age); + if (windM > massMsun){ + printf("Winds too large Mw = %e, Mp = %e age=%f, Z = %e\n", + windM, massMsun, age, zZsun); + windM = 0.125*massMsun; // limit loss to huge if necessary. + } + windZ = 0.0278+ 0.0041* min(max(zZsun, 1.65), 5.0)*windM; + windE = e_factor * 1e12 * windM; // what the actual fuck are the units here??? + *mWinds = windM; + *zWinds = windZ; + *eWinds = windE; + // printf("Winds Mass = %e\n",*mWinds); + // printf("Winds Energy = %e\n", *eWinds); + // printf("wind_factor = %f\n", wind_factor); + // printf("energy_factor = %f\n", e_factor); + // printf("Metallicity = %e\n", zZsun); + } + + return SUCCESS; +} \ No newline at end of file diff --git a/src/enzo/MechStars_transformComovingWithStar.C b/src/enzo/MechStars_transformComovingWithStar.C new file mode 100644 index 000000000..26343379d --- /dev/null +++ b/src/enzo/MechStars_transformComovingWithStar.C @@ -0,0 +1,46 @@ + + +#include +#include "macros_and_parameters.h" +#include "typedefs.h" + + +int transformComovingWithStar(float* Density, float* Metals, + float* Vel1, float* Vel2, float* Vel3, + float up, float vp, float wp, + int sizeX, int sizeY, int sizeZ, int direction){ + /* transform velocities to momenta or back and make them comoving with the star particle */ + if (direction > 0){ + + /* To comoving with star */ + for (int k = 0; k < sizeZ; k++){ + for (int j = 0; j> (A) & 1) #define STARFEED_METHOD(A) (StarParticleFeedback >> (A) & 1) From 0eefcb72c11a3152f101abcce05c061c0f537d15 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 10 Aug 2019 12:55:41 -0700 Subject: [PATCH 002/115] Corrected error in rates determination --- src/enzo/MechStars_determineSN.C | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/enzo/MechStars_determineSN.C b/src/enzo/MechStars_determineSN.C index dc86dfed0..41f18c83e 100644 --- a/src/enzo/MechStars_determineSN.C +++ b/src/enzo/MechStars_determineSN.C @@ -9,6 +9,7 @@ #include #include #include +#include "ErrorExceptions.h" #include "macros_and_parameters.h" #include "typedefs.h" #include "global_data.h" @@ -25,6 +26,8 @@ int determineSN(float age, int* nSNII, int* nSNIA, } /* else, calculate SN rate, probability and determine number of events */ int seed = clock(); + *nSNII = 0; + *nSNIA = 0; float RII=0, RIA=0, PII=0, PIA=0, random = 0; if (SingleSN == 1 && NEvents < 0) { @@ -35,12 +38,12 @@ int determineSN(float age, int* nSNII, int* nSNIA, RII = 0.0; RIA = 0.0; } - if (3.401 <= age < 10.37) + if (3.401 <= age && age< 10.37) { RII = 5.408e-4; RIA = 0.0; } - if (10.37 <= age < 37.53) + if (10.37 <= age && age < 37.53) { RII = 2.516e-4; RIA = 0.0; @@ -50,7 +53,7 @@ int determineSN(float age, int* nSNII, int* nSNIA, RII = 0.0; RIA = 5.2e-8+1.6e-5*exp(-1.0*pow((age-50.0)/10.0, 2)/2.0); } - // printf("Rates: %f %f %f\n", age, RII, RIA); + // fprintf(stdout, "Rates: %f %f %f\n", age, RII, RIA); /* rates -> probabilities */ if (RII > 0){ srand(seed); @@ -62,6 +65,9 @@ int determineSN(float age, int* nSNII, int* nSNIA, *nSNII = round; PII -= round; } + if (PII > 1.0 && !UnrestrictedSN){ + ENZO_FAIL("PII too large!"); + } int psn = *nSNII; if (random < PII){ *nSNII = psn+1; From ab507c5e6070f070d13b0a4feb2b07fee54cda1e Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 10 Aug 2019 13:09:16 -0700 Subject: [PATCH 003/115] edited make to include Mechstars --- src/enzo/Make.config.objects | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index 15f650163..7c7221a35 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -76,6 +76,7 @@ OBJS_CONFIG_LIB = \ CheckShearingBoundaryConsistency.o \ chtable.o \ cic_deposit.o \ + cic_deposit_mech_stars.o \ cic_deposit_c.o \ cic_flag.o \ cic_flag_c.o \ @@ -545,6 +546,9 @@ OBJS_CONFIG_LIB = \ Grid_KHInitializeGrid.o \ Grid_KHInitializeGridRamp.o \ Grid_MagneticFieldResetter.o \ + Grid_MechStarsCreation.o\ + Grid_MechStarsDepositFeedback.o\ + Grid_MechStarsFeedbackRoutine.o\ Grid_MirrorStarParticles.o \ Grid_MoveAllParticles.o \ Grid_MoveAllStars.o \ @@ -733,6 +737,10 @@ OBJS_CONFIG_LIB = \ mbh_maker.o \ mcooling.o \ MakeFieldConservative.o\ + MechStars_checkCreationCriteria.o\ + MechStars_determineSN.o\ + MechStars_determineWinds.o\ + MechStars_transformComovingWithStar.o\ MemoryAllocationRoutines.o \ MemoryPoolRoutines.o \ MersenneTwister.o \ From 48e4eb3772559469dc5781096f914b7648425ec8 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 10 Aug 2019 13:14:41 -0700 Subject: [PATCH 004/115] forgot some file updates --- src/enzo/Grid_MechStarsDepositFeedback.C | 17 ++++++++++++----- src/enzo/Grid_MechStarsFeedbackRoutine.C | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 9061bb8d4..72c070388 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -235,10 +235,10 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* Hopkins uses ratio of masses to determine how to couple. Radius here is well-known and fixed, so we use that instead */ if (dxRatio > 1.0){ - if (ejectaEnergy < 1e5 || dxRatio > 100){ - coupledEnergy = 0.0; - coupledMomenta = 0.0; - }else{ + // if (ejectaEnergy < 1e5 || dxRatio > 100){ + // coupledEnergy = 0.0; + // coupledMomenta = 0.0; + // }else{ coupledEnergy = ejectaEnergy*pow(dxRatio, -6.5); usePt = 1; @@ -249,10 +249,17 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if (dxRatio > 4) Efactor = coupledEnergy/ejectaEnergy*pow(dxRatio,3); coupledMomenta = 4.8e5*pow(nmean, -1.0/7.0) * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; //Msun*km/s - } + // } } else { if (debug)fprintf(stdout, "Directly calculating momenta using energy = %e and mass = %e ", ejectaEnergy, ejectaMass); + + /* + The multiplicative factor tacked on the end of the momentum here + ensures a smooth connection from p = sqrt(2*m*e) to the p=pt at r_cool + above. Without it, there are large discontinuities where the different + forms of momenta meet (dx=r_cool) + */ coupledMomenta = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5) * pow(1.0+dxRatio, 3.75*pow(nmean, -1./14.))/SolarMass/1e5; //Msun*km/s if (debug)fprintf(stdout, "Calculated p = %e ", coupledMomenta); diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 0f1f1fe4e..0b38d142f 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -190,7 +190,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) /* determine how many supernova events */ if (SingleSN) { - fprintf(stdout,"Checking for SN\n"); + fprintf(stdout,"Checking for SN age = %f\n", age); determineSN(age, &nSNII, &nSNIA, ParticleMass[pIndex]*MassUnits, TimeUnits, dtFixed); numSN += nSNII+nSNIA; From c98f4a2a3462ffb59ab55c6c39d1dc60ec7022fc Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 10 Aug 2019 15:24:54 -0700 Subject: [PATCH 005/115] Hopefully all these files will help it work on frontera! --- src/enzo/Make.mach.azton-intel | 108 +++++++++++++++++ src/enzo/cic_deposit_mech_stars.F | 189 ++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 src/enzo/Make.mach.azton-intel create mode 100755 src/enzo/cic_deposit_mech_stars.F diff --git a/src/enzo/Make.mach.azton-intel b/src/enzo/Make.mach.azton-intel new file mode 100644 index 000000000..3bfd529fb --- /dev/null +++ b/src/enzo/Make.mach.azton-intel @@ -0,0 +1,108 @@ +#======================================================================= +# +# FILE: Make.mach.linux-gnu +# +# DESCRIPTION: Makefile settings for a machine running Ubuntu +# +# AUTHOR: Rick Wagner (rick@ucsd.edu) +# +# DATE: 2008-09-16 +# +# This configuration assumes that build-essentials, gfortran, +# OpenMPI and HDF5 have been installed using apt-get. +# +#======================================================================= + +MACH_TEXT = Use apt-get to install libhdf5-serial-dev gfortran openmpi-bin libopenmpi-dev +MACH_VALID = 1 +MACH_FILE = Make.mach.linux-gnu + +#----------------------------------------------------------------------- +# Install paths (local variables) +#----------------------------------------------------------------------- + +LOCAL_GRACKLE_INSTALL = $(HOME)/research/grackle_noomp +LOCAL_HYPRE_INSTALL = $(HOME)/local + +#----------------------------------------------------------------------- +# Compiler settings +#----------------------------------------------------------------------- + +MACH_CPP = fpp # C preprocessor command + +# With MPI + +MACH_CC_MPI = mpiicc # C compiler when using MPI +MACH_CXX_MPI = mpiicpc # C++ compiler when using MPI +MACH_FC_MPI = mpiifort # Fortran 77 compiler when using MPI +MACH_F90_MPI = mpiifort # Fortran 90 compiler when using MPI +MACH_LD_MPI = mpiicpc # Linker when using MPI + +# Without MPI + +MACH_CC_NOMPI = icc # C compiler when not using MPI +MACH_CXX_NOMPI = icpc # C++ compiler when not using MPI +MACH_FC_NOMPI = ifort # Fortran 77 compiler when not using MPI +MACH_F90_NOMPI = ifort # Fortran 90 compiler when not using MPI +MACH_LD_NOMPI = icpc # Linker when not using MPI + +#----------------------------------------------------------------------- +# Machine-dependent defines +#----------------------------------------------------------------------- + +MACH_DEFINES = -DLINUX -DH5_USE_16_API + +#----------------------------------------------------------------------- +# Compiler flag settings +#----------------------------------------------------------------------- + + +MACH_CPPFLAGS = -P -traditional +MACH_CFLAGS = +MACH_CXXFLAGS = +MACH_FFLAGS = -fno-second-underscore -ffixed-line-length-132 +MACH_F90FLAGS = -fno-second-underscore +MACH_LDFLAGS = + +#----------------------------------------------------------------------- +# Optimization flags +#----------------------------------------------------------------------- + +MACH_OPT_WARN = -Wall -g +MACH_OPT_DEBUG = -g +MACH_OPT_HIGH = -O2 -g -march=native +MACH_OPT_AGGRESSIVE = -O3 -g -march=native + +#----------------------------------------------------------------------- +# Includes +#----------------------------------------------------------------------- + +LOCAL_INCLUDES_MPI = # MPI includes +LOCAL_INCLUDES_HDF5 = -I$(HOME)/research/depend/hdf5-1.8.14/hdf5/include # HDF5 includes +LOCAL_INCLUDES_HYPRE = -I$(LOCAL_HYPRE_INSTALL)/include +LOCAL_INCLUDES_PAPI = # PAPI includes +LOCAL_INCLUDES_GRACKLE = -I$(LOCAL_GRACKLE_INSTALL)/include + +MACH_INCLUDES = $(LOCAL_INCLUDES_HDF5) +MACH_INCLUDES_MPI = $(LOCAL_INCLUDES_MPI) +MACH_INCLUDES_HYPRE = $(LOCAL_INCLUDES_HYPRE) +MACH_INCLUDES_PAPI = $(LOCAL_INCLUDES_PAPI) +MACH_INCLUDES_GRACKLE = $(LOCAL_INCLUDES_GRACKLE) + +#----------------------------------------------------------------------- +# Libraries +#----------------------------------------------------------------------- + +LOCAL_LIBS_MPI = # MPI libraries +LOCAL_LIBS_HDF5 = -L$(HOME)/research/depend/hdf5-1.8.14/hdf5/lib -lhdf5 +LOCAL_LIBS_HYPRE = -L$(LOCAL_HYPRE_INSTALL)/lib -lHYPRE +LOCAL_LIBS_PAPI = # PAPI libraries +LOCAL_LIBS_MACH = -L/opt/intel/compilers_and_libraries_2019.4.243/linux/compiler/lib/intel64_lin\ + -lm -lstdc++ -lcilkrts -lifcore -lquadmath # Machine-dependent libraries +LOCAL_LIBS_GRACKLE = -L$(LOCAL_GRACKLE_INSTALL)/lib -lgrackle + +MACH_LIBS = $(LOCAL_LIBS_HDF5) $(LOCAL_LIBS_MACH) +MACH_LIBS_MPI = $(LOCAL_LIBS_MPI) +MACH_LIBS_HYPRE = $(LOCAL_LIBS_HYPRE) +MACH_LIBS_PAPI = $(LOCAL_LIBS_PAPI) +MACH_LIBS_GRACKLE = $(LOCAL_LIBS_GRACKLE) \ No newline at end of file diff --git a/src/enzo/cic_deposit_mech_stars.F b/src/enzo/cic_deposit_mech_stars.F new file mode 100755 index 000000000..4b45b0ae7 --- /dev/null +++ b/src/enzo/cic_deposit_mech_stars.F @@ -0,0 +1,189 @@ +#include "fortran.def" + +c======================================================================= +c////////////////////// SUBROUTINE CIC_DEPOSIT \\\\\\\\\\\\\\\\\\\\\\\ +c + subroutine cic_deposit_ms(posx, posy, posz, ndim, npositions, + & mass, field, leftedge, + & dim1, dim2, dim3, cellsize) +c +c PERFORMS 1/2/3D CLOUD-IN-CELL INTERPOLATION FROM FIELD TO SUMFIELD +c +c written by: Greg Bryan +c date: January, 1998 +c modified1: +c +c PURPOSE: This routine performs a three-dimension, second-order +c interpolation from field to sumfield (without clearing sumfield +c first) at the positions specified. +c +c INPUTS: +c ndim - dimensionality +c cellsize - the cell size of field +c dim1,2,3 - real dimensions of field +c leftedge - the left edge(s) of field +c npositions - number of particles +c posx,y,z - particle positions +c sumfield - 1D field (length npositions) of masses +c +c OUTPUT ARGUMENTS: +c field - field to be deposited to +c +c EXTERNALS: +c +c LOCALS: +c +c----------------------------------------------------------------------- +c + implicit NONE +#include "fortran_types.def" +c +c----------------------------------------------------------------------- +c +c argument declarations +c + INTG_PREC dim1, dim2, dim3, npositions, ndim + P_PREC posx(npositions), posy(npositions), posz(npositions) + R_PREC leftedge(3) + R_PREC mass(npositions) + R_PREC field(dim1, dim2, dim3) + R_PREC cellsize +c +c locals +c + INTG_PREC iii, jjj, kkk + INTG_PREC i1, j1, k1, n + R_PREC xpos, ypos, zpos, dx, dy, dz, fact + R_PREC edge1, edge2, edge3, half + parameter (half = 0.5001) +c +c\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////// +c======================================================================= +c + +! write(0,*) npositions, leftedge, dim1, dim2, dim3, cellsize + + fact = 1.0/cellsize + edge1 = real(dim1) - half + edge2 = real(dim2) - half + edge3 = real(dim3) - half +c +c 1D +c + if (ndim .eq. 1) then +c + do n=1, npositions +c +c Compute the position of the central cell +c + xpos = min(max((posx(n) - leftedge(1))*fact, half), edge1) +c +c Convert this into an integer index +c + i1 = int(xpos + 0.5) +c +c Compute the weights +c + dx = real(i1) + 0.5 - xpos +c +c Interpolate from field into sumfield +c + field(i1 ,1,1) = field(i1 ,1,1) + mass(n)*dx + field(i1+1,1,1) = field(i1+1,1,1) + mass(n)*(1.0-dx) +c + enddo +c + endif +c +c 2D +c + if (ndim .eq. 2) then +c + do n=1, npositions +c +c Compute the position of the central cell +c + xpos = min(max((posx(n) - leftedge(1))*fact, half), edge1) + ypos = min(max((posy(n) - leftedge(2))*fact, half), edge2) +c +c Convert this into an integer index +c + i1 = int(xpos + 0.5) + j1 = int(ypos + 0.5) +c +c Compute the weights +c + dx = real(i1) + 0.5 - xpos + dy = real(j1) + 0.5 - ypos +c +c Interpolate from field into sumfield +c + field(i1 ,j1 ,1) = field(i1 ,j1 ,1) + + & mass(n)* dx * dy + field(i1+1,j1 ,1) = field(i1+1,j1 ,1) + + & mass(n)*(1.0-dx)* dy + field(i1 ,j1+1,1) = field(i1 ,j1+1,1) + + & mass(n)* dx *(1.0-dy) + field(i1+1,j1+1,1) = field(i1+1,j1+1,1) + + & mass(n)*(1.0-dx)*(1.0-dy) +c + enddo +c + endif +c +c 3D +c + if (ndim .eq. 3) then +c + do n=1, npositions +c +c Compute the position of the central cell +c + xpos = min(max((posx(n) - leftedge(1))*fact, half), edge1) + ypos = min(max((posy(n) - leftedge(2))*fact, half), edge2) + zpos = min(max((posz(n) - leftedge(3))*fact, half), edge3) +c +c Convert this into an integer index +c + i1 = int(xpos + 0.5) + j1 = int(ypos + 0.5) + k1 = int(zpos + 0.5) +c +c Compute the weights +c + dx = real(i1) + 0.5 - xpos + dy = real(j1) + 0.5 - ypos + dz = real(k1) + 0.5 - zpos +c +c Interpolate from field into sumfield +c + field(i1 ,j1 ,k1 ) = field(i1 ,j1 ,k1 ) + + & mass(n)* dx * dy * dz + field(i1+1,j1 ,k1 ) = field(i1+1,j1 ,k1 ) + + & mass(n)*(1.0-dx)* dy * dz + field(i1 ,j1+1,k1 ) = field(i1 ,j1+1,k1 ) + + & mass(n)* dx *(1.0-dy)* dz + field(i1+1,j1+1,k1 ) = field(i1+1,j1+1,k1 ) + + & mass(n)*(1.0-dx)*(1.0-dy)* dz + field(i1 ,j1 ,k1+1) = field(i1 ,j1 ,k1+1) + + & mass(n)* dx * dy *(1.0-dz) + field(i1+1,j1 ,k1+1) = field(i1+1,j1 ,k1+1) + + & mass(n)*(1.0-dx)* dy *(1.0-dz) + field(i1 ,j1+1,k1+1) = field(i1 ,j1+1,k1+1) + + & mass(n)* dx *(1.0-dy)*(1.0-dz) + field(i1+1,j1+1,k1+1) = field(i1+1,j1+1,k1+1) + + & mass(n)*(1.0-dx)*(1.0-dy)*(1.0-dz) +c + enddo + +! do kkk=1,dim3 +! write(0,'("K = ",i2)') kkk +! do jjj=1,dim2 +! write(0,'((14(1pe8.1)))')(field(iii,jjj,kkk),iii=1,dim1) +! end do +! end do + + endif + + return + end From a15483ff7c00358859b3a173e56954ec68c62ae0 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Wed, 14 Aug 2019 12:49:47 -0500 Subject: [PATCH 006/115] Vast debugging from frontera. Get crashes with and without SMM. Is it fronteras MPI? run on comet to see. --- src/enzo/Grid_MechStarsCreation.C | 69 ++++++++++--------- src/enzo/Grid_MechStarsDepositFeedback.C | 77 ++++++++-------------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 69 +++++++++---------- src/enzo/Grid_StarParticleHandler.C | 35 +++++++--- src/enzo/MechStars_checkCreationCriteria.C | 14 ++-- src/enzo/MechStars_determineSN.C | 6 +- 6 files changed, 131 insertions(+), 139 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index c6c1a9f75..a53968cb8 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -40,7 +40,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, { if (level < StarMakeLevel) return 0; float stretchFactor=1.4; - bool debug = true; + bool debug = false; // fprintf(stdout, "Preparing to check grids\n"); // limit creation to level specified in parameter file @@ -91,7 +91,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float dx = CellWidth[0][0]; int GZ = int(NumberOfGhostZones); int nCreated = *NumberOfParticlesSoFar; - fprintf(stdout, "Starting creation with %d prior particles\n",nCreated); + //fprintf(stdout, "Starting creation with %d prior particles\n",nCreated); for (int i = GZ; i < GridDimension[0]-GZ; i++){ for(int j = GZ; j < GridDimension[1]-GZ; j++){ for (int k = GZ; k< GridDimension[2]-GZ; k++){ @@ -110,7 +110,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float dynamicalTime = 0; float Time = this->Time; - int stat = checkCreationCriteria(BaryonField[DensNum], + int createStar = checkCreationCriteria(BaryonField[DensNum], BaryonField[MetalNum], Temperature, DMField, BaryonField[Vel1Num], BaryonField[Vel2Num], BaryonField[Vel3Num], @@ -120,7 +120,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, - if (stat){ + if (createStar){ int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; /* Determine Mass of new particle */ @@ -135,16 +135,19 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float newMass = min(MassShouldForm, StarMakerMaximumFormationMass); newMass = newMass/MassUnits; - if (newMass > BaryonField[DensNum][index]) exit(136); - nCreated ++; + if (newMass > BaryonField[DensNum][index]) ENZO_FAIL("STAR MASS > CELL MASS"); + if (newMass*MassUnits < StarMakerMinimumMass){ + fprintf(stdout,"NOT ENOUGH MASS IN CELL \n"); + continue; + } float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); - fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); + // fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); ParticleArray->ParticleMass[nCreated] = newMass; ParticleArray->ParticleAttribute[1][nCreated] = dynamicalTime/TimeUnits; ParticleArray->ParticleAttribute[0][nCreated] = Time; ParticleArray->ParticleAttribute[2][nCreated] = BaryonField[MetalNum][index] - /BaryonField[DensNum][index]/0.02; + /BaryonField[DensNum][index]; ParticleArray->ParticleType[nCreated] = PARTICLE_TYPE_STAR; BaryonField[DensNum][index] -= newMass; @@ -160,45 +163,47 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, if (HydroMethod != 0) fprintf(stderr,"Mechanical star maker not tested for anything except HydroMethod = 0\n"); ParticleArray->ParticleVelocity[0][nCreated] = - 0.33*(BaryonField[Vel1Num][preI]+BaryonField[Vel1Num][postI] + 0.033*(BaryonField[Vel1Num][preI]+BaryonField[Vel1Num][postI] +BaryonField[Vel1Num][index]); ParticleArray->ParticleVelocity[1][nCreated] = - 0.33*(BaryonField[Vel2Num][preI]+BaryonField[Vel2Num][postI] + 0.033*(BaryonField[Vel2Num][preI]+BaryonField[Vel2Num][postI] +BaryonField[Vel2Num][index]); ParticleArray->ParticleVelocity[2][nCreated] = - 0.33*(BaryonField[Vel3Num][preI]+BaryonField[Vel3Num][postI] + 0.033*(BaryonField[Vel3Num][preI]+BaryonField[Vel3Num][postI] +BaryonField[Vel3Num][index]); /* give it position at center of host cell */ ParticleArray->ParticlePosition[0][nCreated] = CellLeftEdge[0][0] - +(dx*(float(i)-0.5)); + +(dx*(float(i)+0.5)); ParticleArray->ParticlePosition[1][nCreated] = CellLeftEdge[1][0] - +(dx*(float(j)-0.5)); + +(dx*(float(j)+0.5)); ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] - +(dx*(float(k)-0.5)); + +(dx*(float(k)+0.5)); if (nCreated >= MaximumNumberOfNewParticles) return nCreated; - fprintf(stdout,"Created star: %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", - nCreated, - ParticleArray->ParticleType[nCreated], - ParticleArray->ParticleMass[nCreated]*MassUnits, - ParticleArray->ParticleAttribute[0][nCreated], - ParticleArray->ParticleAttribute[1][nCreated], - ParticleArray->ParticleAttribute[2][nCreated], - ParticleArray->ParticlePosition[0][nCreated], - ParticleArray->ParticlePosition[1][nCreated], - ParticleArray->ParticlePosition[2][nCreated], - ParticleArray->ParticleVelocity[0][nCreated]*VelocityUnits/1e5, - ParticleArray->ParticleVelocity[1][nCreated]*VelocityUnits/1e5, - ParticleArray->ParticleVelocity[2][nCreated]*VelocityUnits/1e5, - index, GridDimension[0]*GridDimension[2]*GridDimension[3], i,j,k); + if (debug) + fprintf(stdout,"Created star: %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", + nCreated, + ParticleArray->ParticleType[nCreated], + ParticleArray->ParticleMass[nCreated]*MassUnits, + ParticleArray->ParticleAttribute[0][nCreated], + ParticleArray->ParticleAttribute[1][nCreated], + ParticleArray->ParticleAttribute[2][nCreated], + ParticleArray->ParticlePosition[0][nCreated], + ParticleArray->ParticlePosition[1][nCreated], + ParticleArray->ParticlePosition[2][nCreated], + ParticleArray->ParticleVelocity[0][nCreated]*VelocityUnits/1e5, + ParticleArray->ParticleVelocity[1][nCreated]*VelocityUnits/1e5, + ParticleArray->ParticleVelocity[2][nCreated]*VelocityUnits/1e5, + index, GridDimension[0]*GridDimension[2]*GridDimension[3], i,j,k); + nCreated ++; } }//end for k }//end for j } // end for i - if (nCreated > 0){ - fprintf(stdout, "Created %d star particles\n",nCreated); - } + //if (nCreated > 0 && debug){ + // fprintf(stdout, "Created %d star particles\n",nCreated); + // } *NumberOfParticlesSoFar = nCreated; return nCreated; -} \ No newline at end of file +} diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 72c070388..326f9e0ae 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -42,8 +42,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, and all have radius dx from the source particle. Each vertex particle will then be CIC deposited to the grid! */ - bool debug = true; - bool criticalDebug = true; + bool debug = false; + bool criticalDebug = false; int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; @@ -99,11 +99,11 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, of all quantities and be coupled to the grid after the cic deposition. */ float density [size]; float metals [size]; - float *u = new float [size]; - float *v = new float[size]; - float *w = new float [size]; - float *totalEnergy =new float [size]; - float *gasEnergy =new float[size]; + float u [size]; + float v [size]; + float w [size]; + float totalEnergy [size]; + float gasEnergy [size]; for (int i=0; i 4) Efactor = coupledEnergy/ejectaEnergy*pow(dxRatio,3); coupledMomenta = 4.8e5*pow(nmean, -1.0/7.0) * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; //Msun*km/s // } @@ -272,7 +270,6 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, Analytic SNR shell mass is on, adjust the shell mass Shell is limited on upper end by 1/1000 mass of cell with mean density*/ - float maxShellMass = 1.0*DensityUnits*MassUnits/1000; // large shell mass evacuates too efficently... muField-> 0.0 and NaN ensues! if (dxRatio <= 50 && dxRatio >= 0.1 && coupledEnergy > 0 && AnalyticSNRShellMass){ shellVelocity = 413.0 *pow(nmean, 1.0/7.0) @@ -284,7 +281,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, can only contribute to the mass if the shell velocity is higher than the gas velocity.*/ if (shellVelocity > vmean){ - shellMass = max(1e3, coupledMomenta/shellVelocity); //Msun + shellMass = max(8e3, coupledMomenta/shellVelocity); //Msun /* cant let host cells evacuate completely! Shell mass will be evacuated from central cells by CIC a negative mass, @@ -309,38 +306,12 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, eKinetic = coupledMomenta*coupledMomenta /(2.0*coupledMass)*SolarMass*1e10; - /* rescale momenta if it results in too much energy */ - - // if (eKinetic > coupledEnergy && !usePt){ - // float fact = coupledEnergy/eKinetic; - // if (debug)fprintf(stdout, "recalculating momenta: e_k > e_cpl: e_k = %e e_cpl = %e factor = %e ", - // eKinetic, coupledEnergy, fact); - // coupledMomenta = pow(fact*2.0*ejectaEnergy*(coupledMass*SolarMass), 0.5) - // * pow(1.0+dxRatio, 3.75*pow(nmean, -1./14.))/SolarMass/1e5; - // eKinetic = coupledMomenta*coupledMomenta - // /(2.0*coupledMass)*SolarMass*1e10; - // if (debug)fprintf(stdout, "new e_k = %e p = %e\n",eKinetic, coupledMomenta); - // } - - // // // /* If p_t gives too much kinetic energy, reduce it - // // // to preserve energy conservation */ - - // if (eKinetic > coupledEnergy && usePt){ - // float fact = pow(coupledEnergy/eKinetic,14.0/13.0); - // if (debug)fprintf(stdout, "recalculating momenta: e_k > e_cpl e_k = %e e_cpl = %e ", - // eKinetic, coupledEnergy); - // coupledMomenta = pow(dxRatio, -3)*4.8e5*pow(nmean, -1.0/7.0) - // * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; - // eKinetic = coupledMomenta*coupledMomenta - // /(2.0*coupledMass)*SolarMass*1e10; - // if (debug)fprintf(stdout, "new e_k = %e p = %e\n",eKinetic, coupledMomenta); - // } float coupledGasEnergy = max(ejectaEnergy-eKinetic, 0); if (debug)fprintf(stdout, "Coupled Gas Energy = %e\n",coupledGasEnergy); - if (dxRatio > 1.0) - coupledGasEnergy *= pow(dxRatio, -6.5); - /* rescale momentum for new shell */ + // if (dxRatio > 1.0) + // coupledGasEnergy *= pow(dxRatio, -6.5); + float shellMetals = zZsun*0.02 * shellMass; float coupledMetals = ejectaMetal + shellMetals; @@ -348,9 +319,9 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if (debug) fprintf(stdout, "Coupled Momentum: %e\n", coupledMomenta/float(nCouple)); /* Reduce coupled quantities to per-particle quantity and convert to - code quantities. + code units. Hopkins has complicated weights due to complicated geometry. - This is more simple since our coupled particles are + This implementation is simple since our coupled particles are spherically symmetric about the feedback particle*/ coupledEnergy /= float(nCouple); @@ -358,13 +329,17 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, coupledMass /= float(nCouple); coupledMetals /= float(nCouple); coupledMomenta /= float(nCouple); + /* Transform coupled quantities to code units */ + coupledEnergy /= EnergyUnits; coupledGasEnergy /= EnergyUnits; coupledMass /= MassUnits; coupledMetals /= MassUnits; coupledMomenta /= MomentaUnits; + /* CIC deposit the particles with their respective quantities */ + float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; for (int n = 0; n < nCouple; n++){ @@ -381,24 +356,24 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); if (pX != 0.0){ FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np,&pX, u, LeftEdge, + &CloudParticlePositionZ[n], &GridRank, &np,&pX, &u[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); } if (pY != 0.0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&pY, v, LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&pY, &v[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); if (pZ != 0.0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&pZ, w, LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&pZ, &w[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); if (coupledEnergy > 0 && DualEnergyFormalism) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&coupledEnergy, totalEnergy, LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&coupledEnergy, &totalEnergy[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); if (coupledGasEnergy > 0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&coupledGasEnergy, gasEnergy, LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&coupledGasEnergy, &gasEnergy[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); } /* Deposit one negative mass particle centered on star to account for @@ -520,6 +495,6 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, GridDimension[2], -1); - delete [] u,v,w, gasEnergy, totalEnergy; + // delete [] u,v,w, gasEnergy, totalEnergy; return SUCCESS; -} \ No newline at end of file +} diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 0b38d142f..8ec504489 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -1,5 +1,5 @@ /* - Routine to determine feedback quantities and couple them to the + Routine to determine feedback quantities and couple them to the Grid. Coupling follows the implementation of Hopkins 2017 with modification for Enzo's fixed grid @@ -22,16 +22,16 @@ #include "phys_constants.h" - int determineSN(float age, int* nSNII, int* nSNIA, float massMsun, + int determineSN(float age, int* nSNII, int* nSNIA, float massMsun, float TimeUnits, float dtFixed); int determineWinds(float age, float* eWinds, float* zWinds, float* mWinds, float massMsun, float zZsun, float TimeUnits, float dtFixed); int checkCreationCriteria(float* Density, float* Metals, float* Temperature,float* DMField, - float* Vel1, float* Vel2, float* Vel3, + float* Vel1, float* Vel2, float* Vel3, float* CoolingTime, int GridDim, - float* shieldedFraction, float* freeFallTime, - float* dynamicalTime, int i, int j, int k, + float* shieldedFraction, float* freeFallTime, + float* dynamicalTime, int i, int j, int k, float Time, float* RefinementField, float CellWidth); int FindField(int field, int farray[], int numfields); int GetUnits(float *DensityUnits, float *LengthUnits, @@ -45,16 +45,16 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) { - // fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", + // fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", // SingleSN, StellarWinds, UnrestrictedSN); float stretchFactor = 1.4;//1/sqrt(2) to cover cell diagonal /* Get units to use */ int dim, i, j, k, index, size, field, GhostZones = NumberOfGhostZones; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; - + /* Compute size (in floats) of the current grid. */ - + size = 1; for (dim = 0; dim < GridRank; dim++) size *= GridDimension[dim]; @@ -73,11 +73,11 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } - double dx = CellWidth[0][0]; + return FAIL; + } + double dx = CellWidth[0][0]; MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; - /* + /* get metallicity field and set flag; assumed true thoughout feedback since so many quantities are metallicity dependent */ @@ -87,7 +87,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) MetallicityField = TRUE; else MetalNum = 0; - + int numSN = 0; /* Begin Iteration of all particles */ @@ -103,7 +103,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) if (ParticleType[pIndex] == PARTICLE_TYPE_STAR && ParticleMass[pIndex] > 0.0 && ParticleAttribute[0][pIndex] > 0.0){ - + // if (StarMakerAgeCutoff) // if ((Time-ParticleAttribute[0][pIndex]) // *TimeUnits/(150*3.1557e7) > 150) @@ -127,10 +127,10 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) float gridDx = GridDimension[0]*dx; float gridDy = GridDimension[1]*dx; float gridDz = GridDimension[2]*dx; - /* Keep particle 2 cells from edge since we cant transfer to + /* Keep particle 2 cells from edge since we cant transfer to neighboring grids */ float borderDx = (stretchFactor+1)*dx; - if (xp > CellLeftEdge[0][0]+gridDx + if (xp > CellLeftEdge[0][0]+gridDx || xp < CellLeftEdge[0][0] || yp > CellLeftEdge[1][0]+gridDy || yp < CellLeftEdge[1][0] @@ -169,14 +169,14 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) } if (shifted > 0){ if (debug) - fprintf(stderr, "Particle position shifted away from edge: %e: %f %f %f\n%f %f %f\n", + fprintf(stderr, "Particle position shifted away from edge: %e: %f %f %f\n%f %f %f\n", age,xp, yp, zp, CellLeftEdge[0][0]+borderDx, CellLeftEdge[1][0]+borderDx, CellLeftEdge[2][0]+borderDx); int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; } /* REMOVED: Check for continual formation, i guess. Only really done because - Hopkins did it. We can just make more stars next timestep I guess. + Hopkins did it. We can just make more stars next timestep I guess. On the other hand, the function is already written... */ /* create some stuff. This is a lot of overhead for something optional... */ @@ -189,55 +189,50 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) // printf("Checking particle: %f %e \n", age, ParticleMass[pIndex]*MassUnits); /* determine how many supernova events */ if (SingleSN) - { - fprintf(stdout,"Checking for SN age = %f\n", age); + { + // fprintf(stdout,"Checking for SN age = %f\n", age); determineSN(age, &nSNII, &nSNIA, ParticleMass[pIndex]*MassUnits, TimeUnits, dtFixed); numSN += nSNII+nSNIA; - if (true) if (nSNII > 0 || nSNIA > 0) - fprintf(stdout,"\n\nSUPERNOVAE!!!! %d %d level = %d\n\n", nSNII, nSNIA, level); + if ((nSNII > 0 || nSNIA > 0) && debug) + fprintf(stdout,"SUPERNOVAE!!!! %d %d level = %d\n", nSNII, nSNIA, level); if (nSNII > 0 || nSNIA > 0){ /* set feedback qtys based on number and types of events */ /* 1e51 erg per sn */ float energySN = (nSNII + nSNIA)*1e51; - + /*10.5 Msun ejecta for type II and IA*/ SNMassEjected = (nSNII+nSNIA)*10.5; /* Metal yeilds from starburst 99 */ float zZsun = min(BaryonField[MetalNum][index]/BaryonField[DensNum][index]/0.02, 1e-4); SNMetalEjected = nSNII*(1.91+0.0479*max(zZsun, 1.65)); - SNMetalEjected += nSNIA*(1.4); + SNMetalEjected += nSNIA*(1.4); // this metal should get coupled to SNIA field if its being used MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], ip, jp, kp, size, mu_field, 0); } } - + float windEnergy=0, windMass=0, windMetals=0; /* Do the same for winds. Cooling Radius is very small, So almost no energy is coupled, but some mass may be. */ - - + + if (StellarWinds) { // printf("Checking Winds\n"); float zZsun = min(BaryonField[MetalNum][index]/BaryonField[DensNum][index]/0.02, 1e-8); - determineWinds(age, &windEnergy, &windMass, &windMetals, + determineWinds(age, &windEnergy, &windMass, &windMetals, ParticleMass[pIndex]*MassUnits, zZsun, TimeUnits, dtFixed); - if (windMass > 1e-5 && windEnergy > 1e10){ - MechStars_DepositFeedback(windEnergy, windMass, windMetals, + MechStars_DepositFeedback(windEnergy, windMass, windMetals, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], ip, jp, kp, size, mu_field, 1); - } else { - windMass = 0.0; - windEnergy= 0.0; - windMetals = 0.0; - } - + + } if (windMass > 0.0 || SNMassEjected > 0){ if (debug) printf("Subtracting off mass %e\n",(windMass+SNMassEjected)); @@ -248,4 +243,4 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) }// end iteration over particles return SUCCESS; -} \ No newline at end of file +} diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index 857231bdd..dda381d2d 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -832,15 +832,17 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, } if (STARMAKE_METHOD(MECHANICAL)){ NumberOfNewParticlesSoFar = NumberOfParticles; - - NumberOfNewParticles = MechStars_Creation(tg, temperature, + int nRetStars = 0; + nRetStars = MechStars_Creation(tg, temperature, dmfield, level, cooling_time, MaximumNumberOfNewParticles, &NumberOfNewParticles); + //fprintf(stdout, "Created %d new stars!", NumberOfNewParticles); + if (nRetStars != NumberOfNewParticles) fprintf(stdout, "star count return and pointer mismatch!\n"); + for (i = NumberOfNewParticlesSoFar; i < NumberOfNewParticles; i++){ + tg->ParticleType[i] = NormalStarType; + //fprintf(stdout, "Set star %d type %d", i, NormalStarType); - for (i = NumberOfNewParticlesSoFar; i < NumberOfNewParticles; i++) - tg->ParticleType[i] = NormalStarType; - - + } } if (STARMAKE_METHOD(MOM_STAR)) { @@ -1443,14 +1445,27 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, /* Move any new particles into their new homes. */ if (NumberOfNewParticles > 0) { - if (debug) + /* Set the particle numbers. The correct indices will be assigned in CommunicationUpdateStarParticleCount in StarParticleFinalize later.*/ - for (i = 0; i < NumberOfNewParticles; i++) - tg->ParticleNumber[i] = INT_UNDEFINED; - + for (i = 0; i < NumberOfNewParticles; i++){ + tg->ParticleNumber[i] = INT_UNDEFINED; + fprintf(stdout,"Created star: %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f\n", + i, + tg->ParticleType[i], + tg->ParticleMass[i], + tg->ParticleAttribute[0][i], + tg->ParticleAttribute[1][i], + tg->ParticleAttribute[2][i], + tg->ParticlePosition[0][i], + tg->ParticlePosition[1][i], + tg->ParticlePosition[2][i], + tg->ParticleVelocity[0][i], + tg->ParticleVelocity[1][i], + tg->ParticleVelocity[2][i]); + } /* Move Particles into this grid (set cell size) using the fake grid. */ tg->NumberOfParticles = NumberOfNewParticles; diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index cbbe67545..b6b266729 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -31,6 +31,7 @@ int checkCreationCriteria(float* Density, float* Metals, float* dynamicalTime, int i, int j, int k, float Time, float* RefinementField, float CellWidth) { + bool debug = false; bool status = PASS; float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; @@ -61,8 +62,8 @@ int checkCreationCriteria(float* Density, float* Metals, { status = FAIL; } - if (debug && status) fprintf(stdout, "Passed Density: %e: %e\n", - dmean,StarMakerOverDensityThreshold); + //if (debug && status) fprintf(stdout, "Passed Density: %e: %e\n", + // dmean,StarMakerOverDensityThreshold); /* in addition to the converging flow check, we check the virial parameter of the gas to see if it is locally gravitationally bound*/ @@ -110,10 +111,11 @@ int checkCreationCriteria(float* Density, float* Metals, if (Temperature[index] > 1e4) { + status = FAIL; //no hot gas forming stars! float totalDensity = Density[index] +DMField[index]*DensityUnits; - float Tdyn = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); - if (Tdyn/TimeUnits < CoolingTime[index]) status = FAIL; + *dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); + if (*dynamicalTime/TimeUnits < CoolingTime[index]) status = FAIL; } /* is gas mass > critical jeans mass? */ @@ -147,7 +149,7 @@ int checkCreationCriteria(float* Density, float* Metals, if (*shieldedFraction < 0) status = FAIL; *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; - if (status) fprintf(stdout, "passed creation criteria\n"); + //if (status && debug) fprintf(stdout, "passed creation criteria\n"); return status; -} \ No newline at end of file +} diff --git a/src/enzo/MechStars_determineSN.C b/src/enzo/MechStars_determineSN.C index 41f18c83e..07a0729fa 100644 --- a/src/enzo/MechStars_determineSN.C +++ b/src/enzo/MechStars_determineSN.C @@ -48,12 +48,12 @@ int determineSN(float age, int* nSNII, int* nSNIA, RII = 2.516e-4; RIA = 0.0; } - if (37.52 <= age) + if (37.53 <= age) { RII = 0.0; RIA = 5.2e-8+1.6e-5*exp(-1.0*pow((age-50.0)/10.0, 2)/2.0); } - // fprintf(stdout, "Rates: %f %f %f\n", age, RII, RIA); + // fprintf(stdout, "Rates: %f %f %f\n", age, RII, RIA); /* rates -> probabilities */ if (RII > 0){ srand(seed); @@ -95,4 +95,4 @@ int determineSN(float age, int* nSNII, int* nSNIA, } return SUCCESS; -} \ No newline at end of file +} From fa9a9718d4f1bacfa2aa0a689e805ac77c14370c Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 17 Aug 2019 11:35:14 -0500 Subject: [PATCH 007/115] reverted energy deposition to as defined in Hopkins. Tests were failures and the deposition matches that of star_maker3mom.F now as well --- src/enzo/Grid_MechStarsDepositFeedback.C | 69 +++++++++--------------- 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 326f9e0ae..ef8cb7830 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -49,8 +49,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* Compute size (in floats) of the current grid. */ float stretchFactor =1.;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host - // in units of dx - int usePt = 0; + // in units of dx. Since the cloud forms a sphere shell, stretchFactor > 1 is not recommended size = 1; for (int dim = 0; dim < GridRank; dim++) size *= GridDimension[dim]; @@ -90,7 +89,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, MetalNum = 0; /* set other units that we need */ - MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; + MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; //Msun! float EnergyUnits = DensityUnits*pow(LengthUnits*dx, 3) * VelocityUnits*VelocityUnits;//[g cm^2/s^2] -> code_energy float MomentaUnits = VelocityUnits; @@ -217,7 +216,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float zZsun = max(zmean, 1e-8); float fz = (zZsun < 0.01)? (2.0): (pow(zZsun, -0.14)); - /* conversions */ + /* Cooling radius as in Hopkins, but as an average over cells */ float CoolingRadius = 28.4 * pow(max(0.001,nmean), -3.0/7.0) *pow(ejectaEnergy/1.0e51, 2.0/7.0)* fz; @@ -232,51 +231,33 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float coupledMomenta = 0.0; float eKinetic = 0.0; - /* Hopkins uses ratio of masses to determine how to couple. - Radius here is well-known and fixed, so we use that instead */ - if (dxRatio > 1.0){ - // if (ejectaEnergy < 1e5 || dxRatio > 100){ - // coupledEnergy = 0.0; - // coupledMomenta = 0.0; - // }else{ - coupledEnergy = ejectaEnergy*pow(dxRatio, -6.5); - usePt = 1; - - /* Determine coupled momenta if rc < dx - else couple p_ejecta */ - if(debug)fprintf(stdout, "Using P_t with Nb = %f, E= %e",nmean, coupledEnergy/1e51); - coupledMomenta = 4.8e5*pow(nmean, -1.0/7.0) - * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; //Msun*km/s - // } - } else { - if (debug)fprintf(stdout, "Directly calculating momenta using energy = %e and mass = %e ", - ejectaEnergy, ejectaMass); - - /* - The multiplicative factor tacked on the end of the momentum here - ensures a smooth connection from p = sqrt(2*m*e) to the p=pt at r_cool - above. Without it, there are large discontinuities where the different - forms of momenta meet (dx=r_cool) - */ - coupledMomenta = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5) - * pow(1.0+dxRatio, 3.75*pow(nmean, -1./14.))/SolarMass/1e5; //Msun*km/s - if (debug)fprintf(stdout, "Calculated p = %e ", coupledMomenta); - if (debug)fprintf(stdout, "Ekinetic = %e\n", coupledMomenta*coupledMomenta + /* termninal momentum */ + float pTerminal = 4.8e5*pow(nmean, -1.0/7.0) + * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; + /* analytic momentum for resolved cooling radii */ + float pEjectMod = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5) + * pow(1+dmean*MassUnits/ejectaMass/SolarMass, 0.5)/SolarMass/1e5;; + + /* Select the lower momenta to couple */ + coupledMomenta = min(pEjectMod, pTerminal); + + if (debug)fprintf(stdout, "Calculated p = %e ", coupledMomenta); + if (debug)fprintf(stdout, "Ekinetic = %e\n", coupledMomenta*coupledMomenta /(2.0*ejectaMass)*SolarMass*1e10); - } + float shellMass = 0.0, shellVelocity = 0.0; /* If resolution is in a range compared to Rcool and Analytic SNR shell mass is on, adjust the shell mass - Shell is limited on upper end by 1/1000 mass of - cell with mean density*/ + Shell mass calculation is limited by considering the local gas + velocity */ if (dxRatio <= 50 && dxRatio >= 0.1 && coupledEnergy > 0 && AnalyticSNRShellMass){ shellVelocity = 413.0 *pow(nmean, 1.0/7.0) *pow(zZsun, 3.0/14.0)*pow(coupledEnergy/EnergyUnits/1e51, 1.0/14.0) *pow(dxRatio, -7.0/3.0);//km/s - /* Underdense regions can have large momenta with - low velocity, leading to shell mass instability. + /* Underdense regions can have large coupled momenta with + low velocity (due to large r_cool), leading to shell mass instability. The shell velocity is compared to gas velocity, and can only contribute to the mass if the shell velocity is higher than the gas velocity.*/ @@ -304,13 +285,13 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, ENZO_FAIL("SM_deposit: 252");} float coupledMass = shellMass+ejectaMass; eKinetic = coupledMomenta*coupledMomenta - /(2.0*coupledMass)*SolarMass*1e10; + /(2.0*dmean*MassUnits)*SolarMass*1e10; float coupledGasEnergy = max(ejectaEnergy-eKinetic, 0); if (debug)fprintf(stdout, "Coupled Gas Energy = %e\n",coupledGasEnergy); - // if (dxRatio > 1.0) - // coupledGasEnergy *= pow(dxRatio, -6.5); + if (dxRatio > 1.0) + coupledGasEnergy = (DepositUnresolvedEnergyAsThermal)?(coupledGasEnergy):(coupledGasEnergy*pow(dxRatio, -6.5)); float shellMetals = zZsun*0.02 * shellMass; float coupledMetals = ejectaMetal + shellMetals; @@ -324,7 +305,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, This implementation is simple since our coupled particles are spherically symmetric about the feedback particle*/ - coupledEnergy /= float(nCouple); + coupledEnergy = eKinetic/float(nCouple); coupledGasEnergy /= float(nCouple); coupledMass /= float(nCouple); coupledMetals /= float(nCouple); @@ -377,7 +358,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); } /* Deposit one negative mass particle centered on star to account for - shell mass leaving host cells */ + shell mass leaving host cells . Same for metals that were evacuated*/ int np = 1; shellMass *= -1/MassUnits; FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMass, &density[0], LeftEdge, From d1cd108fae19c9e5af93c35e4250e060bd3df8da Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sun, 18 Aug 2019 13:14:59 -0700 Subject: [PATCH 008/115] Reworked momentum decision tree to cover different phases of SNR --- src/enzo/Grid_MechStarsDepositFeedback.C | 81 ++++++++++++++++++------ 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index ef8cb7830..37da3638a 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -42,13 +42,13 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, and all have radius dx from the source particle. Each vertex particle will then be CIC deposited to the grid! */ - bool debug = false; - bool criticalDebug = false; + bool debug = true; + bool criticalDebug = true; int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; /* Compute size (in floats) of the current grid. */ - float stretchFactor =1.;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host + float stretchFactor =1.25;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host // in units of dx. Since the cloud forms a sphere shell, stretchFactor > 1 is not recommended size = 1; for (int dim = 0; dim < GridRank; dim++) @@ -228,24 +228,61 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if (debug)fprintf(stdout, "Dx [pc] = %f\n", dx*LengthUnits/pc_cm); float dxRatio = stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius; - - float coupledMomenta = 0.0; - float eKinetic = 0.0; + float pEjectMod = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5)/SolarMass/1e5; + /* We want to couple one of four phases: free expansion, Sedov-taylor, shell formation, or terminal + The first three phases are take forms from Kim & Ostriker 2015, the last from Cioffi 1988*/ + float cellwidth = dx*LengthUnits/pc_cm; + float p_free = 0.0;//sqrt(ejectaMass*SolarMass*ejectaEnergy)/SolarMass/1e5;//1.73e4*sqrt(ejectaMass*ejectaEnergy/1e51/3.); // free exp. momentum eq 15 + float r_free = 2.75*pow(ejectaMass/3/nmean, 1./3.); // free exp radius eq 2 + + + // assuming r_sedov == dx, solve for t3 + float t3_sedov = pow( cellwidth*pc_cm + /(5.0*pc_cm*pow(ejectaEnergy/1e51/nmean, 1.0/5.0)), 5./2.); + float p_sedov = 2.21e4*pow(ejectaEnergy/1e51, 4./5.) + * pow(nmean, 1./5.)* pow(t3_sedov, 3./5.); // eq 16 + + // shell formation radius eq 8 + float r_shellform = 22.6*pow(ejectaEnergy/1e51, 0.29)*pow(nmean, -0.42); + // p_sf = m_sf*v_sf eq 9,11 + float p_shellform = 3.3936e5*pow(ejectaEnergy/1e51, 0.94)*pow(nmean, -0.13) ; // p_sf = m_sf*v_sf eq 9,11 + /* termninal momentum */ float pTerminal = 4.8e5*pow(nmean, -1.0/7.0) - * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; - /* analytic momentum for resolved cooling radii */ - float pEjectMod = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5) - * pow(1+dmean*MassUnits/ejectaMass/SolarMass, 0.5)/SolarMass/1e5;; - - /* Select the lower momenta to couple */ - coupledMomenta = min(pEjectMod, pTerminal); - - if (debug)fprintf(stdout, "Calculated p = %e ", coupledMomenta); - if (debug)fprintf(stdout, "Ekinetic = %e\n", coupledMomenta*coupledMomenta - /(2.0*ejectaMass)*SolarMass*1e10); + * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; // cioffi 1988, as written in Hopkins 2018 + float coupledMomenta = 0.0; + float eKinetic = 0.0; + fprintf(stdout, "RADII: %e %e %e t_3=%e\n", r_free, r_shellform, CoolingRadius, t3_sedov); + /* Select the mode of coupling */ + + if (cellwidth < r_free){ + coupledMomenta = p_free; + fprintf(stdout, "Coupling free expansion\n");} + if (cellwidth > r_free && cellwidth < r_shellform){ + coupledMomenta = p_sedov; + fprintf(stdout, "Coupling S-T phase\n");} + if (cellwidth > r_shellform && cellwidth < CoolingRadius){ + coupledMomenta = min(p_shellform*cellwidth/r_shellform, pTerminal); + fprintf(stdout, "Coupling shell-forming stage\n");} + if (cellwidth > CoolingRadius){ + coupledMomenta = pTerminal; + fprintf(stdout, "Coupling terminal momenta\n");} + if (debug)fprintf(stdout, "Calculated p = %e\n", coupledMomenta); + + + /* fading radius of a SNR */ + float *temperature = new float[size]; + this->ComputeTemperatureField(temperature); + float Gcode = GravConst*DensityUnits*pow(TimeUnits,2); + float KBcode = kboltz*MassUnits/(LengthUnits*dx)/pow(TimeUnits,2); + float cSound = sqrt(5/3*kboltz*temperature[index]/mh/muField[index])/1e5; //km/s + float r_fade = 66.0*pow(ejectaEnergy/1e51, 0.32)*pow(nmean, -0.37)*pow(min(cSound/10, .1), -2.0/5.0); + fprintf(stdout, "Rfade = %e cs = %e \n", r_fade, cSound); + delete [] temperature; + + coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3)):(coupledMomenta); float shellMass = 0.0, shellVelocity = 0.0; /* If resolution is in a range compared to Rcool and Analytic SNR shell mass is on, adjust the shell mass @@ -286,19 +323,22 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float coupledMass = shellMass+ejectaMass; eKinetic = coupledMomenta*coupledMomenta /(2.0*dmean*MassUnits)*SolarMass*1e10; + if (debug)fprintf(stdout, "Ekinetic = %e\n", eKinetic); float coupledGasEnergy = max(ejectaEnergy-eKinetic, 0); if (debug)fprintf(stdout, "Coupled Gas Energy = %e\n",coupledGasEnergy); - if (dxRatio > 1.0) - coupledGasEnergy = (DepositUnresolvedEnergyAsThermal)?(coupledGasEnergy):(coupledGasEnergy*pow(dxRatio, -6.5)); + if (dxRatio > 2.0) + coupledGasEnergy = (DepositUnresolvedEnergyAsThermal) + ?(coupledGasEnergy) + :(coupledGasEnergy*pow(dxRatio, -6.5)); float shellMetals = zZsun*0.02 * shellMass; float coupledMetals = ejectaMetal + shellMetals; - if (debug) fprintf(stdout, "Coupled Momentum: %e\n", coupledMomenta/float(nCouple)); + if (debug) fprintf(stdout, "Coupled Momentum: %e\n", coupledMomenta); /* Reduce coupled quantities to per-particle quantity and convert to code units. Hopkins has complicated weights due to complicated geometry. @@ -349,6 +389,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, &CloudParticlePositionZ[n], &GridRank,&np,&pZ, &w[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); if (coupledEnergy > 0 && DualEnergyFormalism) + coupledEnergy += coupledGasEnergy; FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&coupledEnergy, &totalEnergy[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); From 81ca2034ab413b0eb36d4d062cd1b01867fcb146 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 19 Aug 2019 14:00:03 -0700 Subject: [PATCH 009/115] Enforced smooth momentum functional forms --- src/enzo/Grid_MechStarsDepositFeedback.C | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 37da3638a..500b44cb8 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -48,7 +48,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; /* Compute size (in floats) of the current grid. */ - float stretchFactor =1.25;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host + float stretchFactor =1.15;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host // in units of dx. Since the cloud forms a sphere shell, stretchFactor > 1 is not recommended size = 1; for (int dim = 0; dim < GridRank; dim++) @@ -245,7 +245,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, // shell formation radius eq 8 float r_shellform = 22.6*pow(ejectaEnergy/1e51, 0.29)*pow(nmean, -0.42); // p_sf = m_sf*v_sf eq 9,11 - float p_shellform = 3.3936e5*pow(ejectaEnergy/1e51, 0.94)*pow(nmean, -0.13) ; // p_sf = m_sf*v_sf eq 9,11 + float p_shellform = 3.1e5*pow(ejectaEnergy/1e51, 0.94)*pow(nmean, -0.13) ; // p_sf = m_sf*v_sf eq 9,11 /* termninal momentum */ float pTerminal = 4.8e5*pow(nmean, -1.0/7.0) @@ -261,10 +261,10 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, coupledMomenta = p_free; fprintf(stdout, "Coupling free expansion\n");} if (cellwidth > r_free && cellwidth < r_shellform){ - coupledMomenta = p_sedov; + coupledMomenta = min(p_sedov, p_shellform*cellwidth/r_shellform); fprintf(stdout, "Coupling S-T phase\n");} if (cellwidth > r_shellform && cellwidth < CoolingRadius){ - coupledMomenta = min(p_shellform*cellwidth/r_shellform, pTerminal); + coupledMomenta = min(p_shellform+(cellwidth-r_shellform)*(pTerminal-p_shellform)/(CoolingRadius-r_shellform), pTerminal); fprintf(stdout, "Coupling shell-forming stage\n");} if (cellwidth > CoolingRadius){ coupledMomenta = pTerminal; @@ -288,7 +288,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, Analytic SNR shell mass is on, adjust the shell mass Shell mass calculation is limited by considering the local gas velocity */ - if (dxRatio <= 50 && dxRatio >= 0.1 && coupledEnergy > 0 + if (cellwidth > r_shellform && coupledEnergy > 0 && AnalyticSNRShellMass){ shellVelocity = 413.0 *pow(nmean, 1.0/7.0) *pow(zZsun, 3.0/14.0)*pow(coupledEnergy/EnergyUnits/1e51, 1.0/14.0) @@ -307,8 +307,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, for (int ind = -1; ind<=1; ind++){ float minD = min(BaryonField[DensNum][index+ind],BaryonField[DensNum][index+GridDimension[0]*ind]); minD = min(minD,BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]); - if (shellMass >= 0.05*minD*MassUnits) - shellMass = 0.05*minD*MassUnits; + if (shellMass >= 0.25*minD*MassUnits) + shellMass = 0.25*minD*MassUnits; } From 574c7664bf933e042c8eb012be0b73144192be74 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 22 Aug 2019 15:19:21 -0700 Subject: [PATCH 010/115] Reverted deposition cloud to the grid-cloud from simpson 2015--works nicely with the weights, etc from Hopkins. Spherical clouds... do not. --- src/enzo/Grid_MechStarsDepositFeedback.C | 94 ++++++++++++++---------- 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 500b44cb8..74bc2828d 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -48,7 +48,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; /* Compute size (in floats) of the current grid. */ - float stretchFactor =1.15;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host + float stretchFactor =1.;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host // in units of dx. Since the cloud forms a sphere shell, stretchFactor > 1 is not recommended size = 1; for (int dim = 0; dim < GridRank; dim++) @@ -124,20 +124,23 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* A DODECAHEDRON+ISOCAHEDRON */ - int nCouple = 32; + int nCouple = 26; float A = stretchFactor*dx; - - /* Dodec points followed by isoca points */ - FLOAT CloudParticleVectorX [] = {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, - iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, - 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; - FLOAT CloudParticleVectorY [] = {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, - phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, - phi, -phi, -phi, phi, 0, 0, 0, 0}; - FLOAT CloudParticleVectorZ [] = {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, - 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, - phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; - + float cloudSize=1.*dx; + /* Points from HEALPix algorithm; 48 equally dist. points*/ + FLOAT CloudParticleVectorX [] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + // {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, + // iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, + // 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; + FLOAT CloudParticleVectorY [] = {1,1,1,0,0,-1,-1,-1,0,1,1,1,0,0,-1,-1,-1,1,1,1,0,0,-1,-1,-1,0}; + // {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, + // phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, + // phi, -phi, -phi, phi, 0, 0, 0, 0}; + FLOAT CloudParticleVectorZ [] ={1,0,-1,1,-1,1,0,-1,0,1,0,-1,1,-1,1,0,-1,1,0,-1,1,-1,1,0,-1,0}; + // {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, + // 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, + // phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; + float weightsVector [nCouple]; /* Set position of feedback cloud particles */ FLOAT CloudParticlePositionX [nCouple]; @@ -145,10 +148,12 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, FLOAT CloudParticlePositionZ [nCouple]; /*all possible values of x,y,z with origin particle at x=y=z=0.0 */ + for (int cpInd = 0; cpInd < nCouple; cpInd++){ FLOAT norm = sqrt(CloudParticleVectorX[cpInd]*CloudParticleVectorX[cpInd] + CloudParticleVectorY[cpInd]*CloudParticleVectorY[cpInd] + CloudParticleVectorZ[cpInd]*CloudParticleVectorZ[cpInd]); + float xbaMag = A*A*norm*norm; /* in this cloud, take the coupling particle position as 0.5, 0.5, 0.5 */ CloudParticlePositionX[cpInd] = *xp-CloudParticleVectorX[cpInd]/norm* A; @@ -156,10 +161,19 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, A; CloudParticlePositionZ[cpInd] = *zp-CloudParticleVectorZ[cpInd]/norm* A; + weightsVector[cpInd] = 0.5*(1.-1./(1.+1./4./M_PI/26./xbaMag/M_PI)); /* turn the vectors back into unit-vectors */ CloudParticleVectorZ[cpInd] /= norm; CloudParticleVectorY[cpInd] /= norm; CloudParticleVectorX[cpInd] /= norm; + + } + float weightsSum = 0.0; + for (int wind = 0; wind < nCouple; wind++){ + weightsSum += weightsVector[wind]; + } + for (int wind = 0; wind < nCouple; wind++){ + weightsVector[wind] /= weightsSum; } /* Each particle gets 1/32 of energy, momenta, mass, and metal. There are no varying vector / scalar weights to worry about. The momenta coupled @@ -231,7 +245,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float pEjectMod = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5)/SolarMass/1e5; /* We want to couple one of four phases: free expansion, Sedov-taylor, shell formation, or terminal The first three phases are take forms from Kim & Ostriker 2015, the last from Cioffi 1988*/ - float cellwidth = dx*LengthUnits/pc_cm; + float cellwidth = stretchFactor*dx*LengthUnits/pc_cm; float p_free = 0.0;//sqrt(ejectaMass*SolarMass*ejectaEnergy)/SolarMass/1e5;//1.73e4*sqrt(ejectaMass*ejectaEnergy/1e51/3.); // free exp. momentum eq 15 float r_free = 2.75*pow(ejectaMass/3/nmean, 1./3.); // free exp radius eq 2 @@ -345,11 +359,11 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, This implementation is simple since our coupled particles are spherically symmetric about the feedback particle*/ - coupledEnergy = eKinetic/float(nCouple); - coupledGasEnergy /= float(nCouple); - coupledMass /= float(nCouple); - coupledMetals /= float(nCouple); - coupledMomenta /= float(nCouple); + // coupledEnergy = eKinetic/float(scalarWeight); + // coupledGasEnergy /= float(scalarWeight); + // coupledMass /= float(scalarWeight); + // coupledMetals /= float(scalarWeight); + // coupledMomenta /= float(scalarWeight); /* Transform coupled quantities to code units */ @@ -363,50 +377,54 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; for (int n = 0; n < nCouple; n++){ - - FLOAT pX = coupledMomenta*CloudParticleVectorX[n]; - FLOAT pY = coupledMomenta*CloudParticleVectorY[n]; - FLOAT pZ = coupledMomenta*CloudParticleVectorZ[n]; + //fprintf(stdout, "Weight %d = %f", n, weightsVector[n]); + FLOAT pX = coupledMomenta*CloudParticleVectorX[n]*weightsVector[n]; + FLOAT pY = coupledMomenta*CloudParticleVectorY[n]*weightsVector[n]; + FLOAT pZ = coupledMomenta*CloudParticleVectorZ[n]*weightsVector[n]; + float eCouple = coupledEnergy*weightsVector[n]; + float geCouple = coupledGasEnergy * weightsVector[n]; + float mCouple = coupledMass * weightsVector[n]; + float zCouple = coupledMetals * weightsVector[n]; int np = 1; FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np,&coupledMass, &density[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &CloudParticlePositionZ[n], &GridRank, &np,&mCouple, &density[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np,&coupledMetals, &metals[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &CloudParticlePositionZ[n], &GridRank, &np,&zCouple, &metals[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (pX != 0.0){ FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank, &np,&pX, &u[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); } if (pY != 0.0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&pY, &v[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (pZ != 0.0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&pZ, &w[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (coupledEnergy > 0 && DualEnergyFormalism) - coupledEnergy += coupledGasEnergy; + eCouple += geCouple; FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&coupledEnergy, &totalEnergy[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &CloudParticlePositionZ[n], &GridRank,&np,&eCouple, &totalEnergy[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (coupledGasEnergy > 0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&coupledGasEnergy, &gasEnergy[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &CloudParticlePositionZ[n], &GridRank,&np,&geCouple, &gasEnergy[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); } /* Deposit one negative mass particle centered on star to account for shell mass leaving host cells . Same for metals that were evacuated*/ int np = 1; shellMass *= -1/MassUnits; FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMass, &density[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); shellMetals *= -1/MassUnits; FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMetals, &metals[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &dx); + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); /* transform the grid to comoving with star ; wouldnt recommend this on root grid if its too big...*/ From 76fe2a3e18aacf3c966811604feab2b0083ef5d9 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Tue, 17 Sep 2019 18:44:42 -0700 Subject: [PATCH 011/115] Added seeding field for PIII stars; separately track SNII metal, SNIa metals, and P3 metals in different fields. --- src/enzo/CosmologySimulationInitialize.C | 13 + src/enzo/Grid.h | 7 +- src/enzo/Grid_ComputeCoolingTime.C | 5 +- .../Grid_CosmologySimulationInitializeGrid.C | 13 +- src/enzo/Grid_GrackleWrapper.C | 4 +- src/enzo/Grid_MechStarsCreation.C | 153 ++++++----- src/enzo/Grid_MechStarsDepositFeedback.C | 254 ++++++++++-------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 34 ++- src/enzo/Grid_MechStarsSeedSupernova.C | 205 ++++++++++++++ ..._NestedCosmologySimulationInitializeGrid.C | 15 +- src/enzo/Grid_StarParticleHandler.C | 5 +- src/enzo/InitializeNew.C | 2 +- src/enzo/MechStars_checkCreationCriteria.C | 22 +- src/enzo/MechStars_determineSN.C | 2 + src/enzo/MechStars_determineWinds.C | 39 ++- .../MechStars_transformComovingWithStar.C | 10 +- .../NestedCosmologySimulationInitialize.C | 15 ++ src/enzo/ReadParameterFile.C | 3 + src/enzo/SetDefaultGlobalValues.C | 3 +- src/enzo/StarParticleData.h | 3 + src/enzo/WriteParameterFile.C | 3 +- src/enzo/typedefs.h | 2 +- 22 files changed, 588 insertions(+), 224 deletions(-) create mode 100644 src/enzo/Grid_MechStarsSeedSupernova.C diff --git a/src/enzo/CosmologySimulationInitialize.C b/src/enzo/CosmologySimulationInitialize.C index 0a8817758..5fd4d9b39 100644 --- a/src/enzo/CosmologySimulationInitialize.C +++ b/src/enzo/CosmologySimulationInitialize.C @@ -83,6 +83,7 @@ static float CosmologySimulationInitialFractionH2I = 2.0e-20; static float CosmologySimulationInitialFractionH2II = 3.0e-14; static float CosmologySimulationInitialFractionMetal = 1.0e-10; static float CosmologySimulationInitialFractionMetalIa = 1.0e-12; +static float CosmologySimulationsInitialFractionMetalII = 1.0e-12; static int CosmologySimulationUseMetallicityField = FALSE; static int CosmologySimulationManuallySetParticleMassRatio = FALSE; @@ -125,6 +126,8 @@ int CosmologySimulationInitialize(FILE *fptr, FILE *Outfptr, char *HDIName = "HDI_Density"; char *MetalName = "Metal_Density"; char *MetalIaName = "MetalSNIa_Density"; + char *MetalIIName = "MetalSNII_Density"; + char *ColourName = "SN_Colour"; char *GPotName = "Grav_Potential"; char *ForbidName = "ForbiddenRefinement"; char *MachName = "Mach"; @@ -301,6 +304,8 @@ int CosmologySimulationInitialize(FILE *fptr, FILE *Outfptr, &CosmologySimulationInitialFractionMetal); ret += sscanf(line, "CosmologySimulationInitialFractionMetalIa = %"FSYM, &CosmologySimulationInitialFractionMetalIa); + ret += sscanf(line, "CosmologySimulationInitialFractionMetalII = %"FSYM, + &CosmologySimulationsInitialFractionMetalII); ret += sscanf(line, "CosmologySimulationUseMetallicityField = %"ISYM, &CosmologySimulationUseMetallicityField); @@ -663,6 +668,7 @@ int CosmologySimulationInitialize(FILE *fptr, FILE *Outfptr, CosmologySimulationInitialFractionH2II, CosmologySimulationInitialFractionMetal, CosmologySimulationInitialFractionMetalIa, + CosmologySimulationsInitialFractionMetalII, #ifdef TRANSFER RadHydroInitialRadiationEnergy, #endif @@ -791,10 +797,14 @@ int CosmologySimulationInitialize(FILE *fptr, FILE *Outfptr, DataLabel[i++] = MetalName; if (StarMakerTypeIaSNe) DataLabel[i++] = MetalIaName; + if (StarMakerTypeIISNeMetalField) + DataLabel[i++] = MetalIIName; if(MultiMetals){ DataLabel[i++] = ExtraNames[0]; DataLabel[i++] = ExtraNames[1]; } + if (MechStarsSeedField) + DataLabel[i++] = ColourName; } if(STARMAKE_METHOD(COLORED_POP3_STAR)){ DataLabel[i++] = ForbidName; @@ -930,6 +940,8 @@ int CosmologySimulationInitialize(FILE *fptr, FILE *Outfptr, CosmologySimulationInitialFractionMetal); fprintf(Outfptr, "CosmologySimulationInitialFractionMetalIa = %"GSYM"\n", CosmologySimulationInitialFractionMetalIa); + fprintf(Outfptr, "CosmologySimulationInitialFractionMetalII = %"GSYM"\n", + CosmologySimulationsInitialFractionMetalII); fprintf(Outfptr, "CosmologySimulationUseMetallicityField = %"ISYM"\n\n", CosmologySimulationUseMetallicityField); @@ -1076,6 +1088,7 @@ int CosmologySimulationReInitialize(HierarchyEntry *TopGrid, CosmologySimulationInitialFractionH2II, CosmologySimulationInitialFractionMetal, CosmologySimulationInitialFractionMetalIa, + CosmologySimulationsInitialFractionMetalII, #ifdef TRANSFER RadHydroInitialRadiationEnergy, #endif diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index d067fe6e7..bf5d99912 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2217,6 +2217,7 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], float CosmologySimulationInitialFractionH2II, float CosmologySimulationInitialFractionMetal, float CosmologySimulationInitialFractionMetalIa, + float CosmologySimulationInitialFractionMetalII, #ifdef TRANSFER float RadHydroInitialRadiationEnergy, #endif @@ -2273,6 +2274,7 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], float CosmologySimulationInitialFractionH2II, float CosmologySimulationInitialFractionMetal, float CosmologySimulationInitialFractionMetalIa, + float CosmologySimulationInitialFractionMetalII, int CosmologySimulationUseMetallicityField, PINT &CurrentNumberOfParticles, int CosmologySimulationManuallySetParticleMassRatio, @@ -2889,8 +2891,9 @@ int MechStars_DepositFeedback(float supernovaEnergy, float* up, float* vp, float* wp, float* xp, float* yp, float* zp, int ip, int jp, int kp, - int size, float* mu_field, int winds); - + int size, float* mu_field, int winds, + int nSNII, int nSNIA, float starMetals, int isP3); +int MechStars_SeedSupernova(); //------------------------------------------------------------------------ // Radiative transfer methods that don't fit in the TRANSFER define diff --git a/src/enzo/Grid_ComputeCoolingTime.C b/src/enzo/Grid_ComputeCoolingTime.C index 109c2b03f..6b2df04ed 100644 --- a/src/enzo/Grid_ComputeCoolingTime.C +++ b/src/enzo/Grid_ComputeCoolingTime.C @@ -191,10 +191,11 @@ int grid::ComputeCoolingTime(float *cooling_time, int CoolingTimeOnly) float *MetalPointer = NULL; float *TotalMetals = NULL; - if (MetalNum != -1 && SNColourNum != -1) { + if (MetalNum != -1 && SNColourNum != -1 ) { TotalMetals = new float[size]; for (i = 0; i < size; i++) - TotalMetals[i] = BaryonField[MetalNum][i] + BaryonField[SNColourNum][i]; + TotalMetals[i] = BaryonField[MetalNum][i]+BaryonField[SNColourNum][i]; + MetalPointer = TotalMetals; } // ENDIF both metal types else { diff --git a/src/enzo/Grid_CosmologySimulationInitializeGrid.C b/src/enzo/Grid_CosmologySimulationInitializeGrid.C index 928a7e67e..57a83f1d7 100644 --- a/src/enzo/Grid_CosmologySimulationInitializeGrid.C +++ b/src/enzo/Grid_CosmologySimulationInitializeGrid.C @@ -106,6 +106,7 @@ int grid::CosmologySimulationInitializeGrid( float CosmologySimulationInitialFractionH2II, float CosmologySimulationInitialFractionMetal, float CosmologySimulationInitialFractionMetalIa, + float CosmologySimulationInitialFractionMetalII, #ifdef TRANSFER float RadHydroRadiation, #endif @@ -119,7 +120,7 @@ int grid::CosmologySimulationInitializeGrid( int idim, dim, i, j, vel, OneComponentPerFile, ndim, level; int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, - DINum, DIINum, HDINum, MetalNum, MetalIaNum; + DINum, DIINum, HDINum, MetalNum, MetalIaNum, MetalIINum, SNColourNum; #ifdef TRANSFER int EgNum; #endif @@ -290,10 +291,13 @@ int grid::CosmologySimulationInitializeGrid( FieldType[MetalNum = NumberOfBaryonFields++] = Metallicity; if (StarMakerTypeIaSNe) FieldType[MetalIaNum = NumberOfBaryonFields++] = MetalSNIaDensity; + FieldType[MetalIINum = NumberOfBaryonFields++] = MetalSNIIDensity; if(MultiMetals){ FieldType[ExtraField[0] = NumberOfBaryonFields++] = ExtraType0; FieldType[ExtraField[1] = NumberOfBaryonFields++] = ExtraType1; } + if (MechStarsSeedField) + FieldType[SNColourNum = NumberOfBaryonFields++] = SNColour; } if(STARMAKE_METHOD(COLORED_POP3_STAR)){ fprintf(stderr, "Initializing Forbidden Refinement color field\n"); @@ -515,7 +519,8 @@ int grid::CosmologySimulationInitializeGrid( for (i = 0; i < size; i++) BaryonField[MetalIaNum][i] = CosmologySimulationInitialFractionMetalIa * BaryonField[0][i]; - + BaryonField[MetalIINum][i] = CosmologySimulationInitialFractionMetalII + * BaryonField[0][i]; if (MultiMetals) { for (i = 0; i < size; i++) { BaryonField[ExtraField[0]][i] = CosmologySimulationInitialFractionMetal @@ -523,6 +528,10 @@ int grid::CosmologySimulationInitializeGrid( BaryonField[ExtraField[1]][i] = CosmologySimulationInitialFractionMetal * BaryonField[0][i]; } + if (MechStarsSeedField) + for (i=0; i< size; i++) + BaryonField[SNColourNum][i] = CosmologySimulationInitialFractionMetal + * BaryonField[0][i]; } if (STARMAKE_METHOD(COLORED_POP3_STAR) && ReadData) { diff --git a/src/enzo/Grid_GrackleWrapper.C b/src/enzo/Grid_GrackleWrapper.C index b1acd0309..3e20cef59 100644 --- a/src/enzo/Grid_GrackleWrapper.C +++ b/src/enzo/Grid_GrackleWrapper.C @@ -138,6 +138,7 @@ int grid::GrackleWrapper() // the solver) MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields); SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); + MetalFieldPresent = (MetalNum != -1 || SNColourNum != -1); // Double check if there's a metal field when we have metal cooling @@ -157,7 +158,8 @@ int grid::GrackleWrapper() if (MetalNum != -1 && SNColourNum != -1) { TotalMetals = new float[size]; for (i = 0; i < size; i++) - TotalMetals[i] = BaryonField[MetalNum][i] + BaryonField[SNColourNum][i]; + TotalMetals[i] = BaryonField[MetalNum][i]+BaryonField[SNColourNum][i]; + MetalPointer = TotalMetals; } // ENDIF both metal types else { diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index a53968cb8..3e0c27f46 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -3,7 +3,7 @@ Formation follows Hopkins 2017 "How to model supernovae" 07/2019: Azton Wells - */ + */ #include #include #include @@ -22,11 +22,12 @@ int checkCreationCriteria(float* Density, float* Metals, float* Temperature,float* DMField, - float* Vel1, float* Vel2, float* Vel3, + float* Vel1, float* Vel2, float* Vel3, float* CoolingTime, int* GridDim, - float* shieldedFraction, float* freeFallTime, - float* dynamicalTime, int i, int j, int k, - float Time, float* RefinementField, float CellWidth); + float* shieldedFraction, float* freeFallTime, + float* dynamicalTime, int i, int j, int k, + float Time, float* RefinementField, float CellWidth, + bool* gridShouldFormStars, bool* notEnoughMetals); int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, float *MassUnits, float Time); @@ -34,15 +35,15 @@ /* Creation Routine */ -int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, - float *DMField, int level, float* CoolingTime, +int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, + float *DMField, int level, float* CoolingTime, int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar) { if (level < StarMakeLevel) return 0; - float stretchFactor=1.4; - bool debug = false; - // fprintf(stdout, "Preparing to check grids\n"); - // limit creation to level specified in parameter file + bool gridShouldFormStars=false, notEnoughMetals = true; + float stretchFactor=0.6; + bool debug = true; + //get field numbers int DensNum, GENum, Vel1Num, Vel2Num,Vel3Num, TENum; @@ -51,8 +52,8 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); return FAIL; } - - int MetallicityField = FALSE, MetalNum; + + int MetallicityField = FALSE, MetalNum, MetalIaNum, MetalIINum, SNColourNum; if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) { @@ -62,8 +63,8 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } + return FAIL; + } } else MetalNum = 0; @@ -71,30 +72,39 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, fprintf(stderr, "Can only use mechanical star maker routines with metallicity enabled!"); return FAIL; } - - + MetalIaNum = FindField(MetalSNIaDensity, FieldType, NumberOfBaryonFields); + MetalIINum = FindField(MetalSNIIDensity, FieldType, NumberOfBaryonFields); + SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); + int size =1; + for (int dim = 0; dim < GridRank; dim ++) + size *= GridDimension[dim]; + float totalMetal [size]; + for (int i = 0; i< size; i++){ + totalMetal[i] = BaryonField[MetalNum][i]; + if (SNColourNum > 0) totalMetal[i] += BaryonField[SNColourNum][i]; + } int rank = GridRank; - + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } + return FAIL; + } /* Define MassUnits so that code * mass = physical (Msun) and physical(Msun) / MassUnits = code */ MassUnits = DensityUnits*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass; - + float dx = CellWidth[0][0]; int GZ = int(NumberOfGhostZones); int nCreated = *NumberOfParticlesSoFar; //fprintf(stdout, "Starting creation with %d prior particles\n",nCreated); for (int i = GZ; i < GridDimension[0]-GZ; i++){ for(int j = GZ; j < GridDimension[1]-GZ; j++){ - for (int k = GZ; k< GridDimension[2]-GZ; k++){ + for (int k = GZ; k< GridDimension[2]-GZ; k++){ /* Particle creation has several criteria: @@ -103,7 +113,8 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, 3. is cooling time < dynamical time 4. is gas mass > jean critical mass 5. is gas self shielded by Krumholz & Gnedin 2007 criteria - + 6. is virial parameter < 1 + */ float shieldedFraction = 0; float freeFallTime = 0; @@ -111,21 +122,22 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float Time = this->Time; int createStar = checkCreationCriteria(BaryonField[DensNum], - BaryonField[MetalNum], Temperature, DMField, - BaryonField[Vel1Num], BaryonField[Vel2Num], + &totalMetal[0], Temperature, DMField, + BaryonField[Vel1Num], BaryonField[Vel2Num], BaryonField[Vel3Num], CoolingTime, GridDimension, &shieldedFraction, - &freeFallTime, &dynamicalTime, i,j,k,Time, - BaryonField[NumberOfBaryonFields], CellWidth[0][0]); - - - + &freeFallTime, &dynamicalTime, i,j,k,Time, + BaryonField[NumberOfBaryonFields], CellWidth[0][0], + &gridShouldFormStars, ¬EnoughMetals); + + + if (createStar) printf ("SMM Criteria passed!\n"); if (createStar){ int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; /* Determine Mass of new particle */ - float MassShouldForm =(shieldedFraction * BaryonField[DensNum][index] + float MassShouldForm =(shieldedFraction * BaryonField[DensNum][index] * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13); if (MassShouldForm < 0){ @@ -135,42 +147,56 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float newMass = min(MassShouldForm, StarMakerMaximumFormationMass); newMass = newMass/MassUnits; - if (newMass > BaryonField[DensNum][index]) ENZO_FAIL("STAR MASS > CELL MASS"); - if (newMass*MassUnits < StarMakerMinimumMass){ - fprintf(stdout,"NOT ENOUGH MASS IN CELL \n"); - continue; + if (newMass > 0.9*BaryonField[DensNum][index] || + newMass*MassUnits < StarMakerMinimumMass){ + fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e\n", + newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits); + continue; } float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); // fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); ParticleArray->ParticleMass[nCreated] = newMass; - ParticleArray->ParticleAttribute[1][nCreated] = dynamicalTime/TimeUnits; + ParticleArray->ParticleAttribute[1][nCreated] = 0.0; // Tracking SNE in TDP field dynamicalTime/TimeUnits; ParticleArray->ParticleAttribute[0][nCreated] = Time; - ParticleArray->ParticleAttribute[2][nCreated] = BaryonField[MetalNum][index] + + ParticleArray->ParticleAttribute[2][nCreated] = totalMetal[index] /BaryonField[DensNum][index]; + if (StarMakerTypeIaSNe) + ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIaNum][index]; + ParticleArray->ParticleType[nCreated] = PARTICLE_TYPE_STAR; BaryonField[DensNum][index] -= newMass; + BaryonField[MetalNum][index] -= newMass*totalMetal[index]/BaryonField[DensNum][index]; + if (MetalIaNum > 0) + BaryonField[MetalIaNum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[MetalIaNum][index]; + if (MetalIINum > 0) + BaryonField[MetalIINum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[MetalIINum][index]; + if (SNColourNum > 0) + BaryonField[SNColourNum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[SNColourNum][index]/BaryonField[DensNum][index]; + // type IA metal field isnt here right now - // if (StarMakerTypeIASNe) + // if (StarMakerTypeIASNe) // ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIANum]; - int preI = index-1; - int postI = index+1; - int preJ = i+ (j-1)*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; - int postJ = i+ (j+1)*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; - int preK = i+ j*GridDimension[0]+(k-1)*GridDimension[0]*GridDimension[1]; - int postK = i+ j*GridDimension[0]+(k+1)*GridDimension[0]*GridDimension[1]; - if (HydroMethod != 0) + float vX = 0.0; + float vY = 0.0; + float vZ = 0.0; + if (HydroMethod != 0) fprintf(stderr,"Mechanical star maker not tested for anything except HydroMethod = 0\n"); - ParticleArray->ParticleVelocity[0][nCreated] = - 0.033*(BaryonField[Vel1Num][preI]+BaryonField[Vel1Num][postI] - +BaryonField[Vel1Num][index]); - ParticleArray->ParticleVelocity[1][nCreated] = - 0.033*(BaryonField[Vel2Num][preI]+BaryonField[Vel2Num][postI] - +BaryonField[Vel2Num][index]); - ParticleArray->ParticleVelocity[2][nCreated] = - 0.033*(BaryonField[Vel3Num][preI]+BaryonField[Vel3Num][postI] - +BaryonField[Vel3Num][index]); + /* average particle velocity over 125 cells to prevent runaway */ + for (int ip = i-2; ip <= i + 2 ; ip++) + for (int jp = j-2; jp <= j+2 ; jp++) + for (int kp = k-2; kp <= k+2; kp++){ + int ind = ip + jp*GridDimension[0]+kp*GridDimension[0]+GridDimension[1]; + vX += BaryonField[Vel1Num][ind]; + vY += BaryonField[Vel2Num][ind]; + vZ += BaryonField[Vel3Num][ind]; + } + + ParticleArray->ParticleVelocity[0][nCreated] = vX/125.0; + ParticleArray->ParticleVelocity[1][nCreated] = vY/125.0; + ParticleArray->ParticleVelocity[2][nCreated] = vZ/125.0; /* give it position at center of host cell */ @@ -181,12 +207,12 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] +(dx*(float(k)+0.5)); if (nCreated >= MaximumNumberOfNewParticles) return nCreated; - if (debug) - fprintf(stdout,"Created star: %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", - nCreated, - ParticleArray->ParticleType[nCreated], - ParticleArray->ParticleMass[nCreated]*MassUnits, - ParticleArray->ParticleAttribute[0][nCreated], + if (true) + fprintf(stdout,"Created star: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", + level, nCreated, + ParticleArray->ParticleType[nCreated], + ParticleArray->ParticleMass[nCreated]*MassUnits, + ParticleArray->ParticleAttribute[0][nCreated], ParticleArray->ParticleAttribute[1][nCreated], ParticleArray->ParticleAttribute[2][nCreated], ParticleArray->ParticlePosition[0][nCreated], @@ -201,6 +227,13 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, }//end for k }//end for j } // end for i + if (gridShouldFormStars && notEnoughMetals && MechStarsSeedField){ + // set off a p3 supernova at the center of this grid if the + // grid can host star formation but has no appreciable metals + if (debug) fprintf(stdout, "\n\n\nCreating seed field!\n\n\n\n"); + MechStars_SeedSupernova(); + + } //if (nCreated > 0 && debug){ // fprintf(stdout, "Created %d star particles\n",nCreated); // } diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 74bc2828d..0dd88113e 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -23,6 +23,7 @@ float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, float *MassUnits, float Time); int transformComovingWithStar(float* Density, float* Metals, + float* MetalsSNII, float* MetalsSNIA, float* Vel1, float* Vel2, float* Vel3, float up, float vp, float wp, int sizeX, int sizeY, int sizeZ, int direction); @@ -34,7 +35,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float* up, float* vp, float* wp, float* xp, float* yp, float* zp, int ip, int jp, int kp, - int size, float* muField, int winds){ + int size, float* muField, int winds, int nSNII, + int nSNIA, float starMetal, int isP3){ /* This routine will create an isocahedron of coupling particles, where we determine @@ -44,11 +46,12 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, */ bool debug = true; bool criticalDebug = true; + bool printout = debug && !winds; int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; /* Compute size (in floats) of the current grid. */ - float stretchFactor =1.;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host + float stretchFactor =1.0;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host // in units of dx. Since the cloud forms a sphere shell, stretchFactor > 1 is not recommended size = 1; for (int dim = 0; dim < GridRank; dim++) @@ -73,7 +76,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, } FLOAT dx = CellWidth[0][0]; - if (debug) + if (printout) fprintf(stdout, "depositing quantities: Energy %e, Mass %e, Metals %e\n", ejectaEnergy, ejectaMass, ejectaMetal); @@ -81,23 +84,33 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, get metallicity field and set flag; assumed true thoughout feedback since so many quantities are metallicity dependent */ - int MetallicityField = FALSE, MetalNum; + int MetallicityField = FALSE, MetalNum, MetalIaNum, MetalIINum, SNColourNum; if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) MetallicityField = TRUE; - else + else{ + fprintf(stdout, "MechStars only functions with metallicity field enabled!"); + ENZO_FAIL("Grid_MechStarsDepositFeedback: 91"); MetalNum = 0; - + } + MetalIaNum = FindField(MetalSNIaDensity, FieldType, NumberOfBaryonFields); + MetalIINum = FindField(MetalSNIIDensity, FieldType, NumberOfBaryonFields); + SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); + if (PopIIISupernovaUseColour && SNColourNum==-1) ENZO_FAIL("Cant use Seed Field without SNColour field"); /* set other units that we need */ MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; //Msun! float EnergyUnits = DensityUnits*pow(LengthUnits*dx, 3) * VelocityUnits*VelocityUnits;//[g cm^2/s^2] -> code_energy - float MomentaUnits = VelocityUnits; + float MomentaUnits = MassUnits*VelocityUnits; /* Make copys of fields to work with. These will conatin the added deposition of all quantities and be coupled to the grid after the cic deposition. */ + float totalMetals [size]; float density [size]; float metals [size]; + float metalsII [size]; + float metalsIA [size]; + float metalsIII [size]; float u [size]; float v [size]; float w [size]; @@ -106,11 +119,18 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, for (int i=0; i respective momenta. Use -1 to reverse transform after.*/ @@ -124,22 +144,22 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* A DODECAHEDRON+ISOCAHEDRON */ - int nCouple = 26; + int nCouple = 32; float A = stretchFactor*dx; - float cloudSize=1.*dx; + float cloudSize=stretchFactor*dx; /* Points from HEALPix algorithm; 48 equally dist. points*/ - FLOAT CloudParticleVectorX [] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - // {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, - // iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, - // 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; - FLOAT CloudParticleVectorY [] = {1,1,1,0,0,-1,-1,-1,0,1,1,1,0,0,-1,-1,-1,1,1,1,0,0,-1,-1,-1,0}; - // {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, - // phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, - // phi, -phi, -phi, phi, 0, 0, 0, 0}; - FLOAT CloudParticleVectorZ [] ={1,0,-1,1,-1,1,0,-1,0,1,0,-1,1,-1,1,0,-1,1,0,-1,1,-1,1,0,-1,0}; - // {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, - // 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, - // phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; + FLOAT CloudParticleVectorX [] = //{-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, + iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, + 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; + FLOAT CloudParticleVectorY [] = //{1,1,1,0,0,-1,-1,-1,0,1,1,1,0,0,-1,-1,-1,1,1,1,0,0,-1,-1,-1,0}; + {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, + phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, + phi, -phi, -phi, phi, 0, 0, 0, 0}; + FLOAT CloudParticleVectorZ [] = //{1,0,-1,1,-1,1,0,-1,0,1,0,-1,1,-1,1,0,-1,1,0,-1,1,-1,1,0,-1,0}; + {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, + 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, + phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; float weightsVector [nCouple]; /* Set position of feedback cloud particles */ @@ -183,6 +203,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* transform to comoving with the star and take velocities to momenta */ transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], + BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], *up, *vp, *wp, GridDimension[0], GridDimension[1], GridDimension[2], 1); @@ -191,13 +212,13 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, M_shell > 0 iff v_shell > v_gas */ float zmean=0, dmean=0, nmean=0, vmean; for (int ind = -1; ind <= 1; ind++){ - zmean += BaryonField[MetalNum][index+ind]*BaryonField[DensNum][index+ind]; - zmean += BaryonField[MetalNum][index+GridDimension[0]*ind]*BaryonField[DensNum][index+GridDimension[0]*ind]; - zmean += BaryonField[MetalNum][index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + zmean += totalMetals[index+ind]*BaryonField[DensNum][index+ind]; + zmean += totalMetals[index+GridDimension[0]*ind]*BaryonField[DensNum][index+GridDimension[0]*ind]; + zmean += totalMetals[index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; - if (debug) fprintf(stdout, "MuField = %f %f %f\nmax = %d ; %d %d %d\n", - muField[index+ind], muField[index+GridDimension[0]*ind], muField[index+ind*GridDimension[0]*GridDimension[1]], GridDimension[0]*GridDimension[1]*GridDimension[2], - index+ind, index+GridDimension[0]*ind, index+ind*GridDimension[0]*GridDimension[1]); + // if (printout) fprintf(stdout, "MuField = %f %f %f\nmax = %d ; %d %d %d\n", + // muField[index+ind], muField[index+GridDimension[0]*ind], muField[index+ind*GridDimension[0]*GridDimension[1]], GridDimension[0]*GridDimension[1]*GridDimension[2], + // index+ind, index+GridDimension[0]*ind, index+ind*GridDimension[0]*GridDimension[1]); nmean += BaryonField[DensNum][index+ind]*BaryonField[DensNum][index+ind]*DensityUnits/mh/max(0.6,muField[index+ind]); nmean += BaryonField[DensNum][index+GridDimension[0]*ind]* BaryonField[DensNum][index+GridDimension[0]*ind]*DensityUnits/mh/max(muField[index+GridDimension[0]*ind],0.6); @@ -225,7 +246,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, zmean /= (dmean*0.02); nmean /= (dmean); - dmean /= 9.0; + dmean = dmean*DensityUnits/9.0; nmean = max(nmean, 1e-3); float zZsun = max(zmean, 1e-8); float fz = (zZsun < 0.01)? (2.0): (pow(zZsun, -0.14)); @@ -234,14 +255,15 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float CoolingRadius = 28.4 * pow(max(0.001,nmean), -3.0/7.0) *pow(ejectaEnergy/1.0e51, 2.0/7.0)* fz; - if (debug)fprintf(stdout, "cooling radius [pc] = %f\n %f %f %f %e %f \n", + if (printout)fprintf(stdout, "cooling radius [pc] = %e\n %f %e %f %e %e \n", CoolingRadius, nmean, ejectaEnergy/1e51, fz, zmean, dmean); /* Calculate coupled energy scaled by reduction to account for unresolved cooling, then use that energy to calculate momenta*/ float coupledEnergy = ejectaEnergy; - if (debug)fprintf(stdout, "Dx [pc] = %f\n", dx*LengthUnits/pc_cm); + if (printout)fprintf(stdout, "Dx [pc] = %f\n", dx*LengthUnits/pc_cm); float dxRatio = stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius; + if (winds) dxRatio = min(stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius, 20); float pEjectMod = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5)/SolarMass/1e5; /* We want to couple one of four phases: free expansion, Sedov-taylor, shell formation, or terminal The first three phases are take forms from Kim & Ostriker 2015, the last from Cioffi 1988*/ @@ -267,23 +289,23 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float coupledMomenta = 0.0; float eKinetic = 0.0; - fprintf(stdout, "RADII: %e %e %e t_3=%e\n", r_free, r_shellform, CoolingRadius, t3_sedov); + if(printout)fprintf(stdout, "RADII: %e %e %e t_3=%e\n", r_free, r_shellform, CoolingRadius, t3_sedov); /* Select the mode of coupling */ if (cellwidth < r_free){ coupledMomenta = p_free; - fprintf(stdout, "Coupling free expansion\n");} + if(printout)fprintf(stdout, "Coupling free expansion\n");} if (cellwidth > r_free && cellwidth < r_shellform){ coupledMomenta = min(p_sedov, p_shellform*cellwidth/r_shellform); - fprintf(stdout, "Coupling S-T phase\n");} + if(printout)fprintf(stdout, "Coupling S-T phase\n");} if (cellwidth > r_shellform && cellwidth < CoolingRadius){ coupledMomenta = min(p_shellform+(cellwidth-r_shellform)*(pTerminal-p_shellform)/(CoolingRadius-r_shellform), pTerminal); - fprintf(stdout, "Coupling shell-forming stage\n");} + if(printout)fprintf(stdout, "Coupling shell-forming stage\n");} if (cellwidth > CoolingRadius){ coupledMomenta = pTerminal; - fprintf(stdout, "Coupling terminal momenta\n");} - if (debug)fprintf(stdout, "Calculated p = %e\n", coupledMomenta); + if(printout)fprintf(stdout, "Coupling terminal momenta\n");} + if (printout)fprintf(stdout, "Calculated p = %e\n", coupledMomenta); /* fading radius of a SNR */ @@ -293,11 +315,12 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float KBcode = kboltz*MassUnits/(LengthUnits*dx)/pow(TimeUnits,2); float cSound = sqrt(5/3*kboltz*temperature[index]/mh/muField[index])/1e5; //km/s float r_fade = 66.0*pow(ejectaEnergy/1e51, 0.32)*pow(nmean, -0.37)*pow(min(cSound/10, .1), -2.0/5.0); - fprintf(stdout, "Rfade = %e cs = %e \n", r_fade, cSound); + if(printout) fprintf(stdout, "Rfade = %e cs = %e \n", r_fade, cSound); delete [] temperature; - coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3)):(coupledMomenta); + coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3/2)):(coupledMomenta); float shellMass = 0.0, shellVelocity = 0.0; + if(printout) printf("Coupled momentum: %e\n", coupledMomenta); /* If resolution is in a range compared to Rcool and Analytic SNR shell mass is on, adjust the shell mass Shell mass calculation is limited by considering the local gas @@ -336,23 +359,29 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, ENZO_FAIL("SM_deposit: 252");} float coupledMass = shellMass+ejectaMass; eKinetic = coupledMomenta*coupledMomenta - /(2.0*dmean*MassUnits)*SolarMass*1e10; - if (debug)fprintf(stdout, "Ekinetic = %e\n", eKinetic); + /(2.0*dmean*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass)*SolarMass*1e10; + if (printout)fprintf(stdout, "Ekinetic = %e Mass = %e\n", + eKinetic, dmean*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass); + if (eKinetic > 1e60) ENZO_FAIL("Ekinetic > reasonability!\n"); float coupledGasEnergy = max(ejectaEnergy-eKinetic, 0); - if (debug)fprintf(stdout, "Coupled Gas Energy = %e\n",coupledGasEnergy); + if (printout)fprintf(stdout, "Coupled Gas Energy = %e\n",coupledGasEnergy); if (dxRatio > 2.0) coupledGasEnergy = (DepositUnresolvedEnergyAsThermal) ?(coupledGasEnergy) :(coupledGasEnergy*pow(dxRatio, -6.5)); float shellMetals = zZsun*0.02 * shellMass; - float coupledMetals = ejectaMetal + shellMetals; + float coupledMetals = 0.0, SNIAmetals = 0.0, SNIImetals = 0.0, P3metals = 0.0; + if (winds) coupledMetals = ejectaMetal ;//+ shellMetals; // winds only couple to metallicity + SNIAmetals = (StarMakerTypeIaSNe) ? nSNIA * 1.4 : 0.0; + SNIImetals = (StarMakerTypeIISNeMetalField)? nSNII*(1.91+0.0479*max(starMetal, 1.65)) : 0.0; + if (isP3) P3metals = ejectaMetal; - if (debug) fprintf(stdout, "Coupled Momentum: %e\n", coupledMomenta); + if (printout) fprintf(stdout, "Coupled Metals: %e %e %e %e %e\n", ejectaMetal, SNIAmetals, SNIImetals, shellMetals, P3metals); /* Reduce coupled quantities to per-particle quantity and convert to code units. Hopkins has complicated weights due to complicated geometry. @@ -366,16 +395,19 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, // coupledMomenta /= float(scalarWeight); /* Transform coupled quantities to code units */ - + coupledEnergy = min(eKinetic, ejectaEnergy); coupledEnergy /= EnergyUnits; coupledGasEnergy /= EnergyUnits; coupledMass /= MassUnits; coupledMetals /= MassUnits; coupledMomenta /= MomentaUnits; - + SNIAmetals /= MassUnits; + SNIImetals /= MassUnits; + P3metals /= MassUnits; /* CIC deposit the particles with their respective quantities */ float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; + // if (printout) fprintf(stdout, "Entering CIC Loop over cloud particles\n"); for (int n = 0; n < nCouple; n++){ //fprintf(stdout, "Weight %d = %f", n, weightsVector[n]); FLOAT pX = coupledMomenta*CloudParticleVectorX[n]*weightsVector[n]; @@ -385,11 +417,18 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float geCouple = coupledGasEnergy * weightsVector[n]; float mCouple = coupledMass * weightsVector[n]; float zCouple = coupledMetals * weightsVector[n]; + float zIICouple = SNIImetals * weightsVector[n]; + float zIACouple = SNIAmetals * weightsVector[n]; + float p3Couple = P3metals * weightsVector[n]; int np = 1; FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank, &np,&mCouple, &density[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + + // if (!winds) + zCouple += zIICouple + zIACouple; + // printf("Zcpl = %e", zCouple); FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank, &np,&zCouple, &metals[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); @@ -406,15 +445,29 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&pZ, &w[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (coupledEnergy > 0 && DualEnergyFormalism) + if (coupledEnergy > 0 && DualEnergyFormalism && geCouple > 0) eCouple += geCouple; FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&eCouple, &totalEnergy[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (coupledGasEnergy > 0) + if (geCouple > 0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&geCouple, &gasEnergy[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (zIICouple > 0.0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&zIICouple, &metalsII[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (zIACouple > 0.0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&zIACouple, &metalsIA[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (p3Couple > 0.0){ + if (printout)printf("Coupling %f to pIII metals %d\n",p3Couple*MassUnits, n); + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&p3Couple, &metalsIII[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + } } /* Deposit one negative mass particle centered on star to account for shell mass leaving host cells . Same for metals that were evacuated*/ @@ -426,16 +479,20 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMetals, &metals[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - + // printf("Entering Critical printout section\n"); /* transform the grid to comoving with star ; wouldnt recommend this on root grid if its too big...*/ - - float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0; + float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0, preZII=0, preZIa = 0; float dsum = 0.0, zsum=0.0, psum=0.0, psqsum =0.0, tesum=0.0, gesum=0.0, kesum=0.0; - float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0; - if (criticalDebug){ + float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0, postZII=0, postZIa = 0; + if (criticalDebug && !winds){ for (int i=0; i 0) + preZII += BaryonField[MetalIINum][i]; + if (MetalIaNum > 0) + preZIa += BaryonField[MetalIaNum][i]; + if (SNColourNum > 0) preZ += BaryonField[SNColourNum][i]; preP += BaryonField[Vel1Num][i]+BaryonField[Vel2Num][i]+BaryonField[Vel3Num][i]; prePmag += pow(BaryonField[Vel1Num][i]*MomentaUnits,2)+ pow(BaryonField[Vel2Num][i]*MomentaUnits,2) @@ -444,67 +501,49 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, preGE += BaryonField[GENum][i]; } } - /* Since wind energy is so low, if we want to couple something - it will have to thermal at host cell. */ - if (winds && DepositUnresolvedEnergyAsThermal && coupledEnergy == 0){ - totalEnergy[index] = (double(ejectaEnergy)*1e30)/double(EnergyUnits)/BaryonField[DensNum][index]/1e30; - } + + /* Couple the faux deposition grids to to the real grids */ for (int i = 0; i < size; i++){ - float delta = (density[i]) + float delta = (BaryonField[DensNum][i]) /(density[i]+BaryonField[DensNum][i]); - /* Couple placeholder fields to the grid, account - for grids that got initialized to -0.0*/ - BaryonField[DensNum][i] += density[i]; - - //Metals transformed back to density in transform routine - - BaryonField[MetalNum][i] += metals[i]; - BaryonField[TENum][i] += - totalEnergy[i]/BaryonField[DensNum][i]; - - BaryonField[GENum][i] += - gasEnergy[i]/BaryonField[DensNum][i]; - BaryonField[Vel1Num][i] += u[i]; - BaryonField[Vel2Num][i] += v[i]; - BaryonField[Vel3Num][i] += w[i]; - } - + if (delta < 1){ + float deltaZ = BaryonField[MetalNum][i]/(metals[i]+BaryonField[MetalNum][i]); + /* Couple placeholder fields to the grid, account + for grids that got initialized to -0.0*/ + BaryonField[DensNum][i] += density[i]; - /* Sum of feedback quantities: */ - if (debug){ - for (int i = 0; i 0)? - (u[i]*u[i]+v[i]*v[i]+w[i]*w[i])*MomentaUnits*MomentaUnits - /(2*density[i]*MassUnits)*SolarMass*1e10 - : 0; - - } - - fprintf(stdout, "Sum Mass = %e ", dsum*MassUnits); - fprintf(stdout, "Metals = %e ", zsum*MassUnits); - fprintf(stdout, " momenta magnitude = %e ", sqrt(psqsum)); - - fprintf(stdout, " momenta error = %e ", psum*MomentaUnits); - fprintf(stdout, " KE deposit = %e", kesum); - fprintf(stdout, " Gas energy = %e ", gesum * EnergyUnits); - fprintf(stdout, " TE = %e\n", tesum*EnergyUnits); - /* Break out if something went wrong */ - if (isnan(dsum) || isnan(zsum) || isnan(psqsum)|| isnan(tesum)){ - fprintf(stdout, "MechStars_depositFeedback [370]: Found a nan: %e %f %e %e\n",dsum, zsum, psqsum, tesum); - ENZO_FAIL("MechStars_depositFeedback NaN in grid field!"); + //Metals transformed back to density in transform routine + + BaryonField[MetalNum][i] += metals[i]; + if (StarMakerTypeIaSNe) + BaryonField[MetalIaNum][i] += metalsIA[i]; + if (StarMakerTypeIISNeMetalField) + BaryonField[MetalIINum][i] += metalsII[i]; + if (PopIIISupernovaUseColour && SNColourNum != -1) + BaryonField[SNColourNum][i] += metalsIII[i]; + if (PopIIISupernovaUseColour && SNColourNum == -1) + BaryonField[MetalNum][i] += metalsIII[i]; + BaryonField[TENum][i] += + totalEnergy[i]/BaryonField[DensNum][i]; + + BaryonField[GENum][i] += + gasEnergy[i]/BaryonField[DensNum][i]; + BaryonField[Vel1Num][i] += u[i]; + BaryonField[Vel2Num][i] += v[i]; + BaryonField[Vel3Num][i] += w[i]; } } - if (criticalDebug){ + + if (criticalDebug && !winds){ for (int i = 0; i< size ; i++){ postMass += BaryonField[DensNum][i]; postZ += BaryonField[MetalNum][i]; + if (MetalIINum > 0) + postZII += BaryonField[MetalIINum][i]; + if (MetalIaNum > 0) + postZIa += BaryonField[MetalIaNum][i]; + if (SNColourNum > 0) postZ += BaryonField[SNColourNum][i]; postP += BaryonField[Vel1Num][i]+BaryonField[Vel2Num][i]+BaryonField[Vel3Num][i]; postPmag += pow(BaryonField[Vel1Num][i]*MomentaUnits,2)+ pow(BaryonField[Vel2Num][i]*MomentaUnits,2) @@ -512,12 +551,14 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, postTE += BaryonField[TENum][i]; postGE += BaryonField[GENum][i]; } - fprintf(stderr, "Difference quantities: dxRatio = %f dMass = %e dZ = %e P = %e |P| = %e TE = %e GE = %e coupledGE = %e Ej = %e\n", + fprintf(stderr, "Difference quantities: dxRatio = %f dMass = %e dZ = %e dzII = %e dxIa = %e P = %e |P| = %e TE = %e GE = %e coupledGE = %e Ej = %e Mej = %e Zej = %e\n", dxRatio, (postMass-preMass)*MassUnits, (postZ-preZ)*MassUnits, + (postZII-preZII)*MassUnits, (postZIa-preZIa)*MassUnits, (postP - preP)*MomentaUnits, (sqrt(postPmag) - sqrt(prePmag)), (postTE-preTE)*EnergyUnits, (postGE-preGE)*EnergyUnits, - coupledGasEnergy*EnergyUnits*nCouple, ejectaEnergy); + coupledGasEnergy*EnergyUnits*nCouple, ejectaEnergy, + ejectaMass, ejectaMetal); if(isnan(postMass) || isnan(postTE) || isnan(postPmag) || isnan(postZ)){ fprintf(stderr, "NAN IN GRID: %e %e %e %e\n", postMass, postTE, postZ, postP); ENZO_FAIL("MechStars_depositFeedback.C: 395\n") @@ -529,6 +570,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* Transform the grid back */ transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], + BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num], BaryonField[Vel3Num],*up, *vp, *wp, GridDimension[0], GridDimension[1], diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 8ec504489..ed9a4ee43 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -45,11 +45,11 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) { - // fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", - // SingleSN, StellarWinds, UnrestrictedSN); - float stretchFactor = 1.4;//1/sqrt(2) to cover cell diagonal + //fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", + //SingleSN, StellarWinds, UnrestrictedSN); + float stretchFactor = 1.0;//1/sqrt(2) to cover cell diagonal /* Get units to use */ - + bool debug = false; int dim, i, j, k, index, size, field, GhostZones = NumberOfGhostZones; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; @@ -186,7 +186,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) int nSNII = 0; int nSNIA = 0; float SNMassEjected = 0, SNMetalEjected = 0; - // printf("Checking particle: %f %e \n", age, ParticleMass[pIndex]*MassUnits); + //fprintf(stdout, "Checking particle: %f %e \n", age, ParticleMass[pIndex]*MassUnits); /* determine how many supernova events */ if (SingleSN) { @@ -199,18 +199,23 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) if (nSNII > 0 || nSNIA > 0){ /* set feedback qtys based on number and types of events */ /* 1e51 erg per sn */ + ParticleAttribute[1][pIndex] += nSNII + nSNIA; float energySN = (nSNII + nSNIA)*1e51; /*10.5 Msun ejecta for type II and IA*/ SNMassEjected = (nSNII+nSNIA)*10.5; /* Metal yeilds from starburst 99 */ - float zZsun = min(BaryonField[MetalNum][index]/BaryonField[DensNum][index]/0.02, 1e-4); - SNMetalEjected = nSNII*(1.91+0.0479*max(zZsun, 1.65)); - SNMetalEjected += nSNIA*(1.4); // this metal should get coupled to SNIA field if its being used + float starMetal = (ParticleAttribute[2][pIndex]/0.02); //determines metal content of SNeII + // if (StarMakerTypeIISNeMetalField) + // starMetal += ParticleAttribute[4][pIndex]/0.02; + /* Couple these in the deposit routine */ + // SNMetalEjected = nSNII*(1.91+0.0479*max(zZsun, 1.65)); + // SNMetalEjected += nSNIA*(1.4); // this metal should get coupled to SNIA field if its being used MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], - ip, jp, kp, size, mu_field, 0); + ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, starMetal, 0); + ParticleAttribute[1][pIndex] += nSNII+nSNIA; } } @@ -219,23 +224,24 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) So almost no energy is coupled, but some mass may be. */ - if (StellarWinds) + if (StellarWinds && age > 0.001) { // printf("Checking Winds\n"); - float zZsun = min(BaryonField[MetalNum][index]/BaryonField[DensNum][index]/0.02, 1e-8); + float zZsun = min(ParticleAttribute[2][pIndex]/0.02, MechStarsCriticalMetallicity); determineWinds(age, &windEnergy, &windMass, &windMetals, ParticleMass[pIndex]*MassUnits, zZsun, TimeUnits, dtFixed); - + if (windMass > 10) fprintf(stdout,"Really High Wind Mass!!\n"); + if (windEnergy > 1e5) MechStars_DepositFeedback(windEnergy, windMass, windMetals, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], - ip, jp, kp, size, mu_field, 1); + ip, jp, kp, size, mu_field, 1, 0, 0, 0.0, 0); } if (windMass > 0.0 || SNMassEjected > 0){ - if (debug) printf("Subtracting off mass %e\n",(windMass+SNMassEjected)); + //if (debug) printf("Subtracting off mass %e\n",(windMass+SNMassEjected)); ParticleMass[pIndex] -= (windMass+SNMassEjected)/MassUnits; } // printf("Post-feedback MP = %e\n", ParticleMass[pIndex]*MassUnits); diff --git a/src/enzo/Grid_MechStarsSeedSupernova.C b/src/enzo/Grid_MechStarsSeedSupernova.C new file mode 100644 index 000000000..97e222951 --- /dev/null +++ b/src/enzo/Grid_MechStarsSeedSupernova.C @@ -0,0 +1,205 @@ +/* + If the region can form stars but has no metals, + We seed the region with a Pop III supernova. + This takes mass from the host cell, converting it + into ejecta mass, energy, and ejecta metals and + deposits it using the MechStars infrastructure. + + 07/2019: Azton Wells + */ +#include +#include +#include +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "fortran.def" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" + + + int GetUnits(float *DensityUnits, float *LengthUnits, + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, float *MassUnits, float Time); +extern "C" void FORTRAN_NAME(cic_deposit)(float* xPosition, float* yPosition, + float* zPosition, int* gridRank, int* nParticles, + float* DepositQuantity, float* FieldToDepositTo, + float* leftEdge, int* xGridDim, int* yGridDim, + int* zGridDim, float* gridDx, float* cloudsize); +int search_lower_bound(float *arr, float value, int low, int high, + int total); +unsigned_long_int mt_random(void); +int StarParticlePopIII_IMFInitialize(void); + +int grid::MechStars_SeedSupernova(){ + debug = true; + /* Initialize the IMF lookup table if requested and not defined */ + if (debug) fprintf(stdout, "setting IMF\n"); + if (PopIIIInitialMassFunction) + StarParticlePopIII_IMFInitialize(); + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + /* Find fields: density, total energy, velocity1-3. */ + int CRNum; + if (debug) printf("IMF Set!\n"); + /* Find Multi-species fields. */ + int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, + DINum, DIINum, HDINum; + + if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) { + fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); + return FAIL; + } + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { + fprintf(stderr, "Error in GetUnits.\n"); + return FAIL; + } + int size = 1; + for (int dim = 0; dim < GridRank; dim++) + size *= GridDimension[dim]; + + /* set feedback to random cell in grid*/ + int ip = rand() % (GridDimension[0]-2*NumberOfGhostZones)+NumberOfGhostZones ; + int jp = rand() % (GridDimension[1]-2*NumberOfGhostZones)+NumberOfGhostZones; + int kp = rand() % (GridDimension[2]-2*NumberOfGhostZones)+NumberOfGhostZones; + float position[3] = {((float)ip+0.5)*CellWidth[0][0]+CellLeftEdge[0][0], + ((float)jp+0.5)*CellWidth[0][0]+CellLeftEdge[1][0], + ((float)kp+0.5)*CellWidth[0][0]+CellLeftEdge[2][0]}; + int index = ip + jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; + /* Get mass of star in exact method used by Star_AssignFinalMassFromIMF.C */ + if (debug) fprintf (stdout, "Setting final mass\n"); + unsigned_long_int random_int = mt_random(); + const int max_random = (1<<16); + float x = (float) (random_int%max_random) / (float) (max_random); + float dm = log10(PopIIIUpperMassCutoff / PopIIILowerMassCutoff) / + (float) (IMF_TABLE_ENTRIES-1); + + /* (binary) search for the mass bin corresponding to the random + number */ + + int width = IMF_TABLE_ENTRIES/2; + int bin_number = IMF_TABLE_ENTRIES/2; + + while (width > 1) { + width /= 2; + if (x > IMFData[bin_number]) + bin_number += width; + else if (x < IMFData[bin_number]) + bin_number -= width; + else + break; + } + + float FinalMass = PopIIILowerMassCutoff * POW(10.0, bin_number * dm); + /* certain mass have no effect since they collapse to black holes */ + if (FinalMass < 10 || (FinalMass >40 && FinalMass < 140) || (FinalMass > 260)){ + printf("Mass Outside Supernova Range!\n"); + return SUCCESS; + } + /* Now, calculate feedback parameters as in Star_CalculateFeedbackParameters.C */ + + // parameters of supernovae // + const float TypeIILowerMass = 11, TypeIIUpperMass = 20.; + const float HNLowerMass = 20.1, HNUpperMass = 40.1; + const float PISNLowerMass = 140, PISNUpperMass = 260; + + // From Nomoto et al. (2006) + const float HypernovaMetals[] = {3.36, 3.53, 5.48, 7.03, 8.59}; // SolarMass + const float HypernovaEnergy[] = {10, 10, 20, 25, 30}; // 1e51 erg + const float CoreCollapseMetals[] = {3.63, 4.41, 6.71, 8.95, 11.19}; // SolarMass + const float CoreCollapseEnergy[] = {1, 1, 1, 1, 1}; // 1e51 erg + + const float SNExplosionMass[] = {19.99, 25, 30, 35, 40.01}; // SolarMass + const float *SNExplosionMetals = (PopIIIUseHypernova ==TRUE) ? + HypernovaMetals : CoreCollapseMetals; + const float *SNExplosionEnergy = (PopIIIUseHypernova ==TRUE) ? + HypernovaEnergy : CoreCollapseEnergy; + float HeCoreMass = 0; + float SNEnergy = 0; + float EjectaMetal = 0; + float EjectaMass = FinalMass; + if (BaryonField[DensNum][index]*DensityUnits*pow(LengthUnits*CellWidth[0][0],3) < 5.0*FinalMass){ + /* Should probably remove from larger area if host cell is too small, + but should only matter at VERY high resolution: M_cell < 50 M_sun*/ + if (debug) fprintf(stdout, "Not enough mass in cell for Seed Supernova: %f < %f", + BaryonField[DensNum][index]*DensityUnits*pow(LengthUnits*CellWidth[0][0],3), FinalMass); + return FAIL; + } + /* Reverse CIC out the star mass */ + int np = 1; float MassRem = -1*EjectaMass; + float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; + float cloudSize = CellWidth[0][0]; + if (debug) fprintf (stdout, "Removing PIII mass from grid\n"); + FORTRAN_NAME(cic_deposit)(&position[0], &position[1], &position[2], + &GridRank,&np,&MassRem, BaryonField[DensNum], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], + &CellWidth[0][0], &cloudSize); + if (debug) fprintf(stdout, "PIII Mass: %f\n", FinalMass); + if (FinalMass > PISNLowerMass && FinalMass < PISNUpperMass){ + HeCoreMass = (13./24.)*(FinalMass-20); + SNEnergy = (5.0+1.304*(HeCoreMass-64))*1e51; + EjectaMetal = HeCoreMass; + } + if (FinalMass > TypeIILowerMass && FinalMass < TypeIIUpperMass){ + SNEnergy = 1e51; + EjectaMetal = 0.1077+0.3383*(FinalMass-11); + } + if (FinalMass > HNLowerMass && FinalMass < HNUpperMass){ + int bin = search_lower_bound((float*)SNExplosionMass, FinalMass, 0, 5, 5); + float frac = (SNExplosionMass[bin+1] - FinalMass) / + (SNExplosionMass[bin+1] - SNExplosionMass[bin]); + SNEnergy = 1e51 * (SNExplosionEnergy[bin] + + frac * (SNExplosionEnergy[bin+1] - SNExplosionEnergy[bin])); + EjectaMetal = (SNExplosionMetals[bin] + + frac * (SNExplosionMetals[bin+1] - SNExplosionMetals[bin])); + } + /* Need mu_field for deposition routine */ + + float mu_field [size]; + for (int k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { + for (int j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { + for (int i = GridStartIndex[0]; i <= GridEndIndex[0]; i++) { + + index = i + j*GridDimension[0] + k*GridDimension[0]*GridDimension[1]; + mu_field[index] = 0.0; + // calculate mu + + if (MultiSpecies == 0) { + mu_field[index] = Mu; + } else { + + if (IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, + HMNum, H2INum, H2IINum, DINum, DIINum, HDINum) == FAIL) { + ENZO_FAIL("Error in grid->IdentifySpeciesFields.\n"); + } + + mu_field[index] = BaryonField[DeNum][index] + BaryonField[HINum][index] + BaryonField[HIINum][index] + + (BaryonField[HeINum][index] + BaryonField[HeIINum][index] + BaryonField[HeIIINum][index])/4.0; + if (MultiSpecies > 1) { + mu_field[index] += BaryonField[HMNum][index] + (BaryonField[H2INum][index] + BaryonField[H2IINum][index])/2.0; + } + if (MultiSpecies > 2) { + mu_field[index] += (BaryonField[DINum][index] + BaryonField[DIINum][index])/2.0 + (BaryonField[HDINum][index]/3.0); + } + + } + } + } + } + /* Add this to the grid using MechStars_DepositFeedback */ + float vp=0, up=0, wp=0; + if (debug) fprintf(stdout, "Calling DepositFeedback!\n"); + this->MechStars_DepositFeedback(SNEnergy, EjectaMass, EjectaMetal, + &up, &vp, &wp, &position[0], &position[1], &position[2], + ip, jp, kp, size, mu_field, 0, 0, 0, 0, 1); + + return SUCCESS; +} \ No newline at end of file diff --git a/src/enzo/Grid_NestedCosmologySimulationInitializeGrid.C b/src/enzo/Grid_NestedCosmologySimulationInitializeGrid.C index 6c727b84b..5e6e1b413 100644 --- a/src/enzo/Grid_NestedCosmologySimulationInitializeGrid.C +++ b/src/enzo/Grid_NestedCosmologySimulationInitializeGrid.C @@ -104,6 +104,7 @@ int grid::NestedCosmologySimulationInitializeGrid( float CosmologySimulationInitialFractionH2II, float CosmologySimulationInitialFractionMetal, float CosmologySimulationInitialFractionMetalIa, + float CosmologySimulationInitialFractionMetalII, int UseMetallicityField, PINT &CurrentParticleNumber, int CosmologySimulationManuallySetParticleMassRatio, @@ -119,7 +120,7 @@ int grid::NestedCosmologySimulationInitializeGrid( int idim, ndim, dim, i, j, vel, OneComponentPerFile, level; int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, - DINum, DIINum, HDINum, MetalNum, MetalIaNum; + DINum, DIINum, HDINum, MetalNum, MetalIaNum, MetalIINum, SNColourNum; int iTE = ietot; int ExtraField[2]; @@ -395,10 +396,14 @@ int grid::NestedCosmologySimulationInitializeGrid( FieldType[MetalNum = NumberOfBaryonFields++] = Metallicity; if (StarMakerTypeIaSNe) FieldType[MetalIaNum = NumberOfBaryonFields++] = MetalSNIaDensity; + if (StarMakerTypeIISNeMetalField) + FieldType[MetalIINum = NumberOfBaryonFields++] = MetalSNIIDensity; if(MultiMetals){ FieldType[ExtraField[0] = NumberOfBaryonFields++] = ExtraType0; FieldType[ExtraField[1] = NumberOfBaryonFields++] = ExtraType1; } + if (MechStarsSeedField) + FieldType[SNColourNum = NumberOfBaryonFields++] = SNColour; } if (WritePotential) FieldType[NumberOfBaryonFields++] = GravPotential; @@ -622,7 +627,13 @@ int grid::NestedCosmologySimulationInitializeGrid( for (i = 0; i < size; i++) BaryonField[MetalIaNum][i] = CosmologySimulationInitialFractionMetalIa * BaryonField[0][i]; - + if (StarMakerTypeIISNeMetalField) + for (i = 0; i < size; i++) + BaryonField[MetalIaNum][i] = CosmologySimulationInitialFractionMetalII + * BaryonField[0][i]; + if (MechStarsSeedField) + for (i = 0; i < size; i++) + BaryonField[SNColourNum][i] = CosmologySimulationInitialFractionMetal*BaryonField[0][i]; if (MultiMetals) { for (i = 0; i < size; i++) { BaryonField[ExtraField[0]][i] = CosmologySimulationInitialFractionMetal diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index dda381d2d..9f2408d16 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -830,7 +830,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, for (i = NumberOfNewParticlesSoFar; i < NumberOfNewParticles; i++) tg->ParticleType[i] = NormalStarType; } - if (STARMAKE_METHOD(MECHANICAL)){ + if (STARMAKE_METHOD(MECHANICAL) && level >= StarMakeLevel){ NumberOfNewParticlesSoFar = NumberOfParticles; int nRetStars = 0; nRetStars = MechStars_Creation(tg, temperature, @@ -1455,7 +1455,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, fprintf(stdout,"Created star: %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f\n", i, tg->ParticleType[i], - tg->ParticleMass[i], + tg->ParticleMass[i]*DensityUnits*pow(LengthUnits*CellWidth[0][0], 3)/2e33, tg->ParticleAttribute[0][i], tg->ParticleAttribute[1][i], tg->ParticleAttribute[2][i], @@ -1600,6 +1600,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, } } } + //fprintf(stdout, "CALLING MECH FEEDBACK\n"); MechStars_FeedbackRoutine(level, &mu_field[0]); } if (STARFEED_METHOD(MOM_STAR)) { diff --git a/src/enzo/InitializeNew.C b/src/enzo/InitializeNew.C index e47f8491d..2b4d773e5 100644 --- a/src/enzo/InitializeNew.C +++ b/src/enzo/InitializeNew.C @@ -309,7 +309,7 @@ int InitializeNew(char *filename, HierarchyEntry &TopGrid, if (StarParticleCreation || StarParticleFeedback) { NumberOfParticleAttributes = 3; if (StarMakerTypeIaSNe) NumberOfParticleAttributes++; - if (StarMakerTypeIISNeMetalField) NumberOfParticleAttributes++; + // if (StarMakerTypeIISNeMetalField) NumberOfParticleAttributes++; } else { NumberOfParticleAttributes = 0; } diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index b6b266729..ca3f3c851 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -29,8 +29,10 @@ int checkCreationCriteria(float* Density, float* Metals, float* CoolingTime, int* GridDim, float* shieldedFraction, float* freeFallTime, float* dynamicalTime, int i, int j, int k, - float Time, float* RefinementField, float CellWidth) + float Time, float* RefinementField, float CellWidth, + bool* gridShouldFormStars, bool* notEnoughMetals) { + float maxZ = 0.0; bool debug = false; bool status = PASS; float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, @@ -112,8 +114,8 @@ int checkCreationCriteria(float* Density, float* Metals, if (Temperature[index] > 1e4) { status = FAIL; //no hot gas forming stars! - float totalDensity = Density[index] - +DMField[index]*DensityUnits; + float totalDensity = (Density[index] + +DMField[index])*DensityUnits; *dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); if (*dynamicalTime/TimeUnits < CoolingTime[index]) status = FAIL; } @@ -140,9 +142,9 @@ int checkCreationCriteria(float* Density, float* Metals, float TauFactor = 434.8 *LengthUnits*LengthUnits / MassUnits; float Tau = TauFactor * Density[index] *(CellWidth+Density[index]/gradRho); - float Phi = 0.756*pow(1+3.1*Metals[index]/0.02, 0.365); + float Phi = 0.756*pow(1+3.1*Metals[index]/Density[index]/0.02, 0.365); - float Psi = 0.6*Tau*(0.01+Metals[index]/0.02)/ + float Psi = 0.6*Tau*(0.01+Metals[index]/Density[index]/0.02)/ log(1+0.6*Phi+0.01*Phi*Phi); *shieldedFraction = 1 - 3/(1+4*Psi); @@ -150,6 +152,16 @@ int checkCreationCriteria(float* Density, float* Metals, *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; //if (status && debug) fprintf(stdout, "passed creation criteria\n"); + if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity) + *notEnoughMetals = false; + if (status && Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity && MechStarsSeedField) + { + status = FAIL; + /* May want to qualify this with H2 fraction/H2 self-shield approximations, but + This is really just to give a non-uniform seed-field in Pop3 metals*/ + *gridShouldFormStars = true; + if (Metals[index]/Density[index]/0.02 > maxZ) maxZ = Metals[index]/Density[index]/0.02; + } return status; } diff --git a/src/enzo/MechStars_determineSN.C b/src/enzo/MechStars_determineSN.C index 07a0729fa..36020b08d 100644 --- a/src/enzo/MechStars_determineSN.C +++ b/src/enzo/MechStars_determineSN.C @@ -91,6 +91,8 @@ int determineSN(float age, int* nSNII, int* nSNIA, if (random < PIA) *nSNIA = psn+1; + if (*nSNIA > 0) + fprintf(stdout, "PIA = %f\n", PIA); } } return SUCCESS; diff --git a/src/enzo/MechStars_determineWinds.C b/src/enzo/MechStars_determineWinds.C index 1ba23dd71..966dc064a 100644 --- a/src/enzo/MechStars_determineWinds.C +++ b/src/enzo/MechStars_determineWinds.C @@ -23,50 +23,45 @@ int determineWinds(float age, float* eWinds, float* mWinds, float* zWinds, float e_factor = 0.0; // I dont want to deal with new particles // printf("Computing Winds for age = %f, Msun = %e\n", age, massMsun); - if (StellarWinds && oldEnough && massMsun > 100){ + if (StellarWinds && oldEnough && massMsun > 11){ - if (0.01 < age < 1.0){ + if (0.001 < age && age < 1.0){ wind_factor =4.763 * min((0.01 + zZsun), 1.0) ; } - if (1 <= age < 3.5){ + if (1 <= age && age < 3.5){ wind_factor = 4.763*min(0.01+zZsun, 1.0)* pow(age, 1.45+0.08*min(log(zZsun), 1.0)); } - if (3.5 <= age <= 100){ + if (3.5 <= age && age < 100){ wind_factor = 29.4*pow(age/3.5, -3.25)+0.0042; } - if (100 < age){ - wind_factor = 0.42*pow(age/1000, -1.1)/(19.81/log(age)); - e_factor = 4.83; - } - if (age <= 100){ + if (age < 100){ float d = powl(1+age/2.5, 1.4); - float a50 = powl(double(age)/50.0, 5.0); + float a50 = powl(double(age)/10.0, 5.0); e_factor = 5.94e4 / d + a50 +4.83; - if (isnan(e_factor)) - printf("efactor nan d = %d a50 = %f age/50 = %f\n", - d, a50, double(age)*1.0/50.0); + + } + if (100 <= age){ + e_factor = 4.83; + wind_factor = 0.42*pow(age/1000, -1.1)/(19.81/log(age)); } windM = massMsun * wind_factor; //Msun/Gyr - windM = windM*dtFixed/TimeUnits/3.1557e16; //Msun/Gyr - //printf("First winds mass = %e\n", windM); + windM = windM*dtFixed*TimeUnits/3.1557e16; //Msun + // if (debug) printf("First winds mass = %e\nFrom wf = %f, dt=%f Z = %e\n", windM, wind_factor, dtFixed, zZsun); //printf("eFactor = %f age = %f\n", e_factor, age); if (windM > massMsun){ printf("Winds too large Mw = %e, Mp = %e age=%f, Z = %e\n", windM, massMsun, age, zZsun); windM = 0.125*massMsun; // limit loss to huge if necessary. } - windZ = 0.0278+ 0.0041* min(max(zZsun, 1.65), 5.0)*windM; - windE = e_factor * 1e12 * windM; // what the actual fuck are the units here??? + windZ = max(zZsun, 0.016+0.0041*max(zZsun, 1.65)+0.0118)*windM; + windE = e_factor * 1e12 * windM; + //fprintf(stdout, "Age = %e Ewinds = %e Mwinds = %e Zwinds = %e Zsun = %e\n", + // age, windE, windM, windZ, zZsun); *mWinds = windM; *zWinds = windZ; *eWinds = windE; - // printf("Winds Mass = %e\n",*mWinds); - // printf("Winds Energy = %e\n", *eWinds); - // printf("wind_factor = %f\n", wind_factor); - // printf("energy_factor = %f\n", e_factor); - // printf("Metallicity = %e\n", zZsun); } return SUCCESS; diff --git a/src/enzo/MechStars_transformComovingWithStar.C b/src/enzo/MechStars_transformComovingWithStar.C index 26343379d..b7414e823 100644 --- a/src/enzo/MechStars_transformComovingWithStar.C +++ b/src/enzo/MechStars_transformComovingWithStar.C @@ -6,10 +6,12 @@ int transformComovingWithStar(float* Density, float* Metals, + float* MetalsSNII, float* MetalsSNIA, float* Vel1, float* Vel2, float* Vel3, float up, float vp, float wp, int sizeX, int sizeY, int sizeZ, int direction){ - /* transform velocities to momenta or back and make them comoving with the star particle */ + /* transform velocities to momenta or back and make them comoving with the star particle + Transform metallicity fields to metal density fields*/ if (direction > 0){ /* To comoving with star */ @@ -23,13 +25,15 @@ int transformComovingWithStar(float* Density, float* Metals, Vel2[ind] = (preV-vp)*Density[ind]; preV = Vel3[ind]; Vel3[ind] = (preV-wp)*Density[ind]; + MetalsSNII[ind] = Metals[ind]*Density[ind]; + MetalsSNIA[ind] = MetalsSNIA[ind]*Density[ind]; } } } } if (direction < 0){ - /* back to "lab" frame */ + /* back to "lab" frame, metal densities back to metallicities */ for (int k = 0; k < sizeZ; k++){ for (int j = 0; j= TotalEnergy && (A) <= Velocity3) || ((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RaySegments) || ((A) >= Bfield1 && (A) <= AccelerationField3)) ? FALSE : TRUE) +#define FieldTypeIsDensity(A) (((A) == MetalSNIaDensity || (A) = MetalSNIIDensity) || ((A) >= TotalEnergy && (A) <= Velocity3) || ((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RaySegments) || ((A) >= Bfield1 && (A) <= AccelerationField3)) ? FALSE : TRUE) #define FieldTypeIsRadiation(A) ((((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RadiationFreq9)) ? TRUE : FALSE) #define FieldTypeNoInterpolate(A) (((((A) >= Mach) && ((A) <= PreShockDensity)) || ((A) == GravPotential) || ((A) == RaySegments)) ? TRUE : FALSE) From d3170310afff58b1d93b7dcc52b3f0a969045031 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 20 Sep 2019 12:37:22 -0700 Subject: [PATCH 012/115] timing prints and fixed typedefs.h --- src/enzo/Grid_MechStarsCreation.C | 12 +++++------ src/enzo/Grid_MechStarsDepositFeedback.C | 16 ++++++--------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 11 +++++++--- src/enzo/Grid_StarParticleHandler.C | 26 ++++++++++++------------ src/enzo/Make.config.objects | 1 + src/enzo/typedefs.h | 2 +- 6 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index 3e0c27f46..b3f913dda 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -42,7 +42,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, if (level < StarMakeLevel) return 0; bool gridShouldFormStars=false, notEnoughMetals = true; float stretchFactor=0.6; - bool debug = true; + bool debug = false; //get field numbers @@ -131,7 +131,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, &gridShouldFormStars, ¬EnoughMetals); - if (createStar) printf ("SMM Criteria passed!\n"); + //f (createStar) printf ("SMM Criteria passed!\n"); if (createStar){ int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; @@ -149,8 +149,8 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, newMass = newMass/MassUnits; if (newMass > 0.9*BaryonField[DensNum][index] || newMass*MassUnits < StarMakerMinimumMass){ - fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e\n", - newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits); + //fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e\n", + // newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits); continue; } float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; @@ -207,7 +207,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] +(dx*(float(k)+0.5)); if (nCreated >= MaximumNumberOfNewParticles) return nCreated; - if (true) + if (debug) fprintf(stdout,"Created star: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", level, nCreated, ParticleArray->ParticleType[nCreated], @@ -230,7 +230,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, if (gridShouldFormStars && notEnoughMetals && MechStarsSeedField){ // set off a p3 supernova at the center of this grid if the // grid can host star formation but has no appreciable metals - if (debug) fprintf(stdout, "\n\n\nCreating seed field!\n\n\n\n"); + fprintf(stdout, "\n\n\nCreating seed field!\n\n\n\n"); MechStars_SeedSupernova(); } diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 0dd88113e..a8dfbaebb 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -44,8 +44,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, and all have radius dx from the source particle. Each vertex particle will then be CIC deposited to the grid! */ - bool debug = true; - bool criticalDebug = true; + bool debug = false; + bool criticalDebug = false; bool printout = debug && !winds; int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; @@ -147,7 +147,9 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, int nCouple = 32; float A = stretchFactor*dx; float cloudSize=stretchFactor*dx; - /* Points from HEALPix algorithm; 48 equally dist. points*/ + + /* each coupled particle is at the vertex of a compound of a dodecahedron and isocahedron */ + FLOAT CloudParticleVectorX [] = //{-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, @@ -318,7 +320,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if(printout) fprintf(stdout, "Rfade = %e cs = %e \n", r_fade, cSound); delete [] temperature; - coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3/2)):(coupledMomenta); + // coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3/2)):(coupledMomenta); float shellMass = 0.0, shellVelocity = 0.0; if(printout) printf("Coupled momentum: %e\n", coupledMomenta); /* If resolution is in a range compared to Rcool and @@ -388,13 +390,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, This implementation is simple since our coupled particles are spherically symmetric about the feedback particle*/ - // coupledEnergy = eKinetic/float(scalarWeight); - // coupledGasEnergy /= float(scalarWeight); - // coupledMass /= float(scalarWeight); - // coupledMetals /= float(scalarWeight); - // coupledMomenta /= float(scalarWeight); - /* Transform coupled quantities to code units */ coupledEnergy = min(eKinetic, ejectaEnergy); coupledEnergy /= EnergyUnits; coupledGasEnergy /= EnergyUnits; diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index ed9a4ee43..676416a83 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -50,6 +50,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) float stretchFactor = 1.0;//1/sqrt(2) to cover cell diagonal /* Get units to use */ bool debug = false; + float startFB = MPI_Wtime(); int dim, i, j, k, index, size, field, GhostZones = NumberOfGhostZones; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; @@ -88,8 +89,8 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) else MetalNum = 0; - int numSN = 0; - + int numSN = 0; // counter of events + int c = 0; // counter of particles /* Begin Iteration of all particles */ // printf("\nIterating all particles "); for (int pIndex=0; pIndex < NumberOfParticles; pIndex++){ @@ -103,7 +104,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) if (ParticleType[pIndex] == PARTICLE_TYPE_STAR && ParticleMass[pIndex] > 0.0 && ParticleAttribute[0][pIndex] > 0.0){ - + c++; // if (StarMakerAgeCutoff) // if ((Time-ParticleAttribute[0][pIndex]) // *TimeUnits/(150*3.1557e7) > 150) @@ -247,6 +248,10 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) // printf("Post-feedback MP = %e\n", ParticleMass[pIndex]*MassUnits); } }// end iteration over particles + if (c > 0){ + fprintf(stdout, "Ptcl Number = %d Events = %d FeedbackTime = %e Size = %d\n", + c, numSN, MPI_Wtime()-startFB, GridDimension[0]*GridDimension[1]*GridDimension[2]); + } return SUCCESS; } diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index 9f2408d16..ec125f309 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -1452,19 +1452,19 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, for (i = 0; i < NumberOfNewParticles; i++){ tg->ParticleNumber[i] = INT_UNDEFINED; - fprintf(stdout,"Created star: %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f\n", - i, - tg->ParticleType[i], - tg->ParticleMass[i]*DensityUnits*pow(LengthUnits*CellWidth[0][0], 3)/2e33, - tg->ParticleAttribute[0][i], - tg->ParticleAttribute[1][i], - tg->ParticleAttribute[2][i], - tg->ParticlePosition[0][i], - tg->ParticlePosition[1][i], - tg->ParticlePosition[2][i], - tg->ParticleVelocity[0][i], - tg->ParticleVelocity[1][i], - tg->ParticleVelocity[2][i]); + // fprintf(stdout,"Created star: %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f\n", + // i, + // tg->ParticleType[i], + // tg->ParticleMass[i]*DensityUnits*pow(LengthUnits*CellWidth[0][0], 3)/2e33, + // tg->ParticleAttribute[0][i], + // tg->ParticleAttribute[1][i], + // tg->ParticleAttribute[2][i], + // tg->ParticlePosition[0][i], + // tg->ParticlePosition[1][i], + // tg->ParticlePosition[2][i], + // tg->ParticleVelocity[0][i], + // tg->ParticleVelocity[1][i], + // tg->ParticleVelocity[2][i]); } /* Move Particles into this grid (set cell size) using the fake grid. */ diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index 7c7221a35..b14852429 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -549,6 +549,7 @@ OBJS_CONFIG_LIB = \ Grid_MechStarsCreation.o\ Grid_MechStarsDepositFeedback.o\ Grid_MechStarsFeedbackRoutine.o\ + Grid_MechStarsSeedSupernova.o\ Grid_MirrorStarParticles.o \ Grid_MoveAllParticles.o \ Grid_MoveAllStars.o \ diff --git a/src/enzo/typedefs.h b/src/enzo/typedefs.h index 4439f73d1..7a2dd9bf4 100644 --- a/src/enzo/typedefs.h +++ b/src/enzo/typedefs.h @@ -192,7 +192,7 @@ enum field_type {Density, TotalEnergy, InternalEnergy, Pressure, FieldUndefined}; */ -#define FieldTypeIsDensity(A) (((A) == MetalSNIaDensity || (A) = MetalSNIIDensity) || ((A) >= TotalEnergy && (A) <= Velocity3) || ((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RaySegments) || ((A) >= Bfield1 && (A) <= AccelerationField3)) ? FALSE : TRUE) +#define FieldTypeIsDensity(A) ((((A) == MetalSNIaDensity || (A) == MetalSNIIDensity) || ((A) >= TotalEnergy && (A) <= Velocity3) || ((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RaySegments) || ((A) >= Bfield1 && (A) <= AccelerationField3)) ? FALSE : TRUE) #define FieldTypeIsRadiation(A) ((((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RadiationFreq9)) ? TRUE : FALSE) #define FieldTypeNoInterpolate(A) (((((A) >= Mach) && ((A) <= PreShockDensity)) || ((A) == GravPotential) || ((A) == RaySegments)) ? TRUE : FALSE) From dc15e5b5d52a754522ef0d1b82f24207c7847bd4 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 23 Sep 2019 08:52:53 -0700 Subject: [PATCH 013/115] Multiple optimization to try and make winds tractable. Theres just so many goddamn stars! --- src/enzo/Grid.h | 6 +- src/enzo/Grid_MechStarsCreation.C | 54 +++--- src/enzo/Grid_MechStarsDepositFeedback.C | 170 +++++++++--------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 126 ++++++++++--- src/enzo/Grid_MechStarsSeedSupernova.C | 10 +- src/enzo/Grid_StarParticleHandler.C | 7 +- src/enzo/MechStars_checkCreationCriteria.C | 27 ++- .../MechStars_transformComovingWithStar.C | 43 +++-- 8 files changed, 276 insertions(+), 167 deletions(-) diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index bf5d99912..6446e1d4b 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2885,15 +2885,17 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int MechStars_Creation(grid* ParticleArray, float* Temperature, float *DMField, int level, float* CoolingTime, int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar); -int MechStars_FeedbackRoutine(int level, float* mu_field); +int MechStars_FeedbackRoutine(int level, float* mu_field, float* temperature, + float* coolingtime, float* dmfield); int MechStars_DepositFeedback(float supernovaEnergy, float ejectaMass, float ejectaMetal, + float* totalMetal, float* up, float* vp, float* wp, float* xp, float* yp, float* zp, int ip, int jp, int kp, int size, float* mu_field, int winds, int nSNII, int nSNIA, float starMetals, int isP3); -int MechStars_SeedSupernova(); +int MechStars_SeedSupernova(float* totalMetal, int* seedIndex); //------------------------------------------------------------------------ // Radiative transfer methods that don't fit in the TRANSFER define diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index b3f913dda..a8d12e7a4 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -27,7 +27,8 @@ float* shieldedFraction, float* freeFallTime, float* dynamicalTime, int i, int j, int k, float Time, float* RefinementField, float CellWidth, - bool* gridShouldFormStars, bool* notEnoughMetals); + bool* gridShouldFormStars, bool* notEnoughMetals, + int continuingFormation, int* seedIndex); int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, float *MassUnits, float Time); @@ -42,7 +43,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, if (level < StarMakeLevel) return 0; bool gridShouldFormStars=false, notEnoughMetals = true; float stretchFactor=0.6; - bool debug = false; + bool debug = true; //get field numbers @@ -78,10 +79,10 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, int size =1; for (int dim = 0; dim < GridRank; dim ++) size *= GridDimension[dim]; - float totalMetal [size]; + float* totalMetal = new float [size]; for (int i = 0; i< size; i++){ totalMetal[i] = BaryonField[MetalNum][i]; - if (SNColourNum > 0) totalMetal[i] += BaryonField[SNColourNum][i]; + if (MechStarsSeedField) totalMetal[i] += BaryonField[SNColourNum][i]; } int rank = GridRank; @@ -98,6 +99,9 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, and physical(Msun) / MassUnits = code */ MassUnits = DensityUnits*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass; + /* Index of last cell that was capable of star formation but has no metals */ + int *seedIndex = new int [3]; + float dx = CellWidth[0][0]; int GZ = int(NumberOfGhostZones); int nCreated = *NumberOfParticlesSoFar; @@ -120,18 +124,17 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float freeFallTime = 0; float dynamicalTime = 0; float Time = this->Time; - int createStar = checkCreationCriteria(BaryonField[DensNum], - &totalMetal[0], Temperature, DMField, + totalMetal, Temperature, DMField, BaryonField[Vel1Num], BaryonField[Vel2Num], BaryonField[Vel3Num], CoolingTime, GridDimension, &shieldedFraction, &freeFallTime, &dynamicalTime, i,j,k,Time, BaryonField[NumberOfBaryonFields], CellWidth[0][0], - &gridShouldFormStars, ¬EnoughMetals); + &gridShouldFormStars, ¬EnoughMetals, 0, seedIndex); - //f (createStar) printf ("SMM Criteria passed!\n"); + //if (createStar && debug) printf ("SMM Criteria passed!\n"); if (createStar){ int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; @@ -144,13 +147,10 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, printf("Negative formation mass: %f %f",shieldedFraction, freeFallTime); continue; } - float newMass = min(MassShouldForm, - StarMakerMaximumFormationMass); - newMass = newMass/MassUnits; - if (newMass > 0.9*BaryonField[DensNum][index] || - newMass*MassUnits < StarMakerMinimumMass){ - //fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e\n", - // newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits); + float newMass = min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]); + if (newMass*MassUnits < StarMakerMinimumMass){ + fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e Mmin = %e\n", + newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits, StarMakerMinimumMass); continue; } float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; @@ -207,9 +207,10 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] +(dx*(float(k)+0.5)); if (nCreated >= MaximumNumberOfNewParticles) return nCreated; - if (debug) - fprintf(stdout,"Created star: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", - level, nCreated, + if (true) + fprintf(stdout,"Created star: %e %e ::: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", + BaryonField[DensNum][index],BaryonField[DensNum][index]*MassUnits, + level, nCreated+1, ParticleArray->ParticleType[nCreated], ParticleArray->ParticleMass[nCreated]*MassUnits, ParticleArray->ParticleAttribute[0][nCreated], @@ -227,16 +228,25 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, }//end for k }//end for j } // end for i - if (gridShouldFormStars && notEnoughMetals && MechStarsSeedField){ - // set off a p3 supernova at the center of this grid if the + /* + If the grid has met star formation criteria, but stars are not formed due to lack of metals, + we set off a P3 SN event at the last grid cell that could have hosted star formation. Can and will set + off multiple events per grid cell if the same cell meets criteria on the next iteration! + */ + if (gridShouldFormStars && MechStarsSeedField && (nCreated == 0)){ + // set off a p3 supernova at at the last cell that could + // host star formation in the grid if the // grid can host star formation but has no appreciable metals - fprintf(stdout, "\n\n\nCreating seed field!\n\n\n\n"); - MechStars_SeedSupernova(); + fprintf(stdout, "\n\n\n[%d] %d %d %d Creating seed field!\n\n\n\n", + ID,seedIndex[0], seedIndex[1], seedIndex[2]) ; + MechStars_SeedSupernova(&totalMetal[0], seedIndex); } //if (nCreated > 0 && debug){ // fprintf(stdout, "Created %d star particles\n",nCreated); // } + delete [] seedIndex; + delete [] totalMetal; *NumberOfParticlesSoFar = nCreated; return nCreated; } diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index a8dfbaebb..99b878914 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -1,6 +1,7 @@ #include #include #include +#include #include "ErrorExceptions.h" #include "macros_and_parameters.h" #include "typedefs.h" @@ -25,13 +26,15 @@ int transformComovingWithStar(float* Density, float* Metals, float* MetalsSNII, float* MetalsSNIA, float* Vel1, float* Vel2, float* Vel3, + float* TE, float* GE, float up, float vp, float wp, int sizeX, int sizeY, int sizeZ, int direction); int FindField(int field, int farray[], int numfields); int grid::MechStars_DepositFeedback(float ejectaEnergy, - float ejectaMass, float ejectaMetal, + float ejectaMass, float ejectaMetal, + float* totalMetals, float* up, float* vp, float* wp, float* xp, float* yp, float* zp, int ip, int jp, int kp, @@ -105,33 +108,38 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* Make copys of fields to work with. These will conatin the added deposition of all quantities and be coupled to the grid after the cic deposition. */ - float totalMetals [size]; - float density [size]; - float metals [size]; - float metalsII [size]; - float metalsIA [size]; - float metalsIII [size]; - float u [size]; - float v [size]; - float w [size]; - float totalEnergy [size]; - float gasEnergy [size]; - for (int i=0; i respective momenta. Use -1 to reverse transform after.*/ /* these temp arrays are implicitly comoving with the star! */ @@ -202,11 +210,14 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, is simply \hat(r_ba) p/12 for r_ba the vector from source to coupled particle. */ - /* transform to comoving with the star and take velocities to momenta */ + /* transform to comoving with the star and take velocities to momenta. + Take Energy densities to energy + */ transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], + BaryonField[TENum], BaryonField[GENum], *up, *vp, *wp, GridDimension[0], GridDimension[1], GridDimension[2], 1); /* Use averaged quantities across multiple cells so that deposition is stable. @@ -384,6 +395,29 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if (printout) fprintf(stdout, "Coupled Metals: %e %e %e %e %e\n", ejectaMetal, SNIAmetals, SNIImetals, shellMetals, P3metals); + + // printf("Entering Critical printout section\n"); + /* transform the grid to comoving with star ; wouldnt recommend this on root grid if its too big...*/ + float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0, preZII=0, preZIa = 0; + float dsum = 0.0, zsum=0.0, psum=0.0, psqsum =0.0, tesum=0.0, gesum=0.0, kesum=0.0; + float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0, postZII=0, postZIa = 0; + if (criticalDebug && !winds){ + for (int i=0; i 0) + preZII += BaryonField[MetalIINum][i]; + if (MetalIaNum > 0) + preZIa += BaryonField[MetalIaNum][i]; + if (SNColourNum > 0) preZ += BaryonField[SNColourNum][i]; + preP += BaryonField[Vel1Num][i]+BaryonField[Vel2Num][i]+BaryonField[Vel3Num][i]; + prePmag += pow(BaryonField[Vel1Num][i]*MomentaUnits,2)+ + pow(BaryonField[Vel2Num][i]*MomentaUnits,2) + +pow(BaryonField[Vel3Num][i]*MomentaUnits,2); + preTE += BaryonField[TENum][i]; + preGE += BaryonField[GENum][i]; + } + } /* Reduce coupled quantities to per-particle quantity and convert to code units. Hopkins has complicated weights due to complicated geometry. @@ -404,7 +438,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; // if (printout) fprintf(stdout, "Entering CIC Loop over cloud particles\n"); - for (int n = 0; n < nCouple; n++){ + for (int n = 0; n < nCouple; ++n){ //fprintf(stdout, "Weight %d = %f", n, weightsVector[n]); FLOAT pX = coupledMomenta*CloudParticleVectorX[n]*weightsVector[n]; FLOAT pY = coupledMomenta*CloudParticleVectorY[n]*weightsVector[n]; @@ -475,61 +509,33 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMetals, &metals[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - // printf("Entering Critical printout section\n"); - /* transform the grid to comoving with star ; wouldnt recommend this on root grid if its too big...*/ - float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0, preZII=0, preZIa = 0; - float dsum = 0.0, zsum=0.0, psum=0.0, psqsum =0.0, tesum=0.0, gesum=0.0, kesum=0.0; - float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0, postZII=0, postZIa = 0; - if (criticalDebug && !winds){ - for (int i=0; i 0) - preZII += BaryonField[MetalIINum][i]; - if (MetalIaNum > 0) - preZIa += BaryonField[MetalIaNum][i]; - if (SNColourNum > 0) preZ += BaryonField[SNColourNum][i]; - preP += BaryonField[Vel1Num][i]+BaryonField[Vel2Num][i]+BaryonField[Vel3Num][i]; - prePmag += pow(BaryonField[Vel1Num][i]*MomentaUnits,2)+ - pow(BaryonField[Vel2Num][i]*MomentaUnits,2) - +pow(BaryonField[Vel3Num][i]*MomentaUnits,2); - preTE += BaryonField[TENum][i]; - preGE += BaryonField[GENum][i]; - } - } + /* Couple the faux deposition grids to to the real grids */ - for (int i = 0; i < size; i++){ + // for (int i = 0; i < size; i++){ - float delta = (BaryonField[DensNum][i]) - /(density[i]+BaryonField[DensNum][i]); - if (delta < 1){ - float deltaZ = BaryonField[MetalNum][i]/(metals[i]+BaryonField[MetalNum][i]); - /* Couple placeholder fields to the grid, account - for grids that got initialized to -0.0*/ - BaryonField[DensNum][i] += density[i]; - - //Metals transformed back to density in transform routine + // BaryonField[DensNum][i] += density[i]; + + // //Metals transformed back to fractional forms in transform routine - BaryonField[MetalNum][i] += metals[i]; - if (StarMakerTypeIaSNe) - BaryonField[MetalIaNum][i] += metalsIA[i]; - if (StarMakerTypeIISNeMetalField) - BaryonField[MetalIINum][i] += metalsII[i]; - if (PopIIISupernovaUseColour && SNColourNum != -1) - BaryonField[SNColourNum][i] += metalsIII[i]; - if (PopIIISupernovaUseColour && SNColourNum == -1) - BaryonField[MetalNum][i] += metalsIII[i]; - BaryonField[TENum][i] += - totalEnergy[i]/BaryonField[DensNum][i]; + // BaryonField[MetalNum][i] += metals[i]; + // if (StarMakerTypeIaSNe) + // BaryonField[MetalIaNum][i] += metalsIA[i]; + // if (StarMakerTypeIISNeMetalField) + // BaryonField[MetalIINum][i] += metalsII[i]; + // if (PopIIISupernovaUseColour && SNColourNum != -1) + // BaryonField[SNColourNum][i] += metalsIII[i]; + // if (PopIIISupernovaUseColour && SNColourNum == -1) + // BaryonField[MetalNum][i] += metalsIII[i]; + // BaryonField[TENum][i] += + // totalEnergy[i]/BaryonField[DensNum][i]; - BaryonField[GENum][i] += - gasEnergy[i]/BaryonField[DensNum][i]; - BaryonField[Vel1Num][i] += u[i]; - BaryonField[Vel2Num][i] += v[i]; - BaryonField[Vel3Num][i] += w[i]; - } - } + // BaryonField[GENum][i] += + // gasEnergy[i]/BaryonField[DensNum][i]; + // BaryonField[Vel1Num][i] += u[i]; + // BaryonField[Vel2Num][i] += v[i]; + // BaryonField[Vel3Num][i] += w[i]; + // } if (criticalDebug && !winds){ for (int i = 0; i< size ; i++){ @@ -568,7 +574,9 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num], - BaryonField[Vel3Num],*up, *vp, *wp, + BaryonField[Vel3Num], + BaryonField[TENum], BaryonField[GENum], + *up, *vp, *wp, GridDimension[0], GridDimension[1], GridDimension[2], -1); diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 676416a83..fbda3eb58 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -26,13 +26,15 @@ float TimeUnits, float dtFixed); int determineWinds(float age, float* eWinds, float* zWinds, float* mWinds, float massMsun, float zZsun, float TimeUnits, float dtFixed); - int checkCreationCriteria(float* Density, float* Metals, +int checkCreationCriteria(float* Density, float* Metals, float* Temperature,float* DMField, - float* Vel1, float* Vel2, float* Vel3, - float* CoolingTime, int GridDim, - float* shieldedFraction, float* freeFallTime, - float* dynamicalTime, int i, int j, int k, - float Time, float* RefinementField, float CellWidth); + float* Vel1, float* Vel2, float* Vel3, + float* CoolingTime, int* GridDim, + float* shieldedFraction, float* freeFallTime, + float* dynamicalTime, int i, int j, int k, + float Time, float* RefinementField, float CellWidth, + bool* gridShouldFormStars, bool* notEnoughMetals, + int continuingFormation, int* seedIndex); int FindField(int field, int farray[], int numfields); int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, @@ -42,14 +44,17 @@ -int grid::MechStars_FeedbackRoutine(int level, float* mu_field) +int grid::MechStars_FeedbackRoutine(int level, float* mu_field, + float* Temperature, float* CoolingTime, float* DMField) { //fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", //SingleSN, StellarWinds, UnrestrictedSN); float stretchFactor = 1.0;//1/sqrt(2) to cover cell diagonal /* Get units to use */ - bool debug = false; + bool SingleWinds = true; // flag to consolidate wind feedback into one event centered on most massive cell in grid + // I wouldn't recommend this for unigrid runs... + bool debug = true; float startFB = MPI_Wtime(); int dim, i, j, k, index, size, field, GhostZones = NumberOfGhostZones; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; @@ -82,15 +87,25 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) get metallicity field and set flag; assumed true thoughout feedback since so many quantities are metallicity dependent */ - int MetallicityField = FALSE, MetalNum; + int MetallicityField = FALSE, MetalNum, SNColourNum=-1; if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) MetallicityField = TRUE; else MetalNum = 0; - + if (MechStarsSeedField) + SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); + float* totalMetal = new float [size]; + for (int i = 0; i < size; i++){ + totalMetal[i] = BaryonField[MetalNum][i]; + if (MechStarsSeedField) + totalMetal[i] += BaryonField[SNColourNum][i]; + } int numSN = 0; // counter of events int c = 0; // counter of particles + float maxD = 0.0; + int maxI=0, maxJ=0, maxK=0; + int maxindex=0; /* Begin Iteration of all particles */ // printf("\nIterating all particles "); for (int pIndex=0; pIndex < NumberOfParticles; pIndex++){ @@ -176,14 +191,65 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; } - /* REMOVED: Check for continual formation, i guess. Only really done because - Hopkins did it. We can just make more stars next timestep I guess. - On the other hand, the function is already written... */ - /* create some stuff. This is a lot of overhead for something - optional... */ + /* Check for continual formation. Continually forming new mass allows the + star particle count to stay lower, ultimately reducing runtime by having + fewer particles to iterate. + */ + index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; + + float shieldedFraction = 0, dynamicalTime = 0, freeFallTime = 0; + bool gridShouldFormStars = true, notEnoughMetals=false; + float zFraction = BaryonField[MetalNum][index]; + if (MechStarsSeedField){ + zFraction += BaryonField[SNColourNum][index]; + } + zFraction /= BaryonField[DensNum][index]; + if (ParticleMass[pIndex]*MassUnits < StarMakerMaximumMass){ + int createStar = checkCreationCriteria(BaryonField[DensNum], + &zFraction, Temperature, DMField, + BaryonField[Vel1Num], BaryonField[Vel2Num], + BaryonField[Vel3Num], + CoolingTime, GridDimension, &shieldedFraction, + &freeFallTime, &dynamicalTime, ip,jp,kp,Time, + BaryonField[NumberOfBaryonFields], CellWidth[0][0], + &gridShouldFormStars, ¬EnoughMetals, 1, NULL); + if(createStar){ + float MassShouldForm =min((shieldedFraction * BaryonField[DensNum][index] + * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13), + 0.5*BaryonField[DensNum][index]*MassUnits); + printf("Adding new mass %e\n",MassShouldForm); + /* Dont allow negative mass, or taking all gas in cell */ + if (MassShouldForm < 0 ) + MassShouldForm = 0; + if (MassShouldForm > 0.1*BaryonField[DensNum][index]*MassUnits) + MassShouldForm = 0.1*BaryonField[DensNum][index]*MassUnits; + + // Set units and modify particle + MassShouldForm /= MassUnits; + if (MassShouldForm > 0){ + float deltaMass = MassShouldForm/MassUnits/(ParticleMass[pIndex]+MassShouldForm/MassUnits); + /* modify metallicity */ + float zFraction = BaryonField[MetalNum][index]; + if (MechStarsSeedField){ + zFraction += BaryonField[SNColourNum][index]; + } + zFraction /= BaryonField[DensNum][index]; + // update mass-weighted metallicity fraction of star particle + ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex]*ParticleMass[pIndex]+zFraction*MassShouldForm)/(ParticleMass[pIndex]+MassShouldForm); + // update mass-weighted age of star particle + if (age > 3.5) // only update if particle is old enough for SNe + ParticleAttribute[0][pIndex] = (ParticleAttribute[0][pIndex]*ParticleMass[pIndex]+Time*MassShouldForm)/(ParticleMass[pIndex]+MassShouldForm); + /* Add new formation mass to particle */ + ParticleMass[pIndex] += MassShouldForm; + printf("added new mass %e + %e = %e newZ = %f newAge = %f\n", + (ParticleMass[pIndex]-MassShouldForm)*MassUnits, MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, + ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); + } + } + } + /* Start actual feedback: Supernova calculations */ - index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; int nSNII = 0; int nSNIA = 0; float SNMassEjected = 0, SNMetalEjected = 0; @@ -212,7 +278,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) /* Couple these in the deposit routine */ // SNMetalEjected = nSNII*(1.91+0.0479*max(zZsun, 1.65)); // SNMetalEjected += nSNIA*(1.4); // this metal should get coupled to SNIA field if its being used - MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, + MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, starMetal, 0); @@ -220,25 +286,29 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) } } - float windEnergy=0, windMass=0, windMetals=0; /* Do the same for winds. Cooling Radius is very small, So almost no energy is coupled, but some mass may be. */ + float windEnergy=0, windMass=0, windMetals=0; - - if (StellarWinds && age > 0.001) + /* + Ignore very old stars, veryvery young stars, and ones whose mass is depleted + */ + if (StellarWinds && age > 0.001 && ParticleMass[pIndex]*MassUnits > 1) { // printf("Checking Winds\n"); float zZsun = min(ParticleAttribute[2][pIndex]/0.02, MechStarsCriticalMetallicity); + determineWinds(age, &windEnergy, &windMass, &windMetals, ParticleMass[pIndex]*MassUnits, zZsun, TimeUnits, dtFixed); if (windMass > 10) fprintf(stdout,"Really High Wind Mass!!\n"); - if (windEnergy > 1e5) - MechStars_DepositFeedback(windEnergy, windMass, windMetals, - &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], - &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], - ip, jp, kp, size, mu_field, 1, 0, 0, 0.0, 0); - + if (windEnergy > 1e5 && SingleWinds){ + printf("Winds: M = %e E=%e\n", windMass, windEnergy); + MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, + &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], + &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], + ip, jp, kp, size, mu_field, 1, 0, 0, 0.0, 0); + } } if (windMass > 0.0 || SNMassEjected > 0){ @@ -252,6 +322,8 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field) fprintf(stdout, "Ptcl Number = %d Events = %d FeedbackTime = %e Size = %d\n", c, numSN, MPI_Wtime()-startFB, GridDimension[0]*GridDimension[1]*GridDimension[2]); } - + /* to avoid iterating deposition over 10k particles, do ONE winds feedback that is summed all wind feedback in the region, + centered on the most massive cell in the grid*/ + delete [] totalMetal; return SUCCESS; } diff --git a/src/enzo/Grid_MechStarsSeedSupernova.C b/src/enzo/Grid_MechStarsSeedSupernova.C index 97e222951..b9c8bef51 100644 --- a/src/enzo/Grid_MechStarsSeedSupernova.C +++ b/src/enzo/Grid_MechStarsSeedSupernova.C @@ -36,7 +36,7 @@ int search_lower_bound(float *arr, float value, int low, int high, unsigned_long_int mt_random(void); int StarParticlePopIII_IMFInitialize(void); -int grid::MechStars_SeedSupernova(){ +int grid::MechStars_SeedSupernova(float* totalMetal, int* seedIndex){ debug = true; /* Initialize the IMF lookup table if requested and not defined */ if (debug) fprintf(stdout, "setting IMF\n"); @@ -67,9 +67,9 @@ int grid::MechStars_SeedSupernova(){ size *= GridDimension[dim]; /* set feedback to random cell in grid*/ - int ip = rand() % (GridDimension[0]-2*NumberOfGhostZones)+NumberOfGhostZones ; - int jp = rand() % (GridDimension[1]-2*NumberOfGhostZones)+NumberOfGhostZones; - int kp = rand() % (GridDimension[2]-2*NumberOfGhostZones)+NumberOfGhostZones; + int ip = seedIndex[0];//rand() % (GridDimension[0]-2*NumberOfGhostZones)+NumberOfGhostZones ; + int jp = seedIndex[1];//rand() % (GridDimension[1]-2*NumberOfGhostZones)+NumberOfGhostZones; + int kp = seedIndex[2];//rand() % (GridDimension[2]-2*NumberOfGhostZones)+NumberOfGhostZones; float position[3] = {((float)ip+0.5)*CellWidth[0][0]+CellLeftEdge[0][0], ((float)jp+0.5)*CellWidth[0][0]+CellLeftEdge[1][0], ((float)kp+0.5)*CellWidth[0][0]+CellLeftEdge[2][0]}; @@ -197,7 +197,7 @@ int grid::MechStars_SeedSupernova(){ /* Add this to the grid using MechStars_DepositFeedback */ float vp=0, up=0, wp=0; if (debug) fprintf(stdout, "Calling DepositFeedback!\n"); - this->MechStars_DepositFeedback(SNEnergy, EjectaMass, EjectaMetal, + this->MechStars_DepositFeedback(SNEnergy, EjectaMass, EjectaMetal, totalMetal, &up, &vp, &wp, &position[0], &position[1], &position[2], ip, jp, kp, size, mu_field, 0, 0, 0, 0, 1); diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index ec125f309..4b23e6b51 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -1600,8 +1600,13 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, } } } + /* Compute the cooling time. */ + + float *cooling_time = new float[size]; + this->ComputeCoolingTime(cooling_time); //fprintf(stdout, "CALLING MECH FEEDBACK\n"); - MechStars_FeedbackRoutine(level, &mu_field[0]); + MechStars_FeedbackRoutine(level, &mu_field[0], temperature,cooling_time, dmfield); + delete [] cooling_time; } if (STARFEED_METHOD(MOM_STAR)) { diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index ca3f3c851..e0a58fa84 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -30,10 +30,11 @@ int checkCreationCriteria(float* Density, float* Metals, float* shieldedFraction, float* freeFallTime, float* dynamicalTime, int i, int j, int k, float Time, float* RefinementField, float CellWidth, - bool* gridShouldFormStars, bool* notEnoughMetals) + bool* gridShouldFormStars, bool* notEnoughMetals, + int continuingFormation, int* seedIndex) { float maxZ = 0.0; - bool debug = false; + bool debug = true; bool status = PASS; float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; @@ -64,8 +65,8 @@ int checkCreationCriteria(float* Density, float* Metals, { status = FAIL; } - //if (debug && status) fprintf(stdout, "Passed Density: %e: %e\n", - // dmean,StarMakerOverDensityThreshold); + // if (debug && status) fprintf(stdout, "Passed Density: %e: %e\n", + // dmean,StarMakerOverDensityThreshold); /* in addition to the converging flow check, we check the virial parameter of the gas to see if it is locally gravitationally bound*/ @@ -106,7 +107,7 @@ int checkCreationCriteria(float* Density, float* Metals, alpha = ((vfactor) + pow(cSound/(CellWidth), 2.0)) / (8.0 * M_PI* Gcode * Density[index]); - // printf("CreationCriteria vf = %e cs = %e Gcode = %e Alpha = %e\n", vfactor, cSound, Gcode, alpha); + if (alpha > 1.0) status = FAIL; /* Is cooling time < dynamical time or temperature < 1e4 */ @@ -151,16 +152,28 @@ int checkCreationCriteria(float* Density, float* Metals, if (*shieldedFraction < 0) status = FAIL; *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; - //if (status && debug) fprintf(stdout, "passed creation criteria\n"); + + if (status && debug && (Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity || !MechStarsSeedField)){ + printf("CreationCriteria f_s = %f vf = %e cs = %e Gcode = %e Alpha = %e Z-sun=%e localRho = %f\n", + *shieldedFraction, vfactor, cSound, Gcode, alpha, Metals[index]/Density[index]/0.02, Density[index]); + return PASS; + } + if (status && debug) fprintf(stdout, "passed creation criteria\n"); if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity) *notEnoughMetals = false; - if (status && Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity && MechStarsSeedField) + if (status && Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity && MechStarsSeedField + && !continuingFormation) { + if (debug) fprintf(stdout,"No metals, criteria passed, but not forming\n"); status = FAIL; /* May want to qualify this with H2 fraction/H2 self-shield approximations, but This is really just to give a non-uniform seed-field in Pop3 metals*/ *gridShouldFormStars = true; if (Metals[index]/Density[index]/0.02 > maxZ) maxZ = Metals[index]/Density[index]/0.02; + /* Store index of this grid to potentially be center of P3 seed later */ + seedIndex[0] = i; + seedIndex[1] = j; + seedIndex[2] = k; } return status; diff --git a/src/enzo/MechStars_transformComovingWithStar.C b/src/enzo/MechStars_transformComovingWithStar.C index b7414e823..97ba0cd45 100644 --- a/src/enzo/MechStars_transformComovingWithStar.C +++ b/src/enzo/MechStars_transformComovingWithStar.C @@ -8,43 +8,42 @@ int transformComovingWithStar(float* Density, float* Metals, float* MetalsSNII, float* MetalsSNIA, float* Vel1, float* Vel2, float* Vel3, + float* TE, float* GE, float up, float vp, float wp, int sizeX, int sizeY, int sizeZ, int direction){ /* transform velocities to momenta or back and make them comoving with the star particle Transform metallicity fields to metal density fields*/ + int size = sizeX*sizeY*sizeZ; if (direction > 0){ /* To comoving with star */ - for (int k = 0; k < sizeZ; k++){ - for (int j = 0; j Date: Mon, 23 Sep 2019 09:17:34 -0700 Subject: [PATCH 014/115] Refinements to continual formation routine in Grid_MechStarsDepositFeedback.C --- src/enzo/Grid_MechStarsFeedbackRoutine.C | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index fbda3eb58..6fa69f681 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -203,7 +203,6 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, if (MechStarsSeedField){ zFraction += BaryonField[SNColourNum][index]; } - zFraction /= BaryonField[DensNum][index]; if (ParticleMass[pIndex]*MassUnits < StarMakerMaximumMass){ int createStar = checkCreationCriteria(BaryonField[DensNum], &zFraction, Temperature, DMField, @@ -221,30 +220,28 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, /* Dont allow negative mass, or taking all gas in cell */ if (MassShouldForm < 0 ) MassShouldForm = 0; - if (MassShouldForm > 0.1*BaryonField[DensNum][index]*MassUnits) - MassShouldForm = 0.1*BaryonField[DensNum][index]*MassUnits; + if (MassShouldForm > 0.5*BaryonField[DensNum][index]*MassUnits) + MassShouldForm = 0.5*BaryonField[DensNum][index]*MassUnits; // Set units and modify particle MassShouldForm /= MassUnits; if (MassShouldForm > 0){ - float deltaMass = MassShouldForm/MassUnits/(ParticleMass[pIndex]+MassShouldForm/MassUnits); + float delta = MassShouldForm/(ParticleMass[pIndex]+MassShouldForm); /* modify metallicity */ - float zFraction = BaryonField[MetalNum][index]; - if (MechStarsSeedField){ - zFraction += BaryonField[SNColourNum][index]; - } zFraction /= BaryonField[DensNum][index]; // update mass-weighted metallicity fraction of star particle - ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex]*ParticleMass[pIndex]+zFraction*MassShouldForm)/(ParticleMass[pIndex]+MassShouldForm); + ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex]*(1.-delta)+zFraction*delta); // update mass-weighted age of star particle if (age > 3.5) // only update if particle is old enough for SNe - ParticleAttribute[0][pIndex] = (ParticleAttribute[0][pIndex]*ParticleMass[pIndex]+Time*MassShouldForm)/(ParticleMass[pIndex]+MassShouldForm); + ParticleAttribute[0][pIndex] = (ParticleAttribute[0][pIndex]*(1.-delta)+Time*delta); /* Add new formation mass to particle */ ParticleMass[pIndex] += MassShouldForm; printf("added new mass %e + %e = %e newZ = %f newAge = %f\n", (ParticleMass[pIndex]-MassShouldForm)*MassUnits, MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, - ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); + ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); + /* Take formed mass out of grid cell */ + BaryonField[DensNum][index] -= MassShouldForm; } } } From a239f47e9c13fb38f7fb236b7f513a4473d41521 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 23 Sep 2019 09:29:03 -0700 Subject: [PATCH 015/115] forgot to account for metals in continual formation! --- src/enzo/Grid_MechStarsFeedbackRoutine.C | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 6fa69f681..a5d78d64e 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -241,7 +241,11 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, (ParticleMass[pIndex]-MassShouldForm)*MassUnits, MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); /* Take formed mass out of grid cell */ - BaryonField[DensNum][index] -= MassShouldForm; + BaryonField[DensNum][index] -= MassShouldForm; + /* Take metals out of host cell too! */ + BaryonField[MetalNum][index] -= BaryonField[MetalNum][index]/BaryonField[DensNum][index]*MassShouldForm; + if (MechStarsSeedField) + BaryonField[SNColourNum][index] -= BaryonField[SNColourNum][index]/BaryonField[DensNum][index]*MassShouldForm; } } } From fffc0c95398c9cd4db6a69ee7fc1559a5338cca2 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 23 Sep 2019 09:31:49 -0700 Subject: [PATCH 016/115] Removed modification of SNII and SNIa fields at particle creation- these are fractions and dont need modification --- src/enzo/Grid_MechStarsCreation.C | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index a8d12e7a4..b2c2341fc 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -168,10 +168,6 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, ParticleArray->ParticleType[nCreated] = PARTICLE_TYPE_STAR; BaryonField[DensNum][index] -= newMass; BaryonField[MetalNum][index] -= newMass*totalMetal[index]/BaryonField[DensNum][index]; - if (MetalIaNum > 0) - BaryonField[MetalIaNum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[MetalIaNum][index]; - if (MetalIINum > 0) - BaryonField[MetalIINum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[MetalIINum][index]; if (SNColourNum > 0) BaryonField[SNColourNum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[SNColourNum][index]/BaryonField[DensNum][index]; From a03b77eee13f3a7f0553c48d91f4a2d262c0c4f1 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 23 Sep 2019 10:28:04 -0700 Subject: [PATCH 017/115] Added timing prints to star creation and accretion printout --- src/enzo/Grid_MechStarsCreation.C | 6 +++--- src/enzo/Grid_MechStarsFeedbackRoutine.C | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index b2c2341fc..5e2998031 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -204,9 +204,9 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, +(dx*(float(k)+0.5)); if (nCreated >= MaximumNumberOfNewParticles) return nCreated; if (true) - fprintf(stdout,"Created star: %e %e ::: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", - BaryonField[DensNum][index],BaryonField[DensNum][index]*MassUnits, - level, nCreated+1, + fprintf(stdout,"Created star: [%f] %e %e ::: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", + Time*TimeUnits/3.1557e13,BaryonField[DensNum][index], + BaryonField[DensNum][index]*MassUnits, level, nCreated+1, ParticleArray->ParticleType[nCreated], ParticleArray->ParticleMass[nCreated]*MassUnits, ParticleArray->ParticleAttribute[0][nCreated], diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index a5d78d64e..71268795e 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -237,8 +237,9 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, ParticleAttribute[0][pIndex] = (ParticleAttribute[0][pIndex]*(1.-delta)+Time*delta); /* Add new formation mass to particle */ ParticleMass[pIndex] += MassShouldForm; - printf("added new mass %e + %e = %e newZ = %f newAge = %f\n", - (ParticleMass[pIndex]-MassShouldForm)*MassUnits, MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, + printf("[%f] added new mass %e + %e = %e newZ = %f newAge = %f\n", + Time*TimeUnits/3.1557e13, (ParticleMass[pIndex]-MassShouldForm)*MassUnits, + MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); /* Take formed mass out of grid cell */ BaryonField[DensNum][index] -= MassShouldForm; @@ -303,7 +304,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, ParticleMass[pIndex]*MassUnits, zZsun, TimeUnits, dtFixed); if (windMass > 10) fprintf(stdout,"Really High Wind Mass!!\n"); - if (windEnergy > 1e5 && SingleWinds){ + if (windEnergy > 1e5){ printf("Winds: M = %e E=%e\n", windMass, windEnergy); MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], From 7cef58a6b4cef225a1814fc1383fae7208ea8565 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 23 Sep 2019 12:27:58 -0700 Subject: [PATCH 018/115] Moved temperature calculation to calling routines and just pass pointers --- src/enzo/Grid.h | 4 ++-- src/enzo/Grid_MechStarsCreation.C | 2 +- src/enzo/Grid_MechStarsDepositFeedback.C | 20 ++++++++++---------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 4 ++-- src/enzo/Grid_MechStarsSeedSupernova.C | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index 6446e1d4b..ba97f90f9 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2889,13 +2889,13 @@ int MechStars_FeedbackRoutine(int level, float* mu_field, float* temperature, float* coolingtime, float* dmfield); int MechStars_DepositFeedback(float supernovaEnergy, float ejectaMass, float ejectaMetal, - float* totalMetal, + float* totalMetal, float* temperature, float* up, float* vp, float* wp, float* xp, float* yp, float* zp, int ip, int jp, int kp, int size, float* mu_field, int winds, int nSNII, int nSNIA, float starMetals, int isP3); -int MechStars_SeedSupernova(float* totalMetal, int* seedIndex); +int MechStars_SeedSupernova(float* totalMetal, float* temperature, int* seedIndex); //------------------------------------------------------------------------ // Radiative transfer methods that don't fit in the TRANSFER define diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index 5e2998031..1337f3cd0 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -235,7 +235,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, // grid can host star formation but has no appreciable metals fprintf(stdout, "\n\n\n[%d] %d %d %d Creating seed field!\n\n\n\n", ID,seedIndex[0], seedIndex[1], seedIndex[2]) ; - MechStars_SeedSupernova(&totalMetal[0], seedIndex); + MechStars_SeedSupernova(&totalMetal[0], Temperature, seedIndex); } //if (nCreated > 0 && debug){ diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 99b878914..dbd996846 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -34,7 +34,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float ejectaMass, float ejectaMetal, - float* totalMetals, + float* totalMetals, float* temperature, float* up, float* vp, float* wp, float* xp, float* yp, float* zp, int ip, int jp, int kp, @@ -321,15 +321,15 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if (printout)fprintf(stdout, "Calculated p = %e\n", coupledMomenta); - /* fading radius of a SNR */ - float *temperature = new float[size]; - this->ComputeTemperatureField(temperature); - float Gcode = GravConst*DensityUnits*pow(TimeUnits,2); - float KBcode = kboltz*MassUnits/(LengthUnits*dx)/pow(TimeUnits,2); - float cSound = sqrt(5/3*kboltz*temperature[index]/mh/muField[index])/1e5; //km/s - float r_fade = 66.0*pow(ejectaEnergy/1e51, 0.32)*pow(nmean, -0.37)*pow(min(cSound/10, .1), -2.0/5.0); - if(printout) fprintf(stdout, "Rfade = %e cs = %e \n", r_fade, cSound); - delete [] temperature; + /* fading radius of a SNR. For real scale invariance, the momentum deposited should go to zero for large dx!*/ + // float *temperature = new float[size]; + // this->ComputeTemperatureField(temperature); + // float Gcode = GravConst*DensityUnits*pow(TimeUnits,2); + // float KBcode = kboltz*MassUnits/(LengthUnits*dx)/pow(TimeUnits,2); + // float cSound = sqrt(5/3*kboltz*temperature[index]/mh/muField[index])/1e5; //km/s + // float r_fade = 66.0*pow(ejectaEnergy/1e51, 0.32)*pow(nmean, -0.37)*pow(min(cSound/10, .1), -2.0/5.0); + // if(printout) fprintf(stdout, "Rfade = %e cs = %e \n", r_fade, cSound); + // delete [] temperature; // coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3/2)):(coupledMomenta); float shellMass = 0.0, shellVelocity = 0.0; diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 71268795e..01eb8f5b2 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -280,7 +280,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, /* Couple these in the deposit routine */ // SNMetalEjected = nSNII*(1.91+0.0479*max(zZsun, 1.65)); // SNMetalEjected += nSNIA*(1.4); // this metal should get coupled to SNIA field if its being used - MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, + MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, Temperature, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, starMetal, 0); @@ -306,7 +306,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, if (windMass > 10) fprintf(stdout,"Really High Wind Mass!!\n"); if (windEnergy > 1e5){ printf("Winds: M = %e E=%e\n", windMass, windEnergy); - MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, + MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, Temperature, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], ip, jp, kp, size, mu_field, 1, 0, 0, 0.0, 0); diff --git a/src/enzo/Grid_MechStarsSeedSupernova.C b/src/enzo/Grid_MechStarsSeedSupernova.C index b9c8bef51..6fb7bc866 100644 --- a/src/enzo/Grid_MechStarsSeedSupernova.C +++ b/src/enzo/Grid_MechStarsSeedSupernova.C @@ -36,7 +36,7 @@ int search_lower_bound(float *arr, float value, int low, int high, unsigned_long_int mt_random(void); int StarParticlePopIII_IMFInitialize(void); -int grid::MechStars_SeedSupernova(float* totalMetal, int* seedIndex){ +int grid::MechStars_SeedSupernova(float* totalMetal, float* temperature, int* seedIndex){ debug = true; /* Initialize the IMF lookup table if requested and not defined */ if (debug) fprintf(stdout, "setting IMF\n"); @@ -197,7 +197,7 @@ int grid::MechStars_SeedSupernova(float* totalMetal, int* seedIndex){ /* Add this to the grid using MechStars_DepositFeedback */ float vp=0, up=0, wp=0; if (debug) fprintf(stdout, "Calling DepositFeedback!\n"); - this->MechStars_DepositFeedback(SNEnergy, EjectaMass, EjectaMetal, totalMetal, + this->MechStars_DepositFeedback(SNEnergy, EjectaMass, EjectaMetal, totalMetal,temperature, &up, &vp, &wp, &position[0], &position[1], &position[2], ip, jp, kp, size, mu_field, 0, 0, 0, 0, 1); From 6acf305ce859c590f96ab5bbd85ed3835097d920 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 23 Sep 2019 13:00:03 -0700 Subject: [PATCH 019/115] Again, moved total metals calculation to calling routines to save time in MechStars routines --- src/enzo/Grid.h | 4 ++-- src/enzo/Grid_MechStarsCreation.C | 14 +++++++------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 24 +++++++++++------------- src/enzo/Grid_StarParticleHandler.C | 4 ++-- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index ba97f90f9..e9308a841 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2883,10 +2883,10 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int MechStars_Creation(grid* ParticleArray, float* Temperature, - float *DMField, int level, float* CoolingTime, + float *DMField, float* totalMetal, int level, float* CoolingTime, int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar); int MechStars_FeedbackRoutine(int level, float* mu_field, float* temperature, - float* coolingtime, float* dmfield); + float* totalMetal, float* coolingtime, float* dmfield); int MechStars_DepositFeedback(float supernovaEnergy, float ejectaMass, float ejectaMetal, float* totalMetal, float* temperature, diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index 1337f3cd0..56458306d 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -37,7 +37,7 @@ /* Creation Routine */ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, - float *DMField, int level, float* CoolingTime, + float *DMField, float* totalMetal, int level, float* CoolingTime, int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar) { if (level < StarMakeLevel) return 0; @@ -79,11 +79,11 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, int size =1; for (int dim = 0; dim < GridRank; dim ++) size *= GridDimension[dim]; - float* totalMetal = new float [size]; - for (int i = 0; i< size; i++){ - totalMetal[i] = BaryonField[MetalNum][i]; - if (MechStarsSeedField) totalMetal[i] += BaryonField[SNColourNum][i]; - } + // float* totalMetal = new float [size]; + // for (int i = 0; i< size; i++){ + // totalMetal[i] = BaryonField[MetalNum][i]; + // if (MechStarsSeedField) totalMetal[i] += BaryonField[SNColourNum][i]; + // } int rank = GridRank; @@ -242,7 +242,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, // fprintf(stdout, "Created %d star particles\n",nCreated); // } delete [] seedIndex; - delete [] totalMetal; + // delete [] totalMetal; *NumberOfParticlesSoFar = nCreated; return nCreated; } diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 01eb8f5b2..ca56144ca 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -44,7 +44,7 @@ int checkCreationCriteria(float* Density, float* Metals, -int grid::MechStars_FeedbackRoutine(int level, float* mu_field, +int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMetal, float* Temperature, float* CoolingTime, float* DMField) { @@ -95,12 +95,12 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, MetalNum = 0; if (MechStarsSeedField) SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); - float* totalMetal = new float [size]; - for (int i = 0; i < size; i++){ - totalMetal[i] = BaryonField[MetalNum][i]; - if (MechStarsSeedField) - totalMetal[i] += BaryonField[SNColourNum][i]; - } + // float* totalMetal = new float [size]; + // for (int i = 0; i < size; i++){ + // totalMetal[i] = BaryonField[MetalNum][i]; + // if (MechStarsSeedField) + // totalMetal[i] += BaryonField[SNColourNum][i]; + // } int numSN = 0; // counter of events int c = 0; // counter of particles float maxD = 0.0; @@ -199,10 +199,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float shieldedFraction = 0, dynamicalTime = 0, freeFallTime = 0; bool gridShouldFormStars = true, notEnoughMetals=false; - float zFraction = BaryonField[MetalNum][index]; - if (MechStarsSeedField){ - zFraction += BaryonField[SNColourNum][index]; - } + float zFraction = totalMetal[index]; if (ParticleMass[pIndex]*MassUnits < StarMakerMaximumMass){ int createStar = checkCreationCriteria(BaryonField[DensNum], &zFraction, Temperature, DMField, @@ -231,7 +228,8 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, /* modify metallicity */ zFraction /= BaryonField[DensNum][index]; // update mass-weighted metallicity fraction of star particle - ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex]*(1.-delta)+zFraction*delta); + ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex]*ParticleMass[pIndex]+zFraction*MassShouldForm)/ + (ParticleMass[pIndex] + MassShouldForm); // update mass-weighted age of star particle if (age > 3.5) // only update if particle is old enough for SNe ParticleAttribute[0][pIndex] = (ParticleAttribute[0][pIndex]*(1.-delta)+Time*delta); @@ -326,6 +324,6 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, } /* to avoid iterating deposition over 10k particles, do ONE winds feedback that is summed all wind feedback in the region, centered on the most massive cell in the grid*/ - delete [] totalMetal; + // delete [] totalMetal; return SUCCESS; } diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index 4b23e6b51..47dedaa03 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -834,7 +834,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, NumberOfNewParticlesSoFar = NumberOfParticles; int nRetStars = 0; nRetStars = MechStars_Creation(tg, temperature, - dmfield, level, cooling_time, MaximumNumberOfNewParticles, + dmfield, TotalMetals, level, cooling_time, MaximumNumberOfNewParticles, &NumberOfNewParticles); //fprintf(stdout, "Created %d new stars!", NumberOfNewParticles); if (nRetStars != NumberOfNewParticles) fprintf(stdout, "star count return and pointer mismatch!\n"); @@ -1605,7 +1605,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, float *cooling_time = new float[size]; this->ComputeCoolingTime(cooling_time); //fprintf(stdout, "CALLING MECH FEEDBACK\n"); - MechStars_FeedbackRoutine(level, &mu_field[0], temperature,cooling_time, dmfield); + MechStars_FeedbackRoutine(level, &mu_field[0], temperature, TotalMetals,cooling_time, dmfield); delete [] cooling_time; } if (STARFEED_METHOD(MOM_STAR)) { From b9d664ae05872d1df1325e87134733c4402f3815 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 26 Sep 2019 16:08:07 -0500 Subject: [PATCH 020/115] missed checks on metal field flags to prevent access when not using SNII, SNIa and PIII metals --- src/enzo/Grid_MechStarsDepositFeedback.C | 74 +++++++++++-------- .../MechStars_transformComovingWithStar.C | 14 ++-- src/enzo/SetDefaultGlobalValues.C | 4 +- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index dbd996846..723d8534b 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -47,10 +47,12 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, and all have radius dx from the source particle. Each vertex particle will then be CIC deposited to the grid! */ + printf("In Feedback deposition\n"); bool debug = false; bool criticalDebug = false; bool printout = debug && !winds; int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; + if (printout) printf("Host index = %d", index); int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; /* Compute size (in floats) of the current grid. */ @@ -80,14 +82,14 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, FLOAT dx = CellWidth[0][0]; if (printout) - fprintf(stdout, "depositing quantities: Energy %e, Mass %e, Metals %e\n", + printf("depositing quantities: Energy %e, Mass %e, Metals %e\n", ejectaEnergy, ejectaMass, ejectaMetal); /* get metallicity field and set flag; assumed true thoughout feedback since so many quantities are metallicity dependent */ - int MetallicityField = FALSE, MetalNum, MetalIaNum, MetalIINum, SNColourNum; + int MetallicityField = FALSE, MetalNum, MetalIaNum=-1, MetalIINum=-1, SNColourNum=-1; if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) MetallicityField = TRUE; @@ -96,16 +98,20 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, ENZO_FAIL("Grid_MechStarsDepositFeedback: 91"); MetalNum = 0; } - MetalIaNum = FindField(MetalSNIaDensity, FieldType, NumberOfBaryonFields); - MetalIINum = FindField(MetalSNIIDensity, FieldType, NumberOfBaryonFields); - SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); - if (PopIIISupernovaUseColour && SNColourNum==-1) ENZO_FAIL("Cant use Seed Field without SNColour field"); + if(StarMakerTypeIaSNe) + MetalIaNum = FindField(MetalSNIaDensity, FieldType, NumberOfBaryonFields); + if (StarMakerTypeIISNeMetalField) + MetalIINum = FindField(MetalSNIIDensity, FieldType, NumberOfBaryonFields); + if (MechStarsSeedField) + SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); + + if (MechStarsSeedField && SNColourNum<0) ENZO_FAIL("Cant use Seed Field without SNColour field"); /* set other units that we need */ MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; //Msun! float EnergyUnits = DensityUnits*pow(LengthUnits*dx, 3) * VelocityUnits*VelocityUnits;//[g cm^2/s^2] -> code_energy float MomentaUnits = MassUnits*VelocityUnits; - + if (printout) printf("Making pointer copies\n"); /* Make copys of fields to work with. These will conatin the added deposition of all quantities and be coupled to the grid after the cic deposition. */ float* density = BaryonField[DensNum]; @@ -151,10 +157,10 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* A DODECAHEDRON+ISOCAHEDRON */ - int nCouple = 32; float A = stretchFactor*dx; float cloudSize=stretchFactor*dx; + if (printout) printf("Making cloud n=%d", nCouple); /* each coupled particle is at the vertex of a compound of a dodecahedron and isocahedron */ @@ -213,7 +219,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* transform to comoving with the star and take velocities to momenta. Take Energy densities to energy */ - + if (printout) printf("Calling transform\n"); transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], @@ -224,6 +230,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, vmean is used to determine whether the supernova shell calculation should proceed: M_shell > 0 iff v_shell > v_gas */ float zmean=0, dmean=0, nmean=0, vmean; + if (printout) fprintf(stdout, "Generating local mean information\n"); for (int ind = -1; ind <= 1; ind++){ zmean += totalMetals[index+ind]*BaryonField[DensNum][index+ind]; zmean += totalMetals[index+GridDimension[0]*ind]*BaryonField[DensNum][index+GridDimension[0]*ind]; @@ -334,20 +341,18 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, // coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3/2)):(coupledMomenta); float shellMass = 0.0, shellVelocity = 0.0; if(printout) printf("Coupled momentum: %e\n", coupledMomenta); - /* If resolution is in a range compared to Rcool and + /* + If resolution is in a range comparable to Rcool and Analytic SNR shell mass is on, adjust the shell mass - Shell mass calculation is limited by considering the local gas - velocity */ + upper range of applicability for shell mass is determined by + local average gas velocity (v_shell ~ v_gas = no shell) + */ if (cellwidth > r_shellform && coupledEnergy > 0 && AnalyticSNRShellMass){ shellVelocity = 413.0 *pow(nmean, 1.0/7.0) *pow(zZsun, 3.0/14.0)*pow(coupledEnergy/EnergyUnits/1e51, 1.0/14.0) *pow(dxRatio, -7.0/3.0);//km/s - /* Underdense regions can have large coupled momenta with - low velocity (due to large r_cool), leading to shell mass instability. - The shell velocity is compared to gas velocity, and - can only contribute to the mass if the shell velocity is - higher than the gas velocity.*/ + if (shellVelocity > vmean){ shellMass = max(8e3, coupledMomenta/shellVelocity); //Msun @@ -369,7 +374,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if (shellMass < 0.0){ fprintf(stdout, "Shell mass = %e Velocity= %e P = %e", shellMass, shellVelocity, coupledMomenta); - ENZO_FAIL("SM_deposit: 252");} + ENZO_FAIL("SM_deposit: 252"); + } float coupledMass = shellMass+ejectaMass; eKinetic = coupledMomenta*coupledMomenta /(2.0*dmean*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass)*SolarMass*1e10; @@ -389,15 +395,21 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float coupledMetals = 0.0, SNIAmetals = 0.0, SNIImetals = 0.0, P3metals = 0.0; if (winds) coupledMetals = ejectaMetal ;//+ shellMetals; // winds only couple to metallicity SNIAmetals = (StarMakerTypeIaSNe) ? nSNIA * 1.4 : 0.0; + if (!StarMakerTypeIaSNe && nSNIA > 0) + coupledMetals += nSNIA*1.4; SNIImetals = (StarMakerTypeIISNeMetalField)? nSNII*(1.91+0.0479*max(starMetal, 1.65)) : 0.0; - if (isP3) P3metals = ejectaMetal; + if (!StarMakerTypeIISNeMetalField && nSNII > 0) + coupledMetals += nSNII*(1.91+0.0479*max(starMetal, 1.65)); + if (isP3 && MechStarsSeedField) P3metals = ejectaMetal; if (printout) fprintf(stdout, "Coupled Metals: %e %e %e %e %e\n", ejectaMetal, SNIAmetals, SNIImetals, shellMetals, P3metals); - // printf("Entering Critical printout section\n"); - /* transform the grid to comoving with star ; wouldnt recommend this on root grid if its too big...*/ + /* + Critical debug compares the pre-feedback and post-feedback field sums. Note that this doesn't + work well on vector quantities outside of an ideal test. + */ float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0, preZII=0, preZIa = 0; float dsum = 0.0, zsum=0.0, psum=0.0, psqsum =0.0, tesum=0.0, gesum=0.0, kesum=0.0; float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0, postZII=0, postZIa = 0; @@ -405,11 +417,12 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, for (int i=0; i 0) + if (StarMakerTypeIISNeMetalField) preZII += BaryonField[MetalIINum][i]; - if (MetalIaNum > 0) + if (StarMakerTypeIaSNe) preZIa += BaryonField[MetalIaNum][i]; - if (SNColourNum > 0) preZ += BaryonField[SNColourNum][i]; + if (MechStarsSeedField) + preZ += BaryonField[SNColourNum][i]; preP += BaryonField[Vel1Num][i]+BaryonField[Vel2Num][i]+BaryonField[Vel3Num][i]; prePmag += pow(BaryonField[Vel1Num][i]*MomentaUnits,2)+ pow(BaryonField[Vel2Num][i]*MomentaUnits,2) @@ -437,7 +450,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* CIC deposit the particles with their respective quantities */ float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; - // if (printout) fprintf(stdout, "Entering CIC Loop over cloud particles\n"); + if (printout) fprintf(stdout, "Entering CIC Loop over cloud particles\n"); + for (int n = 0; n < nCouple; ++n){ //fprintf(stdout, "Weight %d = %f", n, weightsVector[n]); FLOAT pX = coupledMomenta*CloudParticleVectorX[n]*weightsVector[n]; @@ -456,8 +470,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, &CloudParticlePositionZ[n], &GridRank, &np,&mCouple, &density[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - // if (!winds) - zCouple += zIICouple + zIACouple; + if (StarMakerTypeIaSNe && StarMakerTypeIISNeMetalField) + zCouple += zIICouple + zIACouple; // printf("Zcpl = %e", zCouple); FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank, &np,&zCouple, &metals[0], LeftEdge, @@ -484,15 +498,15 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&geCouple, &gasEnergy[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (zIICouple > 0.0) + if (StarMakerTypeIISNeMetalField && zIICouple > 0.0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&zIICouple, &metalsII[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (zIACouple > 0.0) + if (StarMakerTypeIaSNe && zIACouple > 0.0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&zIACouple, &metalsIA[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (p3Couple > 0.0){ + if (MechStarsSeedField && p3Couple > 0.0){ if (printout)printf("Coupling %f to pIII metals %d\n",p3Couple*MassUnits, n); FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&p3Couple, &metalsIII[0], LeftEdge, diff --git a/src/enzo/MechStars_transformComovingWithStar.C b/src/enzo/MechStars_transformComovingWithStar.C index 97ba0cd45..1d86a66da 100644 --- a/src/enzo/MechStars_transformComovingWithStar.C +++ b/src/enzo/MechStars_transformComovingWithStar.C @@ -3,7 +3,7 @@ #include #include "macros_and_parameters.h" #include "typedefs.h" - +#include "StarParticleData.h" int transformComovingWithStar(float* Density, float* Metals, float* MetalsSNII, float* MetalsSNIA, @@ -27,8 +27,10 @@ int transformComovingWithStar(float* Density, float* Metals, Vel2[ind] = (preV-vp)*mult; preV = Vel3[ind]; Vel3[ind] = (preV-wp)*mult; - MetalsSNIA[ind] = MetalsSNIA[ind]*mult; - MetalsSNII[ind] = Metals[ind]*mult; + if(StarMakerTypeIaSNe) + MetalsSNIA[ind] = MetalsSNIA[ind]*mult; + if(StarMakerTypeIISNeMetalField) + MetalsSNII[ind] = Metals[ind]*mult; } } @@ -42,8 +44,10 @@ int transformComovingWithStar(float* Density, float* Metals, Vel1[ind] = Vel1[ind]*mult+up; Vel2[ind] = Vel2[ind]*mult+vp; Vel3[ind] = Vel3[ind]*mult+wp; - MetalsSNIA[ind] = MetalsSNIA[ind]*mult; - MetalsSNII[ind] = Metals[ind]*mult; + if(StarMakerTypeIaSNe) + MetalsSNIA[ind] = MetalsSNIA[ind]*mult; + if(StarMakerTypeIISNeMetalField) + MetalsSNII[ind] = Metals[ind]*mult; } } return SUCCESS; diff --git a/src/enzo/SetDefaultGlobalValues.C b/src/enzo/SetDefaultGlobalValues.C index 7120bb986..8c26c5fc7 100644 --- a/src/enzo/SetDefaultGlobalValues.C +++ b/src/enzo/SetDefaultGlobalValues.C @@ -682,10 +682,10 @@ int SetDefaultGlobalValues(TopGridData &MetaData) SingleSN = 1; StarMakerMaximumFormationMass = 1e4; StarMakerMaximumMass = 1e5; - DepositUnresolvedEnergyAsThermal = 1; + DepositUnresolvedEnergyAsThermal = 0; StarMakeLevel = MaximumRefinementLevel; NEvents = 0; - AnalyticSNRShellMass = 1; + AnalyticSNRShellMass = 0; UnrestrictedSN = 0; // false by default MechStarsCriticalMetallicity = 1e-12; // dont check for metals in formation MechStarsSeedField = 0; // dont seed metals from pop3 imf From 619f7cc66d415ca647e1963c2ab4ae9b4bafed59 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 30 Sep 2019 14:50:28 -0500 Subject: [PATCH 021/115] general debugging, implemented maximum velocity for created star particles. --- src/enzo/Grid_MechStarsCreation.C | 12 ++++++------ src/enzo/Grid_MechStarsDepositFeedback.C | 2 +- src/enzo/Grid_MechStarsFeedbackRoutine.C | 18 +++++++++++------- src/enzo/MechStars_checkCreationCriteria.C | 8 ++++---- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index 56458306d..20029633f 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -149,8 +149,8 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, } float newMass = min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]); if (newMass*MassUnits < StarMakerMinimumMass){ - fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e Mmin = %e\n", - newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits, StarMakerMinimumMass); + //fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e Mmin = %e\n", + // newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits, StarMakerMinimumMass); continue; } float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; @@ -189,10 +189,10 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, vY += BaryonField[Vel2Num][ind]; vZ += BaryonField[Vel3Num][ind]; } - - ParticleArray->ParticleVelocity[0][nCreated] = vX/125.0; - ParticleArray->ParticleVelocity[1][nCreated] = vY/125.0; - ParticleArray->ParticleVelocity[2][nCreated] = vZ/125.0; + float MaxVelocity = 250.*1.0e5/VelocityUnits; + ParticleArray->ParticleVelocity[0][nCreated] = (abs(vX/125.) > MaxVelocity)?(MaxVelocity*((vX > 0)?(1):(-1))):(vX/125.); + ParticleArray->ParticleVelocity[1][nCreated] = (abs(vY/125.) > MaxVelocity)?(MaxVelocity*((vY > 0)?(1):(-1))):(vY/125.); + ParticleArray->ParticleVelocity[2][nCreated] = (abs(vZ/125.) > MaxVelocity)?(MaxVelocity*((vZ > 0)?(1):(-1))):(vZ/125.);; /* give it position at center of host cell */ diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 723d8534b..72e1238af 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -47,7 +47,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, and all have radius dx from the source particle. Each vertex particle will then be CIC deposited to the grid! */ - printf("In Feedback deposition\n"); + //printf("In Feedback deposition\n"); bool debug = false; bool criticalDebug = false; bool printout = debug && !winds; diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index ca56144ca..d36614725 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -152,9 +152,13 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta || yp < CellLeftEdge[1][0] || zp > CellLeftEdge[2][0]+gridDz || zp < CellLeftEdge[2][0]){ - fprintf(stderr, "Particle %d out of grid!\nage: %d, pos: %f, %f, %f GridEdge: %f %f %f", pIndex, - age, xp, yp, zp, CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0] - ); + fprintf(stderr, "Particle %d with type %d out of grid! Mass: %e\nage: %d, pos: %f, %f, %f Vel: %f %f %f\nGridEdge: %f %f %f\nGridEdge: %f %f %f\n", pIndex, + ParticleType[pIndex], age, ParticleMass[pIndex]*MassUnits, + xp, yp, zp, CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0], + ParticleVelocity[0][pIndex], ParticleVelocity[1][pIndex], ParticleVelocity[2][pIndex], + CellLeftEdge[0][0]*GridDimension[0]*CellWidth[0][0], + CellLeftEdge[1][0]*GridDimension[1]*CellWidth[0][0], + CellLeftEdge[2][0]*GridDimension[2]*CellWidth[0][0]); EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); } int shifted = 0; @@ -187,9 +191,9 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta if (debug) fprintf(stderr, "Particle position shifted away from edge: %e: %f %f %f\n%f %f %f\n", age,xp, yp, zp, CellLeftEdge[0][0]+borderDx, CellLeftEdge[1][0]+borderDx, CellLeftEdge[2][0]+borderDx); - int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; - int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; - int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; + int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; + int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; + int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; } /* Check for continual formation. Continually forming new mass allows the star particle count to stay lower, ultimately reducing runtime by having @@ -303,7 +307,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta TimeUnits, dtFixed); if (windMass > 10) fprintf(stdout,"Really High Wind Mass!!\n"); if (windEnergy > 1e5){ - printf("Winds: M = %e E=%e\n", windMass, windEnergy); + //printf("Winds: M = %e E=%e\n", windMass, windEnergy); MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, Temperature, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index e0a58fa84..a5dabb925 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -154,17 +154,17 @@ int checkCreationCriteria(float* Density, float* Metals, *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; if (status && debug && (Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity || !MechStarsSeedField)){ - printf("CreationCriteria f_s = %f vf = %e cs = %e Gcode = %e Alpha = %e Z-sun=%e localRho = %f\n", - *shieldedFraction, vfactor, cSound, Gcode, alpha, Metals[index]/Density[index]/0.02, Density[index]); + //printf("CreationCriteria f_s = %f vf = %e cs = %e Gcode = %e Alpha = %e Z-sun=%e localRho = %f\n", + // *shieldedFraction, vfactor, cSound, Gcode, alpha, Metals[index]/Density[index]/0.02, Density[index]); return PASS; } - if (status && debug) fprintf(stdout, "passed creation criteria\n"); + //if (status && debug) fprintf(stdout, "passed creation criteria\n"); if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity) *notEnoughMetals = false; if (status && Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity && MechStarsSeedField && !continuingFormation) { - if (debug) fprintf(stdout,"No metals, criteria passed, but not forming\n"); + // if (debug) fprintf(stdout,"No metals, criteria passed, but not forming\n"); status = FAIL; /* May want to qualify this with H2 fraction/H2 self-shield approximations, but This is really just to give a non-uniform seed-field in Pop3 metals*/ From fd8d8b1a04add2225bc2efef6912d1a4bacf4497 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Tue, 1 Oct 2019 10:07:14 -0700 Subject: [PATCH 022/115] first commit to incorporate rad hydro with mechanical star maker --- src/enzo/Grid_MechStarsDepositFeedback.C | 39 +++------ src/enzo/Grid_MechStarsFeedbackRoutine.C | 47 ++++++----- src/enzo/MechStars_depositEmissivityField.C | 90 +++++++++++++++++++++ src/enzo/SetDefaultGlobalValues.C | 1 + src/enzo/StarParticleData.h | 1 + 5 files changed, 128 insertions(+), 50 deletions(-) create mode 100644 src/enzo/MechStars_depositEmissivityField.C diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 72e1238af..3372cd9fd 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -124,28 +124,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float* w = BaryonField[Vel3Num]; float* totalEnergy = BaryonField[TENum]; float* gasEnergy = BaryonField[GENum]; - // memset(density, 0, size*sizeof(float)); - // memset(metals, 0, size*sizeof(float)); - // memset(metalsII, 0, size*sizeof(float)); - // memset(metalsIA, 0, size*sizeof(float)); - // memset(metalsIII, 0, size*sizeof(float)); - // memset(u, 0, size*sizeof(float)); - // memset(v, 0, size*sizeof(float)); - // memset(w, 0, size*sizeof(float)); - // memset(totalEnergy, 0, size*sizeof(float)); - // memset(gasEnergy, 0, size*sizeof(float)); - // for (int i=0; i respective momenta. Use -1 to reverse transform after.*/ /* these temp arrays are implicitly comoving with the star! */ @@ -236,9 +215,6 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, zmean += totalMetals[index+GridDimension[0]*ind]*BaryonField[DensNum][index+GridDimension[0]*ind]; zmean += totalMetals[index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; - // if (printout) fprintf(stdout, "MuField = %f %f %f\nmax = %d ; %d %d %d\n", - // muField[index+ind], muField[index+GridDimension[0]*ind], muField[index+ind*GridDimension[0]*GridDimension[1]], GridDimension[0]*GridDimension[1]*GridDimension[2], - // index+ind, index+GridDimension[0]*ind, index+ind*GridDimension[0]*GridDimension[1]); nmean += BaryonField[DensNum][index+ind]*BaryonField[DensNum][index+ind]*DensityUnits/mh/max(0.6,muField[index+ind]); nmean += BaryonField[DensNum][index+GridDimension[0]*ind]* BaryonField[DensNum][index+GridDimension[0]*ind]*DensityUnits/mh/max(muField[index+GridDimension[0]*ind],0.6); @@ -272,33 +248,40 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float fz = (zZsun < 0.01)? (2.0): (pow(zZsun, -0.14)); /* Cooling radius as in Hopkins, but as an average over cells */ + float CoolingRadius = 28.4 * pow(max(0.001,nmean), -3.0/7.0) *pow(ejectaEnergy/1.0e51, 2.0/7.0)* fz; if (printout)fprintf(stdout, "cooling radius [pc] = %e\n %f %e %f %e %e \n", CoolingRadius, nmean, ejectaEnergy/1e51, fz, zmean, dmean); - /* Calculate coupled energy scaled by reduction to account for unresolved - cooling, then use that energy to calculate momenta*/ + float coupledEnergy = ejectaEnergy; if (printout)fprintf(stdout, "Dx [pc] = %f\n", dx*LengthUnits/pc_cm); + float dxRatio = stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius; if (winds) dxRatio = min(stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius, 20); float pEjectMod = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5)/SolarMass/1e5; + /* We want to couple one of four phases: free expansion, Sedov-taylor, shell formation, or terminal The first three phases are take forms from Kim & Ostriker 2015, the last from Cioffi 1988*/ + float cellwidth = stretchFactor*dx*LengthUnits/pc_cm; + + // if we resolve free expansion, all energy is thermally coupled + float p_free = 0.0;//sqrt(ejectaMass*SolarMass*ejectaEnergy)/SolarMass/1e5;//1.73e4*sqrt(ejectaMass*ejectaEnergy/1e51/3.); // free exp. momentum eq 15 float r_free = 2.75*pow(ejectaMass/3/nmean, 1./3.); // free exp radius eq 2 // assuming r_sedov == dx, solve for t3 + float t3_sedov = pow( cellwidth*pc_cm /(5.0*pc_cm*pow(ejectaEnergy/1e51/nmean, 1.0/5.0)), 5./2.); float p_sedov = 2.21e4*pow(ejectaEnergy/1e51, 4./5.) * pow(nmean, 1./5.)* pow(t3_sedov, 3./5.); // eq 16 - // shell formation radius eq 8 + // shell formation radius eq 8 float r_shellform = 22.6*pow(ejectaEnergy/1e51, 0.29)*pow(nmean, -0.42); // p_sf = m_sf*v_sf eq 9,11 float p_shellform = 3.1e5*pow(ejectaEnergy/1e51, 0.94)*pow(nmean, -0.13) ; // p_sf = m_sf*v_sf eq 9,11 diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index d36614725..3c46c62dd 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -26,7 +26,7 @@ float TimeUnits, float dtFixed); int determineWinds(float age, float* eWinds, float* zWinds, float* mWinds, float massMsun, float zZsun, float TimeUnits, float dtFixed); -int checkCreationCriteria(float* Density, float* Metals, + int checkCreationCriteria(float* Density, float* Metals, float* Temperature,float* DMField, float* Vel1, float* Vel2, float* Vel3, float* CoolingTime, int* GridDim, @@ -39,7 +39,8 @@ int checkCreationCriteria(float* Density, float* Metals, int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, float *MassUnits, FLOAT Time); - + int MechStars_depositEmissivityField(int index, float cellwidth, + float* emissivity0, float age, float mass); @@ -50,10 +51,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta //fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", //SingleSN, StellarWinds, UnrestrictedSN); - float stretchFactor = 1.0;//1/sqrt(2) to cover cell diagonal - /* Get units to use */ - bool SingleWinds = true; // flag to consolidate wind feedback into one event centered on most massive cell in grid - // I wouldn't recommend this for unigrid runs... + float stretchFactor = 1.0;// radius from star particle to feedback cloud particle (in units of dx) bool debug = true; float startFB = MPI_Wtime(); int dim, i, j, k, index, size, field, GhostZones = NumberOfGhostZones; @@ -95,12 +93,19 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta MetalNum = 0; if (MechStarsSeedField) SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); - // float* totalMetal = new float [size]; - // for (int i = 0; i < size; i++){ - // totalMetal[i] = BaryonField[MetalNum][i]; - // if (MechStarsSeedField) - // totalMetal[i] += BaryonField[SNColourNum][i]; - // } + + /* Find and set emissivity field if being used */ + int EmisNum = -1; + if (StarMakerEmissivityField){ + EmisNum = FindField(Emissivity0, FieldType, NumberOfBaryonFields); + } + if (EmisNum > 0) + { + /* Zero the emissivity first, as we dont want to to accumulate */ + for (int i = 0; i < size; ++i) + BaryonField[EmisNum][i] = 0.0; + } + int numSN = 0; // counter of events int c = 0; // counter of particles float maxD = 0.0; @@ -109,21 +114,11 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta /* Begin Iteration of all particles */ // printf("\nIterating all particles "); for (int pIndex=0; pIndex < NumberOfParticles; pIndex++){ - // if (ParticleType[pIndex] != 1 && debug) - // fprintf(stdout,"PARTICLE: %d %d %e %f\n", ParticleType[pIndex], - // ParticleNumber[pIndex], - // ParticleMass[pIndex], - // ParticleAttribute[0][pIndex]); - /* Selection criteria */ if (ParticleType[pIndex] == PARTICLE_TYPE_STAR && ParticleMass[pIndex] > 0.0 && ParticleAttribute[0][pIndex] > 0.0){ c++; - // if (StarMakerAgeCutoff) - // if ((Time-ParticleAttribute[0][pIndex]) - // *TimeUnits/(150*3.1557e7) > 150) - // continue; /* get index of cell hosting particle */ float xp = ParticlePosition[0][pIndex]; @@ -243,9 +238,13 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta Time*TimeUnits/3.1557e13, (ParticleMass[pIndex]-MassShouldForm)*MassUnits, MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); + /* Take formed mass out of grid cell */ + BaryonField[DensNum][index] -= MassShouldForm; + /* Take metals out of host cell too! */ + BaryonField[MetalNum][index] -= BaryonField[MetalNum][index]/BaryonField[DensNum][index]*MassShouldForm; if (MechStarsSeedField) BaryonField[SNColourNum][index] -= BaryonField[SNColourNum][index]/BaryonField[DensNum][index]*MassShouldForm; @@ -319,6 +318,10 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta //if (debug) printf("Subtracting off mass %e\n",(windMass+SNMassEjected)); ParticleMass[pIndex] -= (windMass+SNMassEjected)/MassUnits; } + if (StarMakerEmissivityField){ + MechStars_depositEmissivityField(index, CellWidth[0][0], BaryonField[EmisNum], + age, ParticleMass[pIndex]*MassUnits); + } // printf("Post-feedback MP = %e\n", ParticleMass[pIndex]*MassUnits); } }// end iteration over particles diff --git a/src/enzo/MechStars_depositEmissivityField.C b/src/enzo/MechStars_depositEmissivityField.C new file mode 100644 index 000000000..8aec66362 --- /dev/null +++ b/src/enzo/MechStars_depositEmissivityField.C @@ -0,0 +1,90 @@ +/* + Couples the mechanical stars to the radiation machinery in ENZO by filling + in the emissivity0 field. + Code must be compiled with "make emissivity-yes" and "make photon-yes". + Usage at runtime determined by the StarMakerUseEmissivity flag. + Unlike the CIC depositions in the rest of this module, the emissivity is set + solely for the cell hosting the star particle (or its kicked location). + + The radiation deposited here is time varying depending on the age of the particle (and mass). + A better implementation will make the individual bands of radiation time dependent + (more UV early, more IR late). + */ +#include +#include +#include +#include +#include "ErrorExceptions.h" +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "fortran.def" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" +//#include "gFLDProblem.h" + + +int MechStars_depositEmissivityField(int index, float cellwidth, + float* emissivity0, float age, float mass) +{ + // Modeling after fFLDSplit_RadiationSource.F90 to fill in Emissivity0 field. + // etaconst = h_nu0*NGammaDot*specconst/dV + // specconst ~ scaling factor for spectrum -> varies depeding on user choice of tracked radiation + // dV ~ proper volume of cell + // NGammaDot ~ photons per second. -> this will vary depending on age of particle! + const float LsunToErg = 3.85e33; // erg/s + const float evPerErg = 6.2415e11; + const float h_nu0 = 13.6/evPerErg; // erg + /* + Calculate rates of photons given the age-based luminosity in Hopkins 2017. Units are + L_sun/M_sun. While they are given, we dont bother with IR/optical bands here. + We only couple the ionizing radiation, Psi_ion. The others are calculated if they happen + to be used in the future. + */ + float Psi_fuv = 0.0, Psi_ion = 0.0; + if (age < 3.4){ + Psi_fuv = 271. * (1.0 + (age/3.4)*(age/3.4)); + } + if (age < 3.5){ + Psi_ion = 500; + } + if (age > 3.5 && age < 25){ + Psi_ion = 60.*pow(age/3.5, -3.6)+470*pow(age/3.5, 0.045-1.82*log(age)); + } + if (age > 3.4){ + Psi_fuv = 572.*pow(age/3.4, -1.5); + } + // convert to better units + Psi_ion *= mass; // L_sun + Psi_ion *= LsunToErg; // erg/s + /* + assuming all those photons are in the HI ionization range, the number + of photons is + */ + float NGammaDot = Psi_ion / h_nu0; + + + /* + Select spectrum scaling based on parameters + (probably just HI radiation for now) + This routine only works with HI radiation for now, as the + rest of the rates would require another Starburst99 sim to get + */ + if (MechStarsRadiationSpectrum != -1){ + ENZO_FAIL("MechStars only implemented for RadHydroESpectrum = -1\n"); + } + const float specconst = 1.0; + + /* + Apply selected to Emissivity0 in the form of etaconst. + */ + emissivity0[index] += pow(cellwidth, 3.0)*specconst*NGammaDot*h_nu0; + + return SUCCESS; +} + diff --git a/src/enzo/SetDefaultGlobalValues.C b/src/enzo/SetDefaultGlobalValues.C index 8c26c5fc7..b565fae86 100644 --- a/src/enzo/SetDefaultGlobalValues.C +++ b/src/enzo/SetDefaultGlobalValues.C @@ -689,6 +689,7 @@ int SetDefaultGlobalValues(TopGridData &MetaData) UnrestrictedSN = 0; // false by default MechStarsCriticalMetallicity = 1e-12; // dont check for metals in formation MechStarsSeedField = 0; // dont seed metals from pop3 imf + MechStarsRadiationSpectrum = 0; // no field by default! PythonTopGridSkip = 0; PythonSubcycleSkip = 1; PythonReloadScript = FALSE; diff --git a/src/enzo/StarParticleData.h b/src/enzo/StarParticleData.h index ddb18dcea..f561d7c1f 100644 --- a/src/enzo/StarParticleData.h +++ b/src/enzo/StarParticleData.h @@ -162,5 +162,6 @@ SPEXTERN int AnalyticSNRShellMass; SPEXTERN int UnrestrictedSN; SPEXTERN int MechStarsSeedField; SPEXTERN float MechStarsCriticalMetallicity; +SPEXTERN int MechStarsRadiationSpectrum; #endif From e8ec9f907ec9906eae91b3ec5d7aaf93e178d5e7 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 10 Oct 2019 12:54:22 -0700 Subject: [PATCH 023/115] coupled mechanical stars to the ray-tracing solver --- src/enzo/FLDCorrectForImpulses.C | 2 +- src/enzo/Grid_AddH2DissociationFromSources.C | 2 +- src/enzo/Grid_CreateEmissivityLW.C | 2 +- src/enzo/Grid_FindAllStarParticles.C | 9 +- src/enzo/Grid_MechStarsCreation.C | 5 +- src/enzo/Grid_MechStarsDepositFeedback.C | 209 ++++++++---------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 62 +++--- src/enzo/Grid_MechStarsSeedSupernova.C | 18 +- src/enzo/Grid_StarParticleHandler.C | 68 +++--- .../Grid_TestStarParticleInitializeGrid.C | 8 + src/enzo/MechStars_calcPhotonRates.C | 68 ++++++ src/enzo/MechStars_checkCreationCriteria.C | 6 +- src/enzo/MechStars_depositEmissivity.C | 90 ++++++++ src/enzo/MechStars_depositEmissivityField.C | 47 ++-- src/enzo/MechStars_determineSN.C | 1 + .../MechStars_transformComovingWithStar.C | 20 +- src/enzo/RadiativeTransferPrepare.C | 4 +- src/enzo/ReadParameterFile.C | 1 + src/enzo/RestartPhotons.C | 4 +- src/enzo/Star.h | 2 +- src/enzo/StarParticleAddFeedback.C | 2 +- src/enzo/StarParticleRadTransfer.C | 5 +- src/enzo/Star_Accrete.C | 3 +- src/enzo/Star_ComputePhotonRates.C | 13 +- src/enzo/Star_IsARadiationSource.C | 5 +- src/enzo/Star_SetFeedbackFlag.C | 5 + src/enzo/WriteParameterFile.C | 2 + src/enzo/gFLDSplit_Initialize.C | 16 +- src/enzo/typedefs.h | 2 +- 29 files changed, 434 insertions(+), 247 deletions(-) create mode 100644 src/enzo/MechStars_calcPhotonRates.C create mode 100644 src/enzo/MechStars_depositEmissivity.C diff --git a/src/enzo/FLDCorrectForImpulses.C b/src/enzo/FLDCorrectForImpulses.C index 4c6e71d3e..4ad0c1716 100644 --- a/src/enzo/FLDCorrectForImpulses.C +++ b/src/enzo/FLDCorrectForImpulses.C @@ -99,7 +99,7 @@ int FLDCorrectForImpulses(int field, LevelHierarchyEntry *LevelArray[], continue; Lifetime = cstar->ReturnLifetime(); Position = cstar->ReturnPosition(); - cstar->ComputePhotonRates(TimeUnits, nbins, energies, LL); + cstar->ComputePhotonRates(TimeUnits, TimeNow, nbins, energies, LL, 0.0); Luminosity = LL[3]; TimeFraction = (min(BirthTime + Lifetime, FLDTime) - max(BirthTime, FLDTime-dtFLD)) / dtFLD; diff --git a/src/enzo/Grid_AddH2DissociationFromSources.C b/src/enzo/Grid_AddH2DissociationFromSources.C index 7566be159..3b60daad0 100644 --- a/src/enzo/Grid_AddH2DissociationFromSources.C +++ b/src/enzo/Grid_AddH2DissociationFromSources.C @@ -259,7 +259,7 @@ int grid::AddH2DissociationFromSources(Star *AllStars) /* Determine H2 emission rate */ - if (cstar->ComputePhotonRates(TimeUnits, nbins, energies, Luminosity) == FAIL) { + if (cstar->ComputePhotonRates(TimeUnits, Time, nbins, energies, Luminosity,0.0) == FAIL) { ENZO_FAIL("Error in ComputePhotonRates.\n"); } LWLuminosity = Luminosity[3]; diff --git a/src/enzo/Grid_CreateEmissivityLW.C b/src/enzo/Grid_CreateEmissivityLW.C index a8ef2dcce..bcbf52326 100644 --- a/src/enzo/Grid_CreateEmissivityLW.C +++ b/src/enzo/Grid_CreateEmissivityLW.C @@ -85,7 +85,7 @@ int grid::CreateEmissivityLW(Star *AllStars, FLOAT TimeFLD, float dtFLD) else TimeFraction = 1.0; - cstar->ComputePhotonRates(TimeUnits, nbins, energies, Luminosity); + cstar->ComputePhotonRates(TimeUnits, Time, nbins, energies, Luminosity,0.0); E_LW = energies[3]; L_LW = Luminosity[3]; diff --git a/src/enzo/Grid_FindAllStarParticles.C b/src/enzo/Grid_FindAllStarParticles.C index c2ffa2512..fed78df3a 100644 --- a/src/enzo/Grid_FindAllStarParticles.C +++ b/src/enzo/Grid_FindAllStarParticles.C @@ -62,7 +62,9 @@ int grid::FindAllStarParticles(int level) LifetimeFactor = 12.0; else LifetimeFactor = 1.0; - + if (StarParticleFeedback == MECHANICAL){ + LifetimeFactor = huge_number; // mech stars dont die! + } if (this->Time >= ParticleAttribute[0][i] && this->Time <= ParticleAttribute[0][i] + LifetimeFactor * ParticleAttribute[1][i]) { @@ -89,7 +91,10 @@ int grid::FindAllStarParticles(int level) NewStar = new Star(this, i, level); InsertStarAfter(Stars, NewStar); NumberOfStars++; - + if (StarParticleFeedback == MECHANICAL){ + NewStar->SetFeedbackFlag(15); + NewStar->LifeTime = huge_number; // Mechanical stars never "die", they can reaccrete or just deposit wind + } /* For MBHFeedback = 2 to 5 (FeedbackFlag=MBH_JETS), you need the angular momentum; if no file to read in, assume zero angular momentum accreted so far. -Ji-hoon Kim, Nov.2009 */ diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index 20029633f..e190cfe93 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -157,7 +157,10 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); // fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); ParticleArray->ParticleMass[nCreated] = newMass; - ParticleArray->ParticleAttribute[1][nCreated] = 0.0; // Tracking SNE in TDP field dynamicalTime/TimeUnits; + if (StarParticleRadiativeFeedback) + ParticleArray->ParticleAttribute[1][nCreated] = huge_number; // need infinite lifetime for radiative feedback i think? + else + ParticleArray->ParticleAttribute[1][nCreated] = 0.0; // Tracking SNE in TDP field dynamicalTime/TimeUnits; ParticleArray->ParticleAttribute[0][nCreated] = Time; ParticleArray->ParticleAttribute[2][nCreated] = totalMetal[index] diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 3372cd9fd..458a91dcd 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -48,11 +48,11 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, Each vertex particle will then be CIC deposited to the grid! */ //printf("In Feedback deposition\n"); - bool debug = false; - bool criticalDebug = false; + bool debug = true; + bool criticalDebug = true; bool printout = debug && !winds; int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; - if (printout) printf("Host index = %d", index); + if (printout) printf("Host index = %d\n", index); int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; /* Compute size (in floats) of the current grid. */ @@ -89,7 +89,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, get metallicity field and set flag; assumed true thoughout feedback since so many quantities are metallicity dependent */ - int MetallicityField = FALSE, MetalNum, MetalIaNum=-1, MetalIINum=-1, SNColourNum=-1; + int MetallicityField = FALSE, MetalNum=-1, MetalIaNum=-1, MetalIINum=-1, SNColourNum=-1; if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) MetallicityField = TRUE; @@ -111,24 +111,25 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float EnergyUnits = DensityUnits*pow(LengthUnits*dx, 3) * VelocityUnits*VelocityUnits;//[g cm^2/s^2] -> code_energy float MomentaUnits = MassUnits*VelocityUnits; - if (printout) printf("Making pointer copies\n"); - /* Make copys of fields to work with. These will conatin the added deposition - of all quantities and be coupled to the grid after the cic deposition. */ + + /* Make copys of pointers fields to work with (theyre just easier to type!). */ float* density = BaryonField[DensNum]; float* metals = BaryonField[MetalNum]; - float* metalsII = BaryonField[MetalIINum]; - float* metalsIA = BaryonField[MetalIaNum]; - float* metalsIII =BaryonField[SNColourNum]; + float* metalsII=NULL; + float* metalsIA=NULL; + float* metalsIII = NULL; + if (StarMakerTypeIISNeMetalField) + metalsII = BaryonField[MetalIINum]; + if (StarMakerTypeIaSNe) + metalsIA = BaryonField[MetalIaNum]; + if (MechStarsSeedField) + metalsIII = BaryonField[SNColourNum]; float* u = BaryonField[Vel1Num]; float* v = BaryonField[Vel2Num]; float* w = BaryonField[Vel3Num]; float* totalEnergy = BaryonField[TENum]; float* gasEnergy = BaryonField[GENum]; - /* Transform coordinates so that metals is fraction (rho metal/rho baryon) - u, v, w -> respective momenta. Use -1 to reverse transform after.*/ - /* these temp arrays are implicitly comoving with the star! */ - /* Array of coordinates of the isocahedron vertices scaled by r=dx */ float phi = (1.0+sqrt(5))/2.0; //Golden Ratio float iphi = 1.0/phi; // inverse GR @@ -136,25 +137,25 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* A DODECAHEDRON+ISOCAHEDRON */ - int nCouple = 32; + int nCouple = 26; float A = stretchFactor*dx; float cloudSize=stretchFactor*dx; if (printout) printf("Making cloud n=%d", nCouple); /* each coupled particle is at the vertex of a compound of a dodecahedron and isocahedron */ - FLOAT CloudParticleVectorX [] = //{-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, - iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, - 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; - FLOAT CloudParticleVectorY [] = //{1,1,1,0,0,-1,-1,-1,0,1,1,1,0,0,-1,-1,-1,1,1,1,0,0,-1,-1,-1,0}; - {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, - phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, - phi, -phi, -phi, phi, 0, 0, 0, 0}; - FLOAT CloudParticleVectorZ [] = //{1,0,-1,1,-1,1,0,-1,0,1,0,-1,1,-1,1,0,-1,1,0,-1,1,-1,1,0,-1,0}; - {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, - 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, - phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; + FLOAT CloudParticleVectorX [] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + // {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, + // iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, + // 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; + FLOAT CloudParticleVectorY [] = {1,1,1,0,0,-1,-1,-1,0,1,1,1,0,0,-1,-1,-1,1,1,1,0,0,-1,-1,-1,0}; + // {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, + // phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, + // phi, -phi, -phi, phi, 0, 0, 0, 0}; + FLOAT CloudParticleVectorZ [] = {1,0,-1,1,-1,1,0,-1,0,1,0,-1,1,-1,1,0,-1,1,0,-1,1,-1,1,0,-1,0}; + // {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, + // 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, + // phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; float weightsVector [nCouple]; /* Set position of feedback cloud particles */ @@ -188,17 +189,13 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, weightsSum += weightsVector[wind]; } for (int wind = 0; wind < nCouple; wind++){ - weightsVector[wind] /= weightsSum; + weightsVector[wind] = weightsSum; } - /* Each particle gets 1/32 of energy, momenta, mass, and metal. There - are no varying vector / scalar weights to worry about. The momenta coupled - is simply \hat(r_ba) p/12 for r_ba the vector from source to coupled - particle. */ + /* transform to comoving with the star and take velocities to momenta. Take Energy densities to energy */ - if (printout) printf("Calling transform\n"); transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], @@ -208,49 +205,65 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* Use averaged quantities across multiple cells so that deposition is stable. vmean is used to determine whether the supernova shell calculation should proceed: M_shell > 0 iff v_shell > v_gas */ - float zmean=0, dmean=0, nmean=0, vmean; - if (printout) fprintf(stdout, "Generating local mean information\n"); + float zmean=0, dmean=0, nmean=0, vmean=0, mu_mean = 0; for (int ind = -1; ind <= 1; ind++){ - zmean += totalMetals[index+ind]*BaryonField[DensNum][index+ind]; - zmean += totalMetals[index+GridDimension[0]*ind]*BaryonField[DensNum][index+GridDimension[0]*ind]; - zmean += totalMetals[index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + zmean += totalMetals[index+ind]/BaryonField[DensNum][index+ind]; + zmean += totalMetals[index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind]; + zmean += totalMetals[index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + + nmean += BaryonField[DensNum][index+ind]*DensityUnits; + nmean += BaryonField[DensNum][index+GridDimension[0]*ind]*DensityUnits; + nmean += BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]*DensityUnits; - nmean += BaryonField[DensNum][index+ind]*BaryonField[DensNum][index+ind]*DensityUnits/mh/max(0.6,muField[index+ind]); - nmean += BaryonField[DensNum][index+GridDimension[0]*ind]* - BaryonField[DensNum][index+GridDimension[0]*ind]*DensityUnits/mh/max(muField[index+GridDimension[0]*ind],0.6); - nmean += BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind] - *BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]*DensityUnits/mh/max(0.6,muField[index+ind*GridDimension[0]*GridDimension[1]]); + mu_mean += muField[index+ind]; + mu_mean += muField[index+GridDimension[0]*ind]; + mu_mean += muField[index+GridDimension[0]*GridDimension[1]*ind]; dmean += BaryonField[DensNum][index+ind]; dmean += BaryonField[DensNum][index+GridDimension[0]*ind]; dmean += BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; - vmean += BaryonField[Vel1Num][index+ind]*BaryonField[Vel1Num][index+ind]*VelocityUnits*VelocityUnits; - vmean += BaryonField[Vel1Num][index+GridDimension[0]*ind]*BaryonField[Vel1Num][index+GridDimension[0]*ind]*VelocityUnits*VelocityUnits; - vmean += BaryonField[Vel1Num][index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[Vel1Num][index+GridDimension[0]*GridDimension[1]*ind]*VelocityUnits*VelocityUnits; - - vmean += BaryonField[Vel2Num][index+ind]*BaryonField[Vel2Num][index+ind]*VelocityUnits*VelocityUnits; - vmean += BaryonField[Vel2Num][index+GridDimension[0]*ind]*BaryonField[Vel2Num][index+GridDimension[0]*ind]*VelocityUnits*VelocityUnits; - vmean += BaryonField[Vel2Num][index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[Vel2Num][index+GridDimension[0]*GridDimension[1]*ind]*VelocityUnits*VelocityUnits; - - vmean += BaryonField[Vel3Num][index+ind]*BaryonField[Vel3Num][index+ind]*VelocityUnits*VelocityUnits; - vmean += BaryonField[Vel3Num][index+GridDimension[0]*ind]*BaryonField[Vel3Num][index+GridDimension[0]*ind]*VelocityUnits*VelocityUnits; - vmean += BaryonField[Vel3Num][index+GridDimension[0]*GridDimension[1]*ind]*BaryonField[Vel3Num][index+GridDimension[0]*GridDimension[1]*ind]*VelocityUnits*VelocityUnits; + vmean += BaryonField[Vel1Num][index+ind]/BaryonField[DensNum][index+ind] + *BaryonField[Vel1Num][index+ind]/BaryonField[DensNum][index+ind]; + vmean += BaryonField[Vel1Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind] + *BaryonField[Vel1Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind]; + vmean += BaryonField[Vel1Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind] + *BaryonField[Vel1Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + + vmean += BaryonField[Vel2Num][index+ind]/BaryonField[DensNum][index+ind] + *BaryonField[Vel2Num][index+ind]/BaryonField[DensNum][index+ind]; + vmean += BaryonField[Vel2Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind] + *BaryonField[Vel2Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind]; + vmean += BaryonField[Vel2Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind] + *BaryonField[Vel2Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + + vmean += BaryonField[Vel3Num][index+ind]/BaryonField[DensNum][index+ind] + *BaryonField[Vel3Num][index+ind]/BaryonField[DensNum][index+ind]; + vmean += BaryonField[Vel3Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind] + *BaryonField[Vel3Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind]; + vmean += BaryonField[Vel3Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind] + *BaryonField[Vel3Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; } - vmean = sqrt(vmean/dmean/dmean); - zmean /= (dmean*0.02); - nmean /= (dmean); - - dmean = dmean*DensityUnits/9.0; - nmean = max(nmean, 1e-3); + vmean = sqrt(vmean)/27.0*VelocityUnits; // cm/s! + zmean /= (27.0); + mu_mean/= (dmean); + // if (abs(mu_mean) > 10){ + // mu_mean = 0.6; + // } + nmean /= (mu_mean*mh); + dmean = dmean*DensityUnits/(27.); + nmean = dmean/mh*mu_mean; + //nmean = max(nmean, 1e-1); + //if (debug) printf ("Zmean = %e Dmean = %e mu_mean = %e ", zmean, dmean, mu_mean); + //if (debug) printf ("Nmean = %f vmean = %f\n", nmean, vmean/1e5); float zZsun = max(zmean, 1e-8); float fz = (zZsun < 0.01)? (2.0): (pow(zZsun, -0.14)); /* Cooling radius as in Hopkins, but as an average over cells */ float CoolingRadius = 28.4 * - pow(max(0.001,nmean), -3.0/7.0) + pow(max(0.1,nmean), -3.0/7.0) *pow(ejectaEnergy/1.0e51, 2.0/7.0)* fz; if (printout)fprintf(stdout, "cooling radius [pc] = %e\n %f %e %f %e %e \n", CoolingRadius, nmean, ejectaEnergy/1e51, fz, zmean, dmean); @@ -260,7 +273,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if (printout)fprintf(stdout, "Dx [pc] = %f\n", dx*LengthUnits/pc_cm); float dxRatio = stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius; - if (winds) dxRatio = min(stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius, 20); + if (winds) dxRatio = min(stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius, 50); float pEjectMod = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5)/SolarMass/1e5; /* We want to couple one of four phases: free expansion, Sedov-taylor, shell formation, or terminal @@ -336,7 +349,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, *pow(zZsun, 3.0/14.0)*pow(coupledEnergy/EnergyUnits/1e51, 1.0/14.0) *pow(dxRatio, -7.0/3.0);//km/s - if (shellVelocity > vmean){ + if (shellVelocity > vmean/1e5){ shellMass = max(8e3, coupledMomenta/shellVelocity); //Msun /* cant let host cells evacuate completely! @@ -369,7 +382,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float coupledGasEnergy = max(ejectaEnergy-eKinetic, 0); if (printout)fprintf(stdout, "Coupled Gas Energy = %e\n",coupledGasEnergy); - if (dxRatio > 2.0) + if (dxRatio > 1.0) coupledGasEnergy = (DepositUnresolvedEnergyAsThermal) ?(coupledGasEnergy) :(coupledGasEnergy*pow(dxRatio, -6.5)); @@ -378,16 +391,16 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float coupledMetals = 0.0, SNIAmetals = 0.0, SNIImetals = 0.0, P3metals = 0.0; if (winds) coupledMetals = ejectaMetal ;//+ shellMetals; // winds only couple to metallicity SNIAmetals = (StarMakerTypeIaSNe) ? nSNIA * 1.4 : 0.0; - if (!StarMakerTypeIaSNe && nSNIA > 0) + if (!StarMakerTypeIaSNe) coupledMetals += nSNIA*1.4; SNIImetals = (StarMakerTypeIISNeMetalField)? nSNII*(1.91+0.0479*max(starMetal, 1.65)) : 0.0; - if (!StarMakerTypeIISNeMetalField && nSNII > 0) + if (!StarMakerTypeIISNeMetalField) coupledMetals += nSNII*(1.91+0.0479*max(starMetal, 1.65)); if (isP3 && MechStarsSeedField) P3metals = ejectaMetal; - if (printout) fprintf(stdout, "Coupled Metals: %e %e %e %e %e\n", ejectaMetal, SNIAmetals, SNIImetals, shellMetals, P3metals); + if (printout) fprintf(stdout, "Coupled Metals: %e %e %e %e %e %e\n", ejectaMetal, SNIAmetals, SNIImetals, shellMetals, P3metals, coupledMetals); /* Critical debug compares the pre-feedback and post-feedback field sums. Note that this doesn't @@ -421,9 +434,9 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, spherically symmetric about the feedback particle*/ - coupledEnergy = min(eKinetic, ejectaEnergy); - coupledEnergy /= EnergyUnits; - coupledGasEnergy /= EnergyUnits; + coupledEnergy = eKinetic; + coupledEnergy = coupledEnergy/EnergyUnits; + coupledGasEnergy = coupledGasEnergy/EnergyUnits; coupledMass /= MassUnits; coupledMetals /= MassUnits; coupledMomenta /= MomentaUnits; @@ -434,7 +447,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; if (printout) fprintf(stdout, "Entering CIC Loop over cloud particles\n"); - + //printf("Zcouple = "); for (int n = 0; n < nCouple; ++n){ //fprintf(stdout, "Weight %d = %f", n, weightsVector[n]); FLOAT pX = coupledMomenta*CloudParticleVectorX[n]*weightsVector[n]; @@ -453,9 +466,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, &CloudParticlePositionZ[n], &GridRank, &np,&mCouple, &density[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (StarMakerTypeIaSNe && StarMakerTypeIISNeMetalField) - zCouple += zIICouple + zIACouple; - // printf("Zcpl = %e", zCouple); + //printf("%e ", zCouple*MassUnits); FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank, &np,&zCouple, &metals[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); @@ -472,30 +483,33 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], &CloudParticlePositionZ[n], &GridRank,&np,&pZ, &w[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (coupledEnergy > 0 && DualEnergyFormalism && geCouple > 0) - eCouple += geCouple; + if (eCouple > 0 && DualEnergyFormalism ){ + if (geCouple > 0) + eCouple += geCouple; FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&eCouple, &totalEnergy[0], LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&eCouple, BaryonField[TENum], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + } if (geCouple > 0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&geCouple, &gasEnergy[0], LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&geCouple, BaryonField[GENum], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (StarMakerTypeIISNeMetalField && zIICouple > 0.0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&zIICouple, &metalsII[0], LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&zIICouple, metalsII, LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (StarMakerTypeIaSNe && zIACouple > 0.0) FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&zIACouple, &metalsIA[0], LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&zIACouple, metalsIA, LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (MechStarsSeedField && p3Couple > 0.0){ - if (printout)printf("Coupling %f to pIII metals %d\n",p3Couple*MassUnits, n); + //if (printout)printf("Coupling %f to pIII metals %d\n",p3Couple*MassUnits, n); FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&p3Couple, &metalsIII[0], LeftEdge, + &CloudParticlePositionZ[n], &GridRank,&np,&p3Couple, metalsIII, LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); } } + // printf("\n"); /* Deposit one negative mass particle centered on star to account for shell mass leaving host cells . Same for metals that were evacuated*/ int np = 1; @@ -507,33 +521,6 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - - /* Couple the faux deposition grids to to the real grids */ - // for (int i = 0; i < size; i++){ - - // BaryonField[DensNum][i] += density[i]; - - // //Metals transformed back to fractional forms in transform routine - - // BaryonField[MetalNum][i] += metals[i]; - // if (StarMakerTypeIaSNe) - // BaryonField[MetalIaNum][i] += metalsIA[i]; - // if (StarMakerTypeIISNeMetalField) - // BaryonField[MetalIINum][i] += metalsII[i]; - // if (PopIIISupernovaUseColour && SNColourNum != -1) - // BaryonField[SNColourNum][i] += metalsIII[i]; - // if (PopIIISupernovaUseColour && SNColourNum == -1) - // BaryonField[MetalNum][i] += metalsIII[i]; - // BaryonField[TENum][i] += - // totalEnergy[i]/BaryonField[DensNum][i]; - - // BaryonField[GENum][i] += - // gasEnergy[i]/BaryonField[DensNum][i]; - // BaryonField[Vel1Num][i] += u[i]; - // BaryonField[Vel2Num][i] += v[i]; - // BaryonField[Vel3Num][i] += w[i]; - // } - if (criticalDebug && !winds){ for (int i = 0; i< size ; i++){ postMass += BaryonField[DensNum][i]; @@ -556,11 +543,11 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, (postP - preP)*MomentaUnits, (sqrt(postPmag) - sqrt(prePmag)), (postTE-preTE)*EnergyUnits, (postGE-preGE)*EnergyUnits, - coupledGasEnergy*EnergyUnits*nCouple, ejectaEnergy, + coupledGasEnergy*EnergyUnits, ejectaEnergy, ejectaMass, ejectaMetal); if(isnan(postMass) || isnan(postTE) || isnan(postPmag) || isnan(postZ)){ fprintf(stderr, "NAN IN GRID: %e %e %e %e\n", postMass, postTE, postZ, postP); - ENZO_FAIL("MechStars_depositFeedback.C: 395\n") + ENZO_FAIL("MechStars_depositFeedback.C: 530\n") if (postGE-preGE < 0.0) ENZO_FAIL("471"); } diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 3c46c62dd..a38776016 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -40,7 +40,8 @@ float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, float *MassUnits, FLOAT Time); int MechStars_depositEmissivityField(int index, float cellwidth, - float* emissivity0, float age, float mass); + float* emissivity0, float age, float mass, + float TimeUnits, float dt); @@ -111,7 +112,6 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta float maxD = 0.0; int maxI=0, maxJ=0, maxK=0; int maxindex=0; - /* Begin Iteration of all particles */ // printf("\nIterating all particles "); for (int pIndex=0; pIndex < NumberOfParticles; pIndex++){ @@ -199,7 +199,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta float shieldedFraction = 0, dynamicalTime = 0, freeFallTime = 0; bool gridShouldFormStars = true, notEnoughMetals=false; float zFraction = totalMetal[index]; - if (ParticleMass[pIndex]*MassUnits < StarMakerMaximumMass){ + if (ParticleMass[pIndex]*MassUnits < StarMakerMaximumMass && ProblemType != 90){ int createStar = checkCreationCriteria(BaryonField[DensNum], &zFraction, Temperature, DMField, BaryonField[Vel1Num], BaryonField[Vel2Num], @@ -212,7 +212,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta float MassShouldForm =min((shieldedFraction * BaryonField[DensNum][index] * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13), 0.5*BaryonField[DensNum][index]*MassUnits); - printf("Adding new mass %e\n",MassShouldForm); + //printf("Adding new mass %e\n",MassShouldForm); /* Dont allow negative mass, or taking all gas in cell */ if (MassShouldForm < 0 ) MassShouldForm = 0; @@ -230,24 +230,26 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex]*ParticleMass[pIndex]+zFraction*MassShouldForm)/ (ParticleMass[pIndex] + MassShouldForm); // update mass-weighted age of star particle - if (age > 3.5) // only update if particle is old enough for SNe - ParticleAttribute[0][pIndex] = (ParticleAttribute[0][pIndex]*(1.-delta)+Time*delta); + // if (age > 3.5) // only update if particle is old enough for SNe + // ParticleAttribute[0][pIndex] = (ParticleAttribute[0][pIndex]*(1.-delta)+Time*delta); /* Add new formation mass to particle */ - ParticleMass[pIndex] += MassShouldForm; - printf("[%f] added new mass %e + %e = %e newZ = %f newAge = %f\n", - Time*TimeUnits/3.1557e13, (ParticleMass[pIndex]-MassShouldForm)*MassUnits, - MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, - ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); - - /* Take formed mass out of grid cell */ - - BaryonField[DensNum][index] -= MassShouldForm; - - /* Take metals out of host cell too! */ + if (MassShouldForm < 0.5*BaryonField[DensNum][index]){ + ParticleMass[pIndex] += MassShouldForm; + printf("[%f] added new mass %e + %e = %e newZ = %f newAge = %f\n", + Time*TimeUnits/3.1557e13, (ParticleMass[pIndex]-MassShouldForm)*MassUnits, + MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, + ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); + + /* Take formed mass out of grid cell */ + + BaryonField[DensNum][index] -= MassShouldForm; + + /* Take metals out of host cell too! */ - BaryonField[MetalNum][index] -= BaryonField[MetalNum][index]/BaryonField[DensNum][index]*MassShouldForm; - if (MechStarsSeedField) - BaryonField[SNColourNum][index] -= BaryonField[SNColourNum][index]/BaryonField[DensNum][index]*MassShouldForm; + BaryonField[MetalNum][index] -= BaryonField[MetalNum][index]/BaryonField[DensNum][index]*MassShouldForm; + if (MechStarsSeedField) + BaryonField[SNColourNum][index] -= BaryonField[SNColourNum][index]/BaryonField[DensNum][index]*MassShouldForm; + } } } } @@ -265,27 +267,23 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta TimeUnits, dtFixed); numSN += nSNII+nSNIA; if ((nSNII > 0 || nSNIA > 0) && debug) - fprintf(stdout,"SUPERNOVAE!!!! %d %d level = %d\n", nSNII, nSNIA, level); + fprintf(stdout,"SUPERNOVAE!!!! %d %d level = %d age = %f\n", nSNII, nSNIA, level, age); if (nSNII > 0 || nSNIA > 0){ /* set feedback qtys based on number and types of events */ /* 1e51 erg per sn */ - ParticleAttribute[1][pIndex] += nSNII + nSNIA; float energySN = (nSNII + nSNIA)*1e51; /*10.5 Msun ejecta for type II and IA*/ SNMassEjected = (nSNII+nSNIA)*10.5; - /* Metal yeilds from starburst 99 */ float starMetal = (ParticleAttribute[2][pIndex]/0.02); //determines metal content of SNeII - // if (StarMakerTypeIISNeMetalField) - // starMetal += ParticleAttribute[4][pIndex]/0.02; - /* Couple these in the deposit routine */ - // SNMetalEjected = nSNII*(1.91+0.0479*max(zZsun, 1.65)); - // SNMetalEjected += nSNIA*(1.4); // this metal should get coupled to SNIA field if its being used + MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, Temperature, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, starMetal, 0); - ParticleAttribute[1][pIndex] += nSNII+nSNIA; + // can only track number of events in dynamical time if not using it to determine lifetime + if (!StarParticleRadiativeFeedback) + ParticleAttribute[1][pIndex] += nSNII+nSNIA; } } @@ -315,12 +313,14 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta } if (windMass > 0.0 || SNMassEjected > 0){ - //if (debug) printf("Subtracting off mass %e\n",(windMass+SNMassEjected)); ParticleMass[pIndex] -= (windMass+SNMassEjected)/MassUnits; } + /* if these stars are used in conjunction with FLDImplicit or FLDSplit. This + functionality has not been verified + */ if (StarMakerEmissivityField){ MechStars_depositEmissivityField(index, CellWidth[0][0], BaryonField[EmisNum], - age, ParticleMass[pIndex]*MassUnits); + age, ParticleMass[pIndex]*MassUnits, TimeUnits, dtFixed); } // printf("Post-feedback MP = %e\n", ParticleMass[pIndex]*MassUnits); } diff --git a/src/enzo/Grid_MechStarsSeedSupernova.C b/src/enzo/Grid_MechStarsSeedSupernova.C index 6fb7bc866..6f1f74bf9 100644 --- a/src/enzo/Grid_MechStarsSeedSupernova.C +++ b/src/enzo/Grid_MechStarsSeedSupernova.C @@ -104,6 +104,10 @@ int grid::MechStars_SeedSupernova(float* totalMetal, float* temperature, int* se printf("Mass Outside Supernova Range!\n"); return SUCCESS; } + if (FinalMass > 0.1*BaryonField[DensNum][index]*MassUnits){ + printf("Cell too small for PIII star!"); + return FAIL; + } /* Now, calculate feedback parameters as in Star_CalculateFeedbackParameters.C */ // parameters of supernovae // @@ -126,13 +130,13 @@ int grid::MechStars_SeedSupernova(float* totalMetal, float* temperature, int* se float SNEnergy = 0; float EjectaMetal = 0; float EjectaMass = FinalMass; - if (BaryonField[DensNum][index]*DensityUnits*pow(LengthUnits*CellWidth[0][0],3) < 5.0*FinalMass){ - /* Should probably remove from larger area if host cell is too small, - but should only matter at VERY high resolution: M_cell < 50 M_sun*/ - if (debug) fprintf(stdout, "Not enough mass in cell for Seed Supernova: %f < %f", - BaryonField[DensNum][index]*DensityUnits*pow(LengthUnits*CellWidth[0][0],3), FinalMass); - return FAIL; - } + // if (BaryonField[DensNum][index]*DensityUnits*pow(LengthUnits*CellWidth[0][0],3) < 5.0*FinalMass){ + // /* Should probably remove from larger area if host cell is too small, + // but should only matter at VERY high resolution: M_cell < 50 M_sun*/ + // if (debug) fprintf(stdout, "Not enough mass in cell for Seed Supernova: %f < %f", + // BaryonField[DensNum][index]*DensityUnits*pow(LengthUnits*CellWidth[0][0],3), FinalMass); + // return FAIL; + // } /* Reverse CIC out the star mass */ int np = 1; float MassRem = -1*EjectaMass; float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index 47dedaa03..5bc01cb2b 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -663,10 +663,11 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, /* Convert the species densities into fractional densities (i.e. divide by total baryonic density). At the end we will multiply by the new density so that species fractions are maintained. */ - - for (field = 0; field < NumberOfBaryonFields; field++) - if ((FieldType[field] >= ElectronDensity && FieldType[field] <= ExtraType1) || - FieldType[field] == MetalSNIaDensity || FieldType[field] == MetalSNIIDensity) + if (!STARFEED_METHOD(MECHANICAL)){ + for (field = 0; field < NumberOfBaryonFields; field++) + if (((FieldType[field] >= ElectronDensity && FieldType[field] <= ExtraType1) || + FieldType[field] == MetalSNIaDensity || FieldType[field] == MetalSNIIDensity)) + { //fractional density doesnt play nice with CIC used in MechStars #ifdef EMISSIVITY /* it used to be set to FieldType[field] < GravPotential if Geoffrey's Emissivity0 @@ -674,14 +675,15 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, so the values will scale inside StarParticleHandler */ #endif - for (k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) - for (j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { - index = (k*GridDimension[1] + j)*GridDimension[0] + - GridStartIndex[0]; - for (i = GridStartIndex[0]; i <= GridEndIndex[0]; i++, index++) - BaryonField[field][index] /= BaryonField[DensNum][index]; - } - + for (k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) + for (j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { + index = (k*GridDimension[1] + j)*GridDimension[0] + + GridStartIndex[0]; + for (i = GridStartIndex[0]; i <= GridEndIndex[0]; i++, index++) + BaryonField[field][index] /= BaryonField[DensNum][index]; + } + } + } /* If creating primordial stars, make a total H2 density field */ float *h2field = NULL; @@ -718,7 +720,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, else { if (MetalNum != -1) MetalPointer = BaryonField[MetalNum]; - else if (SNColourNum != -1) + if (SNColourNum != -1) MetalPointer = BaryonField[SNColourNum]; } // ENDELSE both metal types @@ -834,7 +836,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, NumberOfNewParticlesSoFar = NumberOfParticles; int nRetStars = 0; nRetStars = MechStars_Creation(tg, temperature, - dmfield, TotalMetals, level, cooling_time, MaximumNumberOfNewParticles, + dmfield, MetalPointer, level, cooling_time, MaximumNumberOfNewParticles, &NumberOfNewParticles); //fprintf(stdout, "Created %d new stars!", NumberOfNewParticles); if (nRetStars != NumberOfNewParticles) fprintf(stdout, "star count return and pointer mismatch!\n"); @@ -1570,11 +1572,8 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, } // end: if NORMAL_STAR if (STARFEED_METHOD(MECHANICAL)){ float mu_field [size]; - for (k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { - for (j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { - for (i = GridStartIndex[0]; i <= GridEndIndex[0]; i++) { + for (index = 0; index < size; ++index) { - index = i + j*GridDimension[0] + k*GridDimension[0]*GridDimension[1]; mu_field[index] = 0.0; // calculate mu @@ -1594,9 +1593,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, } if (MultiSpecies > 2) { mu_field[index] += (BaryonField[DINum][index] + BaryonField[DIINum][index])/2.0 + (BaryonField[HDINum][index]/3.0); - } - } } } } @@ -1605,7 +1602,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, float *cooling_time = new float[size]; this->ComputeCoolingTime(cooling_time); //fprintf(stdout, "CALLING MECH FEEDBACK\n"); - MechStars_FeedbackRoutine(level, &mu_field[0], temperature, TotalMetals,cooling_time, dmfield); + MechStars_FeedbackRoutine(level, &mu_field[0], temperature, MetalPointer, cooling_time, dmfield); delete [] cooling_time; } if (STARFEED_METHOD(MOM_STAR)) { @@ -2068,10 +2065,11 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, } /* Convert the species back from fractional densities to real densities. */ - - for (field = 0; field < NumberOfBaryonFields; field++) { - if ((FieldType[field] >= ElectronDensity && FieldType[field] <= ExtraType1) || - FieldType[field] == MetalSNIaDensity || FieldType[field] == MetalSNIIDensity) { + if (!STARFEED_METHOD(MECHANICAL)) + for (field = 0; field < NumberOfBaryonFields; field++) { + if (((FieldType[field] >= ElectronDensity && FieldType[field] <= ExtraType1) || + FieldType[field] == MetalSNIaDensity || FieldType[field] == MetalSNIIDensity) ) // fractional things do not play nice with CIC + { #ifdef EMISSIVITY /* it used to be set to FieldType[field] < GravPotential if Geoffrey's Emissivity0 @@ -2079,17 +2077,17 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, so the values will scale inside StarParticleHandler */ #endif - for (k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { - for (j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { - index = (k*GridDimension[1] + j)*GridDimension[0] + - GridStartIndex[0]; - for (i = GridStartIndex[0]; i <= GridEndIndex[0]; i++, index++) { - BaryonField[field][index] *= BaryonField[DensNum][index]; - } - } + for (k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { + for (j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { + index = (k*GridDimension[1] + j)*GridDimension[0] + + GridStartIndex[0]; + for (i = GridStartIndex[0]; i <= GridEndIndex[0]; i++, index++) { + BaryonField[field][index] *= BaryonField[DensNum][index]; + } + } + } + } } - } - } /* Clean up. */ diff --git a/src/enzo/Grid_TestStarParticleInitializeGrid.C b/src/enzo/Grid_TestStarParticleInitializeGrid.C index 8c3e2cbb9..99894ea2f 100644 --- a/src/enzo/Grid_TestStarParticleInitializeGrid.C +++ b/src/enzo/Grid_TestStarParticleInitializeGrid.C @@ -91,6 +91,14 @@ int grid::TestStarParticleInitializeGrid(float TestStarParticleStarMass, ParticleAttribute[1][0] = 1.0; else ParticleAttribute[1][0] = 10.0 * Myr_s/TimeUnits; + if (STARFEED_METHOD(MECHANICAL)){ + if (StarParticleRadiativeFeedback){ + ParticleAttribute[1][0] = 1000*Myr_s/TimeUnits; // need infinite lifetime for radiation according to FIRE-2 algorithm + } + else{ + ParticleAttribute[1][0] = 0.0; // track num SNe in TDP field + } + } ParticleAttribute[2][0] = 0.0; // Metal fraction ParticleAttribute[3][0] = 0.0; // metalfSNIa diff --git a/src/enzo/MechStars_calcPhotonRates.C b/src/enzo/MechStars_calcPhotonRates.C new file mode 100644 index 000000000..44bbcaed9 --- /dev/null +++ b/src/enzo/MechStars_calcPhotonRates.C @@ -0,0 +1,68 @@ +/* + Couples the mechanical stars to the radiation machinery in ENZO by filling + in the emissivity0 field. + Code must be compiled with "make emissivity-yes" and "make photon-yes". + Usage at runtime determined by the StarMakerUseEmissivity flag. + Unlike the CIC depositions in the rest of this module, the emissivity is set + solely for the cell hosting the star particle (or its kicked location). + + The radiation deposited here is time varying depending on the age of the particle (and mass). + A better implementation will make the individual bands of radiation time dependent + (more UV early, more IR late). + */ +#include +#include +#include +#include +#include "ErrorExceptions.h" +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "fortran.def" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" +//#include "gFLDProblem.h" + + +int MechStars_calcPhotonRates(Star* star, const float Time) +{ + // Modeling after fFLDSplit_RadiationSource.F90 to fill in Emissivity0 field. + // etaconst = h_nu0*NGammaDot*specconst/dV + // specconst ~ scaling factor for spectrum -> varies depeding on user choice of tracked radiation + // dV ~ proper volume of cell + // NGammaDot ~ photons per second. -> this will vary depending on age of particle! + const float LsunToErg = 3.85e33; // erg/s + const float evPerErg = 6.2415e11; + const float h_nu0 = 13.6/evPerErg; // erg + float age = Time - star->ReturnBirthTime(); + /* + Calculate rates of photons given the age-based luminosity in Hopkins 2017. Units are + L_sun/M_sun. While they are given, we dont bother with IR/optical bands here. + We only couple the ionizing radiation, Psi_ion. The others are calculated if they happen + to be used in the future. + */ + float Psi_fuv = 0.0, Psi_ion = 0.0; + if (age < 3.4){ + Psi_fuv = 271. * (1.0 + (age/3.4)*(age/3.4)); + } + if (age < 3.5){ + Psi_ion = 500; + } + if (age > 3.5 && age < 25){ + Psi_ion = 60.*pow(age/3.5, -3.6)+470*pow(age/3.5, 0.045-1.82*log(age)); + } + if (age > 3.4){ + Psi_fuv = 572.*pow(age/3.4, -1.5); + } + // convert to better units + //Psi_ion *= star->ReturnMass(); // L_sun + return Psi_ion; + + return SUCCESS; +} + diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index a5dabb925..07c7260a2 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -114,11 +114,12 @@ int checkCreationCriteria(float* Density, float* Metals, if (Temperature[index] > 1e4) { - status = FAIL; //no hot gas forming stars! + if (MultiSpecies > 0) status = FAIL; //no hot gas forming stars! float totalDensity = (Density[index] +DMField[index])*DensityUnits; *dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); - if (*dynamicalTime/TimeUnits < CoolingTime[index]) status = FAIL; + if (*dynamicalTime/TimeUnits < CoolingTime[index]) + status = FAIL; } /* is gas mass > critical jeans mass? */ @@ -130,6 +131,7 @@ int checkCreationCriteria(float* Density, float* Metals, float jeansMass = pi/(6.0*pow(Density[index]*DensityUnits, 0.5)) *pow(pi*IsoSndSpeed/GravConst, 1.5)/SolarMass; if (jeansMass > max(baryonMass, 1e3)) status = FAIL; + /* Is self Shielded fraction > 0.0 by Krumholz & Gnedin */ float gradRho = (Density[index+1]-Density[index-1]) diff --git a/src/enzo/MechStars_depositEmissivity.C b/src/enzo/MechStars_depositEmissivity.C new file mode 100644 index 000000000..7a6395d34 --- /dev/null +++ b/src/enzo/MechStars_depositEmissivity.C @@ -0,0 +1,90 @@ +/* + Couples the mechanical stars to the radiation machinery in ENZO by filling + in the emissivity0 field. + Code must be compiled with "make emissivity-yes" and "make photon-yes". + Usage at runtime determined by the StarMakerUseEmissivity flag. + Unlike the CIC depositions in the rest of this module, the emissivity is set + solely for the cell hosting the star particle (or its kicked location). + + The radiation deposited here is time varying depending on the age of the particle (and mass). + A better implementation will make the individual bands of radiation time dependent + (more UV early, more IR late). + */ +#include +#include +#include +#include +#include "ErrorExceptions.h" +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "fortran.def" +#include "CosmologyParameters.h" +#include "StarParticleData.h" +#include "phys_constants.h" +//#include "gFLDProblem.h" + +int MechStars_depositEmissivityField(int index, float cellwidth, + float* emissivity0, float age, float mass, + float TimeUnits, float dt) +{ + // Modeling after fFLDSplit_RadiationSource.F90 to fill in Emissivity0 field. + // etaconst = h_nu0*NGammaDot*specconst/dV + // specconst ~ scaling factor for spectrum -> varies depeding on user choice of tracked radiation + // dV ~ proper volume of cell + // NGammaDot ~ photons per second. -> this will vary depending on age of particle! + const float LsunToErg = 3.85e33; // erg/s + const float evPerErg = 6.2415e11; + const float h_nu0 = 13.6/evPerErg; // erg + /* + Calculate rates of photons given the age-based luminosity in Hopkins 2017. Units are + L_sun/M_sun. While they are given, we dont bother with IR/optical bands here. + We only couple the ionizing radiation, Psi_ion. The others are calculated if they happen + to be used in the future. + */ + float Psi_fuv = 0.0, Psi_ion = 0.0; + if (age < 3.4){ + Psi_fuv = 271. * (1.0 + (age/3.4)*(age/3.4)); + } + if (age < 3.5){ + Psi_ion = 500; + } + if (age > 3.5 && age < 25){ + Psi_ion = 60.*pow(age/3.5, -3.6)+470*pow(age/3.5, 0.045-1.82*log(age)); + } + if (age > 3.4){ + Psi_fuv = 572.*pow(age/3.4, -1.5); + } + // convert to better units + Psi_ion *= mass; // L_sun + Psi_ion *= LsunToErg/TimeUnits*dt; // erg/code_time + /* + assuming all those photons are in the HI ionization range, the number + of photons is + */ + float NGammaDot = Psi_ion / h_nu0; + + + // /* + // Select spectrum scaling based on parameters + // (probably just HI radiation for now) + // This routine only works with HI radiation for now, as the + // rest of the rates would require another Starburst99 sim to get + // */ + if (MechStarsRadiationSpectrum != -1){ + ENZO_FAIL("MechStars only implemented for RadHydroESpectrum = -1\n"); + } + const float specconst = 1.0; + + /* + Apply selected to Emissivity0 in the form of etaconst. + */ + emissivity0[index] += pow(cellwidth, 3.0)*specconst*NGammaDot*h_nu0; + + return SUCCESS; +} + diff --git a/src/enzo/MechStars_depositEmissivityField.C b/src/enzo/MechStars_depositEmissivityField.C index 8aec66362..e4f0c5b98 100644 --- a/src/enzo/MechStars_depositEmissivityField.C +++ b/src/enzo/MechStars_depositEmissivityField.C @@ -29,8 +29,7 @@ //#include "gFLDProblem.h" -int MechStars_depositEmissivityField(int index, float cellwidth, - float* emissivity0, float age, float mass) +int MechStars_calcPhotonRates(Star* star, const float Time) { // Modeling after fFLDSplit_RadiationSource.F90 to fill in Emissivity0 field. // etaconst = h_nu0*NGammaDot*specconst/dV @@ -40,6 +39,7 @@ int MechStars_depositEmissivityField(int index, float cellwidth, const float LsunToErg = 3.85e33; // erg/s const float evPerErg = 6.2415e11; const float h_nu0 = 13.6/evPerErg; // erg + float age = Time - star->ReturnBirthTime(); /* Calculate rates of photons given the age-based luminosity in Hopkins 2017. Units are L_sun/M_sun. While they are given, we dont bother with IR/optical bands here. @@ -60,30 +60,31 @@ int MechStars_depositEmissivityField(int index, float cellwidth, Psi_fuv = 572.*pow(age/3.4, -1.5); } // convert to better units - Psi_ion *= mass; // L_sun - Psi_ion *= LsunToErg; // erg/s - /* - assuming all those photons are in the HI ionization range, the number - of photons is - */ - float NGammaDot = Psi_ion / h_nu0; + Psi_ion *= star->ReturnMass(); // L_sun + return Psi_ion; + // Psi_ion *= LsunToErg/TimeUnits*dt; // erg/code_time + // /* + // assuming all those photons are in the HI ionization range, the number + // of photons is + // */ + // float NGammaDot = Psi_ion / h_nu0; - /* - Select spectrum scaling based on parameters - (probably just HI radiation for now) - This routine only works with HI radiation for now, as the - rest of the rates would require another Starburst99 sim to get - */ - if (MechStarsRadiationSpectrum != -1){ - ENZO_FAIL("MechStars only implemented for RadHydroESpectrum = -1\n"); - } - const float specconst = 1.0; + // /* + // Select spectrum scaling based on parameters + // (probably just HI radiation for now) + // This routine only works with HI radiation for now, as the + // rest of the rates would require another Starburst99 sim to get + // */ + // if (MechStarsRadiationSpectrum != -1){ + // ENZO_FAIL("MechStars only implemented for RadHydroESpectrum = -1\n"); + // } + // const float specconst = 1.0; - /* - Apply selected to Emissivity0 in the form of etaconst. - */ - emissivity0[index] += pow(cellwidth, 3.0)*specconst*NGammaDot*h_nu0; + // /* + // Apply selected to Emissivity0 in the form of etaconst. + // */ + // emissivity0[index] += pow(cellwidth, 3.0)*specconst*NGammaDot*h_nu0; return SUCCESS; } diff --git a/src/enzo/MechStars_determineSN.C b/src/enzo/MechStars_determineSN.C index 36020b08d..90bbd93c1 100644 --- a/src/enzo/MechStars_determineSN.C +++ b/src/enzo/MechStars_determineSN.C @@ -57,6 +57,7 @@ int determineSN(float age, int* nSNII, int* nSNIA, /* rates -> probabilities */ if (RII > 0){ srand(seed); + // printf("Zcpl = %e", zCouple); PII = RII * massMsun / 3.1557e13 *TimeUnits*dt; // printf("PII =%f\n %f %e %f\n", PII, RII, massMsun, age); random = float(rand())/float(RAND_MAX); diff --git a/src/enzo/MechStars_transformComovingWithStar.C b/src/enzo/MechStars_transformComovingWithStar.C index 1d86a66da..65c855928 100644 --- a/src/enzo/MechStars_transformComovingWithStar.C +++ b/src/enzo/MechStars_transformComovingWithStar.C @@ -11,8 +11,10 @@ int transformComovingWithStar(float* Density, float* Metals, float* TE, float* GE, float up, float vp, float wp, int sizeX, int sizeY, int sizeZ, int direction){ - /* transform velocities to momenta or back and make them comoving with the star particle - Transform metallicity fields to metal density fields*/ + /* + transform velocities to momenta or back and make them comoving with the star particle + Metals are still densities here for CIC deposition + */ int size = sizeX*sizeY*sizeZ; if (direction > 0){ @@ -27,16 +29,15 @@ int transformComovingWithStar(float* Density, float* Metals, Vel2[ind] = (preV-vp)*mult; preV = Vel3[ind]; Vel3[ind] = (preV-wp)*mult; - if(StarMakerTypeIaSNe) - MetalsSNIA[ind] = MetalsSNIA[ind]*mult; - if(StarMakerTypeIISNeMetalField) - MetalsSNII[ind] = Metals[ind]*mult; + } } if (direction < 0){ - /* back to "lab" frame, metal densities back to metallicities */ + /* + back to "lab" frame + */ for (int ind = 0; ind < size; ++ind){ float mult = 1./Density[ind]; TE[ind] *= mult; @@ -44,10 +45,7 @@ int transformComovingWithStar(float* Density, float* Metals, Vel1[ind] = Vel1[ind]*mult+up; Vel2[ind] = Vel2[ind]*mult+vp; Vel3[ind] = Vel3[ind]*mult+wp; - if(StarMakerTypeIaSNe) - MetalsSNIA[ind] = MetalsSNIA[ind]*mult; - if(StarMakerTypeIISNeMetalField) - MetalsSNII[ind] = Metals[ind]*mult; + } } return SUCCESS; diff --git a/src/enzo/RadiativeTransferPrepare.C b/src/enzo/RadiativeTransferPrepare.C index bd78231a0..ab4858dba 100644 --- a/src/enzo/RadiativeTransferPrepare.C +++ b/src/enzo/RadiativeTransferPrepare.C @@ -30,7 +30,7 @@ int RadiativeTransferComputeTimestep(LevelHierarchyEntry *LevelArray[], TopGridData *MetaData, float dtLevelAbove, int level); int StarParticleRadTransfer(LevelHierarchyEntry *LevelArray[], int level, - Star *AllStars); + Star *AllStars, float Time); int RestartPhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], int level, Star *AllStars); @@ -60,7 +60,7 @@ int RadiativeTransferPrepare(LevelHierarchyEntry *LevelArray[], int level, /* Convert star particles into radiation sources only if we're going into EvolvePhotons */ if(AllStars != NULL) - StarParticleRadTransfer(LevelArray, level, AllStars); + StarParticleRadTransfer(LevelArray, level, AllStars, GridTime); } // ENDIF diff --git a/src/enzo/ReadParameterFile.C b/src/enzo/ReadParameterFile.C index c08cd7bb1..c76cbd1c0 100644 --- a/src/enzo/ReadParameterFile.C +++ b/src/enzo/ReadParameterFile.C @@ -1140,6 +1140,7 @@ int ReadParameterFile(FILE *fptr, TopGridData &MetaData, float *Initialdt) ret += sscanf(line, "UnrestrictedSN = %"ISYM, &UnrestrictedSN); ret += sscanf(line, "MechStarsCriticalMetallicity = %"FSYM, &MechStarsCriticalMetallicity); ret += sscanf(line, "MechStarsSeedField = %"ISYM, &MechStarsSeedField); + ret += sscanf(line, "MechStarsRadiationSpectrum = %"ISYM, &MechStarsRadiationSpectrum); /* Read Movie Dump parameters */ diff --git a/src/enzo/RestartPhotons.C b/src/enzo/RestartPhotons.C index 036a96cb6..13b891b3f 100644 --- a/src/enzo/RestartPhotons.C +++ b/src/enzo/RestartPhotons.C @@ -40,7 +40,7 @@ int GetUnits(float *DensityUnits, float *LengthUnits, int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], Star *&AllStars, FLOAT GridTime, int level, int LoopTime = TRUE); int StarParticleRadTransfer(LevelHierarchyEntry *LevelArray[], int level, - Star *AllStars); + Star *AllStars, float Time); int RestartPhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], int level, Star *AllStars) @@ -62,7 +62,7 @@ int RestartPhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, MetaData->Time); - StarParticleRadTransfer(LevelArray, level, AllStars); + StarParticleRadTransfer(LevelArray, level, AllStars, MetaData->Time); /* Light crossing time */ diff --git a/src/enzo/Star.h b/src/enzo/Star.h index 823090e65..6726ef293 100644 --- a/src/enzo/Star.h +++ b/src/enzo/Star.h @@ -108,7 +108,7 @@ class Star void ConvertMassToSolar(void); int CalculateMassAccretion(float &BondiRadius, float &density); float CalculateMassLoss(const float dt); - int ComputePhotonRates(const float TimeUnits, int &nbins, float E[], double Q[]); + int ComputePhotonRates(const float TimeUnits, const float Time, int &nbins, float E[], double Q[], float dtForThisStar); int SetFeedbackFlag(FLOAT Time); void SetFeedbackFlag(int flag); #ifdef LARGE_INTS diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index eb2f519a3..3cca1655d 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -208,7 +208,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, float energies[MAX_ENERGY_BINS], deltaE; #ifdef TRANSFER if (RadiativeTransfer) { - cstar->ComputePhotonRates(TimeUnits, nbins, energies, Q); + cstar->ComputePhotonRates(TimeUnits, Time, nbins, energies, Q, dtForThisStar); sigma = (double) FindCrossSection(0, energies[0]); // HI (cm^2) Q_HI = Q[0]; deltaE = energies[0] - 13.6; // eV diff --git a/src/enzo/StarParticleRadTransfer.C b/src/enzo/StarParticleRadTransfer.C index 92b5dfd22..80524d80e 100644 --- a/src/enzo/StarParticleRadTransfer.C +++ b/src/enzo/StarParticleRadTransfer.C @@ -35,7 +35,7 @@ int GetUnits(float *DensityUnits, float *LengthUnits, float *VelocityUnits, FLOAT Time); int StarParticleRadTransfer(LevelHierarchyEntry *LevelArray[], int level, - Star *AllStars) + Star *AllStars, float Time) { /* If photon test simulation, don't change the radiation sources. */ @@ -82,9 +82,10 @@ int StarParticleRadTransfer(LevelHierarchyEntry *LevelArray[], int level, // Check the rules if this star particle is radiative if (cstar->IsARadiationSource(PhotonTime)) { + float dtForThisStar = LevelArray[level]->GridData->ReturnTimeStep(); // Calculate photon luminosity - if (cstar->ComputePhotonRates(TimeUnits, nbins, energies, Q) == FAIL) { + if (cstar->ComputePhotonRates(TimeUnits, Time, nbins, energies, Q, dtForThisStar) == FAIL) { ENZO_FAIL("Error in ComputePhotonRates.\n"); } diff --git a/src/enzo/Star_Accrete.C b/src/enzo/Star_Accrete.C index fa71e9718..44732dc03 100644 --- a/src/enzo/Star_Accrete.C +++ b/src/enzo/Star_Accrete.C @@ -31,7 +31,8 @@ int GetUnits(float *DensityUnits, float *LengthUnits, int Star::Accrete(void) { if (this->CurrentGrid == NULL || - (this->naccretions == 0 && fabs(this->DeltaMass) < tiny_number)) + (this->naccretions == 0 && fabs(this->DeltaMass) < tiny_number) + || FeedbackFlag == MECHANICAL) // mechanical accretion and feedback handled in mechstars routines return SUCCESS; diff --git a/src/enzo/Star_ComputePhotonRates.C b/src/enzo/Star_ComputePhotonRates.C index 542678794..a324f7495 100644 --- a/src/enzo/Star_ComputePhotonRates.C +++ b/src/enzo/Star_ComputePhotonRates.C @@ -30,8 +30,10 @@ #include "LevelHierarchy.h" float ReturnValuesFromSpectrumTable(float ColumnDensity, float dColumnDensity, int mode); +int MechStars_calcPhotonRates(Star* star, const float Time); -int Star::ComputePhotonRates(const float TimeUnits, int &nbins, float E[], double Q[]) +int Star::ComputePhotonRates(const float TimeUnits, const float Time, + int &nbins, float E[], double Q[], float dtForThisStar) { @@ -188,11 +190,20 @@ int Star::ComputePhotonRates(const float TimeUnits, int &nbins, float E[], doubl E[0] = 21.0; // Good for [Z/H] > -1.3 (Schaerer 2003) // Calculate Delta(M_SF) for Cen & Ostriker star particles #ifdef TRANSFER + if (FeedbackFlag == MECHANICAL){ + E[0] = 13.6; // H ionizing radiation + L_UV = MechStars_calcPhotonRates(this, Time);// returns [L_UV] = L_sun/M_sun + cgs_convert = SolarMass/TimeUnits; + + Q[0] = L_UV*eV_erg*SolarLuminosity/E[0]* this->Mass*(dtPhoton); + } + else{ Mform = this->CalculateMassLoss(dtPhoton) / StarMassEjectionFraction; // units of Msun/(time in code units) L_UV = 4 * pi * StarEnergyToStellarUV * Mform * clight * clight / dtPhoton; cgs_convert = SolarMass / TimeUnits; Q[0] = cgs_convert * L_UV * eV_erg / E[0]; // ph/s + } #else Q[0] = 0.0; #endif diff --git a/src/enzo/Star_IsARadiationSource.C b/src/enzo/Star_IsARadiationSource.C index 3ec0d0354..f7b9e0ffa 100644 --- a/src/enzo/Star_IsARadiationSource.C +++ b/src/enzo/Star_IsARadiationSource.C @@ -44,11 +44,12 @@ bool Star::IsARadiationSource(FLOAT Time) // Particles only marked for nothing or continuous supernova rules[0] = (FeedbackFlag == NO_FEEDBACK || FeedbackFlag == CONT_SUPERNOVA || + FeedbackFlag == MECHANICAL || FeedbackFlag == MBH_THERMAL || FeedbackFlag == MBH_JETS); - // Living - rules[1] = (Time >= BirthTime && Time <= BirthTime+LifeTime && type > 0); + // Living, but mechanical stars never die + rules[1] = (FeedbackFlag == MECHANICAL)?(Time >= BirthTime && type > 0):(Time >= BirthTime && Time <= BirthTime+LifeTime && type > 0); // Non-zero BH accretion (usually accretion_rate[] here is NULL - Ji-hoon Kim Sep.2009) if ((type == BlackHole || type == MBH) && naccretions > 0) diff --git a/src/enzo/Star_SetFeedbackFlag.C b/src/enzo/Star_SetFeedbackFlag.C index e676409ca..4f90f68f7 100644 --- a/src/enzo/Star_SetFeedbackFlag.C +++ b/src/enzo/Star_SetFeedbackFlag.C @@ -128,6 +128,11 @@ int Star::SetFeedbackFlag(FLOAT Time) #endif break; + case NormalStar: + //printf("setting feedback flag to %d", MECHANICAL); + this->FeedbackFlag = MECHANICAL; + break; + default: this->FeedbackFlag = NO_FEEDBACK; break; diff --git a/src/enzo/WriteParameterFile.C b/src/enzo/WriteParameterFile.C index ae1c108ff..76d745fd1 100644 --- a/src/enzo/WriteParameterFile.C +++ b/src/enzo/WriteParameterFile.C @@ -1127,6 +1127,8 @@ int WriteParameterFile(FILE *fptr, TopGridData &MetaData, char *name = NULL) fprintf(fptr, "UnrestrictedSN = %"ISYM"\n", UnrestrictedSN); fprintf(fptr, "MechStarsCriticalMetallicity = %"FSYM"\n", MechStarsCriticalMetallicity); fprintf(fptr, "MechStarsSeedField = %"ISYM"\n", MechStarsSeedField); + fprintf(fptr, "MechStarsRadiationSpectrum = %"ISYM"\n", MechStarsRadiationSpectrum); + /* Most Stanford additions: */ fprintf(fptr, "UseHydro = %"ISYM"\n", UseHydro); diff --git a/src/enzo/gFLDSplit_Initialize.C b/src/enzo/gFLDSplit_Initialize.C index c1d9701c0..46cb04411 100644 --- a/src/enzo/gFLDSplit_Initialize.C +++ b/src/enzo/gFLDSplit_Initialize.C @@ -98,7 +98,7 @@ int gFLDSplit::Initialize(HierarchyEntry &TopGrid, TopGridData &MetaData) // printf("FLD Initialize: MPI task %"ISYM" has %"ISYM" available OpenMP threads\n", // MyProcessorNumber,nthreads); // #endif - +if (debug) printf(" Initializing MPI data\n"); #ifndef MPI_INT // in case MPI is not included @@ -122,7 +122,7 @@ int gFLDSplit::Initialize(HierarchyEntry &TopGrid, TopGridData &MetaData) for (face=0; face<2; face++) NBors[dim][face] = ThisGrid->GridData->GetProcessorNeighbors(dim,face); -// if (debug) printf(" Initialize: setting default parameters\n"); +if (debug) printf(" Initialize: setting default parameters\n"); // set default module parameters Nchem = 1; // hydrogen only @@ -171,7 +171,7 @@ int gFLDSplit::Initialize(HierarchyEntry &TopGrid, TopGridData &MetaData) hnu0_HeI = 24.6; // ionization energy of HeI [eV] hnu0_HeII = 54.4; // ionization energy of HeII [eV] -// if (debug) printf(" Initialize: checking input file\n"); +if (debug) printf(" Initialize: checking input file\n"); //////////////////////////////// // if input file present, over-write defaults with module inputs @@ -237,14 +237,14 @@ int gFLDSplit::Initialize(HierarchyEntry &TopGrid, TopGridData &MetaData) } // end loop over file lines } // end successful file open + rewind(fptr); + fclose(fptr); } // end if file name exists - + if (debug) printf(" Initialize: Read in file\n"); // clean up delete[] dummy; - rewind(fptr); - fclose(fptr); -// if (debug) printf(" Initialize: verifying inputs\n"); +if (debug) printf(" Initialize: verifying inputs\n"); //////////////////////////////// @@ -646,7 +646,7 @@ int gFLDSplit::Initialize(HierarchyEntry &TopGrid, TopGridData &MetaData) if (this->ComputeRadiationIntegrals() == FAIL) ENZO_FAIL("gFLDSplit::Initialize Error in computing radiation spectrum integrals"); -// if (debug) printf(" Initialize: initializing HYPRE data structures\n"); +if (debug) printf(" Initialize: initializing HYPRE data structures\n"); #ifdef USE_HYPRE diff --git a/src/enzo/typedefs.h b/src/enzo/typedefs.h index 7a2dd9bf4..0afbb601a 100644 --- a/src/enzo/typedefs.h +++ b/src/enzo/typedefs.h @@ -192,7 +192,7 @@ enum field_type {Density, TotalEnergy, InternalEnergy, Pressure, FieldUndefined}; */ -#define FieldTypeIsDensity(A) ((((A) == MetalSNIaDensity || (A) == MetalSNIIDensity) || ((A) >= TotalEnergy && (A) <= Velocity3) || ((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RaySegments) || ((A) >= Bfield1 && (A) <= AccelerationField3)) ? FALSE : TRUE) +#define FieldTypeIsDensity(A) (( ((A) >= TotalEnergy && (A) <= Velocity3) || ((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RaySegments) || ((A) >= Bfield1 && (A) <= AccelerationField3)) ? FALSE : TRUE) #define FieldTypeIsRadiation(A) ((((A) >= kphHI && (A) <= kdissH2I) || ((A) >= RadiationFreq0 && (A) <= RadiationFreq9)) ? TRUE : FALSE) #define FieldTypeNoInterpolate(A) (((((A) >= Mach) && ((A) <= PreShockDensity)) || ((A) == GravPotential) || ((A) == RaySegments)) ? TRUE : FALSE) From c0cc43cfc15e99b9e86621672012d91704d28a87 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 11 Oct 2019 10:28:19 -0700 Subject: [PATCH 024/115] forgot to add config for make --- src/enzo/Make.config.objects | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index b14852429..81760ca15 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -742,6 +742,8 @@ OBJS_CONFIG_LIB = \ MechStars_determineSN.o\ MechStars_determineWinds.o\ MechStars_transformComovingWithStar.o\ + MechStars_depositEmissivity.o\ + MechStars_calcPhotonRates.o\ MemoryAllocationRoutines.o \ MemoryPoolRoutines.o \ MersenneTwister.o \ From 429feea947fefb18867c8b9b0f2fa0d65191a678 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 14 Oct 2019 16:11:11 -0700 Subject: [PATCH 025/115] Re-incorporated teststar changes to allow cluster testing --- src/enzo/Grid.h | 4 +- .../Grid_TestStarParticleInitializeGrid.C | 69 ++++++++++--------- src/enzo/TestStarParticleInitialize.C | 36 +++++----- 3 files changed, 58 insertions(+), 51 deletions(-) diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index e9308a841..338da59d8 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2069,7 +2069,9 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int TestStarParticleInitializeGrid(float TestStarParticleStarMass, float *Initialdt, FLOAT TestStarParticleStarVelocity[], - FLOAT TestStarParticleStarPosition[]); + + int numberOfTestStars, + float clusterRadius); /* Gravity Test: initialize grid. */ diff --git a/src/enzo/Grid_TestStarParticleInitializeGrid.C b/src/enzo/Grid_TestStarParticleInitializeGrid.C index 99894ea2f..33ce71397 100644 --- a/src/enzo/Grid_TestStarParticleInitializeGrid.C +++ b/src/enzo/Grid_TestStarParticleInitializeGrid.C @@ -29,29 +29,29 @@ int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, double *MassUnits, FLOAT Time); -int grid::TestStarParticleInitializeGrid(float TestStarParticleStarMass, +int grid::TestStarParticleInitializeGrid(float TestStarParticleStarMass, float *Initialdt, FLOAT TestStarParticleStarVelocity[], - FLOAT TestStarParticleStarPosition[]) + int NumberOfTestStars, float clusterRadius) { /* declarations */ float CentralMass = 1.0; int i, dim; float TestInitialdt = *Initialdt; - + /* Return if this doesn't concern us. */ if (ProcessorNumber != MyProcessorNumber) return SUCCESS; - + /* Get Units. */ - float TemperatureUnits = 1, DensityUnits = 1, LengthUnits = 1, + float TemperatureUnits = 1, DensityUnits = 1, LengthUnits = 1, VelocityUnits = 1, TimeUnits = 1; double MassUnits = 1; - + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, &MassUnits, Time) == FAIL) { ENZO_FAIL("Error in GetUnits.\n"); @@ -65,7 +65,7 @@ int grid::TestStarParticleInitializeGrid(float TestStarParticleStarMass, /* Set number of particles for this grid and allocate space. */ - NumberOfParticles = 1; + NumberOfParticles = NumberOfTestStars; NumberOfParticleAttributes = 4; this->AllocateNewParticles(NumberOfParticles); printf("Allocated %d particles\n", NumberOfParticles); @@ -76,33 +76,40 @@ int grid::TestStarParticleInitializeGrid(float TestStarParticleStarMass, ParticleNumber[i] = i; ParticleType[i] = PARTICLE_TYPE_STAR; } - - /* Set central particle. */ - for (dim = 0; dim < GridRank; dim++) { - ParticlePosition[dim][0] = TestStarParticleStarPosition[dim]* - (DomainLeftEdge[dim]+DomainRightEdge[dim]) + 0.5*CellWidth[0][0]; - ParticleVelocity[dim][0] = TestStarParticleStarVelocity[dim]*1e5*TimeUnits/LengthUnits; - } - ParticleMass[0] = CentralMass; - ParticleAttribute[0][0] = Time+1e-7; //creation time:make sure it is non-zero - if (STARFEED_METHOD(UNIGRID_STAR)) ParticleAttribute[1][0] = 10.0 * Myr_s/TimeUnits; - if (STARFEED_METHOD(MOM_STAR)) - if(StarMakerExplosionDelayTime >= 0.0) - ParticleAttribute[1][0] = 1.0; - else - ParticleAttribute[1][0] = 10.0 * Myr_s/TimeUnits; - if (STARFEED_METHOD(MECHANICAL)){ - if (StarParticleRadiativeFeedback){ - ParticleAttribute[1][0] = 1000*Myr_s/TimeUnits; // need infinite lifetime for radiation according to FIRE-2 algorithm + float p1; + + /* Set central particle. */ + for (i = 0; i <= NumberOfParticles; i++){ + for (dim = 0; dim < GridRank; dim++) { + if (NumberOfParticles == 1){ + p1 = 0.5; + }else{ + int rng = clusterRadius*200; + p1 = float(rand() % rng)/100.0+(0.5-clusterRadius); + } + ParticlePosition[dim][i] = p1* + (DomainLeftEdge[dim]+DomainRightEdge[dim]) + 0.5*CellWidth[0][0]; + ParticleVelocity[dim][i] = TestStarParticleStarVelocity[dim]*1e5*TimeUnits/LengthUnits; } - else{ - ParticleAttribute[1][0] = 0.0; // track num SNe in TDP field + ParticleMass[i] = CentralMass; + ParticleAttribute[0][i] = Time+1e-7; //creation time:make sure it is non-zero + if (STARFEED_METHOD(UNIGRID_STAR)) ParticleAttribute[1][i] = 10.0 * Myr_s/TimeUnits; + if (STARFEED_METHOD(MOM_STAR)) + if(StarMakerExplosionDelayTime >= 0.0) + ParticleAttribute[1][i] = 1.0; + else + ParticleAttribute[1][i] =10.0 * Myr_s/TimeUnits; + if (STARFEED_METHOD(MECHANICAL)) { + if (StarParticleRadiativeFeedback){ + ParticleAttribute[1][i] = 25 * Myr_s/TimeUnits; // radiate for 25 Myr + } + else{ + ParticleAttribute[1][i] = 0.0; + } } + ParticleAttribute[2][i] = 0.0; // Metal fraction + ParticleAttribute[3][i] = 0.0; // metalfSNIa } - - ParticleAttribute[2][0] = 0.0; // Metal fraction - ParticleAttribute[3][0] = 0.0; // metalfSNIa - return SUCCESS; } diff --git a/src/enzo/TestStarParticleInitialize.C b/src/enzo/TestStarParticleInitialize.C index 1a8147dfc..363372ceb 100644 --- a/src/enzo/TestStarParticleInitialize.C +++ b/src/enzo/TestStarParticleInitialize.C @@ -64,10 +64,11 @@ int TestStarParticleInitialize(FILE *fptr, FILE *Outfptr, HierarchyEntry &TopGri FLOAT TestStarParticleStarVelocity[3] = {0.0, 0.0, 0.0}; FLOAT TestStarParticleStarPosition[3] = {0.5, 0.5, 0.5}; float TestStarParticleBField[3] = {0.0, 0.0, 0.0}; - float TestStarParticleStarMass = 100.0; + float TestStarParticleStarMass = 1000.0; int TestProblemUseMetallicityField = 1; float TestProblemInitialMetallicityFraction = 2e-3; // 0.1 Zsun - + int NumberOfTestStars = 10; + float clusterRadius = 0.125; @@ -91,18 +92,20 @@ int TestStarParticleInitialize(FILE *fptr, FILE *Outfptr, HierarchyEntry &TopGri &TestStarParticleEnergy); ret += sscanf(line, "TestStarParticleStarMass = %"FSYM, &TestStarParticleStarMass); - ret += sscanf(line,"TestStarParticleStarVelocity = %"PSYM" %"PSYM" %"PSYM, + ret += sscanf(line,"TestStarParticleStarVelocity = %"PSYM" %"PSYM" %"PSYM, &TestStarParticleStarVelocity[0], &TestStarParticleStarVelocity[1], &TestStarParticleStarVelocity[2]); - ret += sscanf(line,"TestStarParticleStarPosition = %"PSYM" %"PSYM" %"PSYM, + ret += sscanf(line,"TestStarParticleStarPosition = %"PSYM" %"PSYM" %"PSYM, &TestStarParticleStarPosition[0], &TestStarParticleStarPosition[1], &TestStarParticleStarPosition[2]); - + ret += sscanf(line, "NumberOfTestStars =%"ISYM, &NumberOfTestStars); + ret += sscanf(line,"ClusterRadius =%"ISYM, &clusterRadius); + ret += sscanf(line, "TestProblemUseMetallicityField = %"ISYM, &TestProblemData.UseMetallicityField); - ret += sscanf(line, "TestProblemInitialMetallicityFraction = %"FSYM, &TestProblemData.MetallicityField_Fraction); + ret += sscanf(line, "TestProblemInitialMetallicityFraction = %"FSYM, &TestProblemData.MetallicityField_Fraction); ret += sscanf(line, "TestProblemInitialHIFraction = %"FSYM, &TestProblemData.HI_Fraction); ret += sscanf(line, "TestProblemInitialHIIFraction = %"FSYM, &TestProblemData.HII_Fraction); @@ -114,7 +117,7 @@ int TestStarParticleInitialize(FILE *fptr, FILE *Outfptr, HierarchyEntry &TopGri /* if the line is suspicious, issue a warning */ - if (ret == 0 && strstr(line, "=") && strstr(line, "TestStarParticle") + if (ret == 0 && strstr(line, "=") && strstr(line, "TestStarParticle") && line[0] != '#') fprintf(stderr, "warning: the following parameter line was not interpreted:\n%s\n", line); @@ -122,24 +125,23 @@ int TestStarParticleInitialize(FILE *fptr, FILE *Outfptr, HierarchyEntry &TopGri /* set up uniform grid as of before explosion */ - - - if (TopGrid.GridData->InitializeUniformGrid(TestStarParticleDensity, + + + if (TopGrid.GridData->InitializeUniformGrid(TestStarParticleDensity, TestStarParticleEnergy, TestStarParticleEnergy, TestStarParticleVelocity, TestStarParticleBField) == FAIL) ENZO_FAIL("Error in InitializeUniformGrid."); - + if (TopGrid.GridData-> TestStarParticleInitializeGrid(TestStarParticleStarMass, - Initialdt, + Initialdt, TestStarParticleStarVelocity, - TestStarParticleStarPosition) == FAIL) + NumberOfTestStars, clusterRadius) == FAIL) ENZO_FAIL("Error in TestStarParticleInitializeGrid.\n"); /* set up field names and units */ - int count = 0; DataLabel[count++] = DensName; DataLabel[count++] = TEName; @@ -159,14 +161,12 @@ int TestStarParticleInitialize(FILE *fptr, FILE *Outfptr, HierarchyEntry &TopGri if (TestProblemData.UseMetallicityField) DataLabel[count++] = MetalName; - int j; for(j=0; j < count; j++) DataUnits[j] = NULL; - + /* Write parameters to parameter output file */ - if (MyProcessorNumber == ROOT_PROCESSOR) { fprintf(Outfptr, "TestStarParticleDensity = %"FSYM"\n", @@ -176,7 +176,6 @@ int TestStarParticleInitialize(FILE *fptr, FILE *Outfptr, HierarchyEntry &TopGri fprintf(Outfptr, "MetallicityField_Fraction = %"FSYM"\n", TestProblemData.MetallicityField_Fraction); } - fprintf(stderr, "TestStarParticleDensity = %"FSYM"\n", TestStarParticleDensity); fprintf(stderr, "TestStarParticleEnergy = %"FSYM"\n", @@ -185,7 +184,6 @@ int TestStarParticleInitialize(FILE *fptr, FILE *Outfptr, HierarchyEntry &TopGri TestProblemData.MetallicityField_Fraction); - return SUCCESS; } From d039490783e1effcae872db3c4fd1533be15165e Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 28 Oct 2019 12:31:33 -0700 Subject: [PATCH 026/115] debugged fringe case supernovae in low density by choosing energy as max(Nsn*1e51, eKinetic). made computational compromises for speed: winds are deposited NGP as opposed to CIC, SNe are still CIC. Star particles shut off after 500 Myr. Only one star particle forms per grid per timestep of that grid. No upper limit is placed on the amount of star formation added to new stars. Turned off critical_debug in the deposition, as it slows the code down too much with ~1k events. --- src/enzo/Grid_MechStarsCreation.C | 195 ++++++++-------- src/enzo/Grid_MechStarsDepositFeedback.C | 211 ++++++++++-------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 21 +- src/enzo/Grid_StarParticleHandler.C | 10 +- src/enzo/MechStars_determineWinds.C | 2 +- .../MechStars_transformComovingWithStar.C | 5 +- 6 files changed, 244 insertions(+), 200 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index e190cfe93..10e9ba310 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -124,105 +124,112 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float freeFallTime = 0; float dynamicalTime = 0; float Time = this->Time; - int createStar = checkCreationCriteria(BaryonField[DensNum], - totalMetal, Temperature, DMField, - BaryonField[Vel1Num], BaryonField[Vel2Num], - BaryonField[Vel3Num], - CoolingTime, GridDimension, &shieldedFraction, - &freeFallTime, &dynamicalTime, i,j,k,Time, - BaryonField[NumberOfBaryonFields], CellWidth[0][0], - &gridShouldFormStars, ¬EnoughMetals, 0, seedIndex); + int createStar = false; + /* + I limit star particle creation to 1/grid/step to + keep feedback affecting the grid region + */ + if (nCreated == 0){ + createStar = checkCreationCriteria(BaryonField[DensNum], + totalMetal, Temperature, DMField, + BaryonField[Vel1Num], BaryonField[Vel2Num], + BaryonField[Vel3Num], + CoolingTime, GridDimension, &shieldedFraction, + &freeFallTime, &dynamicalTime, i,j,k,Time, + BaryonField[NumberOfBaryonFields], CellWidth[0][0], + &gridShouldFormStars, ¬EnoughMetals, 0, seedIndex); - //if (createStar && debug) printf ("SMM Criteria passed!\n"); - if (createStar){ - int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; + //if (createStar && debug) printf ("SMM Criteria passed!\n"); + if (createStar){ + int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; - /* Determine Mass of new particle */ + /* Determine Mass of new particle */ - float MassShouldForm =(shieldedFraction * BaryonField[DensNum][index] - * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13); + float MassShouldForm =(shieldedFraction * BaryonField[DensNum][index] + * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13); - if (MassShouldForm < 0){ - printf("Negative formation mass: %f %f",shieldedFraction, freeFallTime); - continue; - } - float newMass = min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]); - if (newMass*MassUnits < StarMakerMinimumMass){ - //fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e Mmin = %e\n", - // newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits, StarMakerMinimumMass); - continue; - } - float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; - dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); - // fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); - ParticleArray->ParticleMass[nCreated] = newMass; - if (StarParticleRadiativeFeedback) - ParticleArray->ParticleAttribute[1][nCreated] = huge_number; // need infinite lifetime for radiative feedback i think? - else - ParticleArray->ParticleAttribute[1][nCreated] = 0.0; // Tracking SNE in TDP field dynamicalTime/TimeUnits; - ParticleArray->ParticleAttribute[0][nCreated] = Time; - - ParticleArray->ParticleAttribute[2][nCreated] = totalMetal[index] - /BaryonField[DensNum][index]; - if (StarMakerTypeIaSNe) - ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIaNum][index]; - - ParticleArray->ParticleType[nCreated] = PARTICLE_TYPE_STAR; - BaryonField[DensNum][index] -= newMass; - BaryonField[MetalNum][index] -= newMass*totalMetal[index]/BaryonField[DensNum][index]; - if (SNColourNum > 0) - BaryonField[SNColourNum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[SNColourNum][index]/BaryonField[DensNum][index]; - - - // type IA metal field isnt here right now - // if (StarMakerTypeIASNe) - // ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIANum]; - float vX = 0.0; - float vY = 0.0; - float vZ = 0.0; - if (HydroMethod != 0) - fprintf(stderr,"Mechanical star maker not tested for anything except HydroMethod = 0\n"); - /* average particle velocity over 125 cells to prevent runaway */ - for (int ip = i-2; ip <= i + 2 ; ip++) - for (int jp = j-2; jp <= j+2 ; jp++) - for (int kp = k-2; kp <= k+2; kp++){ - int ind = ip + jp*GridDimension[0]+kp*GridDimension[0]+GridDimension[1]; - vX += BaryonField[Vel1Num][ind]; - vY += BaryonField[Vel2Num][ind]; - vZ += BaryonField[Vel3Num][ind]; - } - float MaxVelocity = 250.*1.0e5/VelocityUnits; - ParticleArray->ParticleVelocity[0][nCreated] = (abs(vX/125.) > MaxVelocity)?(MaxVelocity*((vX > 0)?(1):(-1))):(vX/125.); - ParticleArray->ParticleVelocity[1][nCreated] = (abs(vY/125.) > MaxVelocity)?(MaxVelocity*((vY > 0)?(1):(-1))):(vY/125.); - ParticleArray->ParticleVelocity[2][nCreated] = (abs(vZ/125.) > MaxVelocity)?(MaxVelocity*((vZ > 0)?(1):(-1))):(vZ/125.);; - - /* give it position at center of host cell */ - - ParticleArray->ParticlePosition[0][nCreated] = CellLeftEdge[0][0] - +(dx*(float(i)+0.5)); - ParticleArray->ParticlePosition[1][nCreated] = CellLeftEdge[1][0] - +(dx*(float(j)+0.5)); - ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] - +(dx*(float(k)+0.5)); - if (nCreated >= MaximumNumberOfNewParticles) return nCreated; - if (true) - fprintf(stdout,"Created star: [%f] %e %e ::: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", - Time*TimeUnits/3.1557e13,BaryonField[DensNum][index], - BaryonField[DensNum][index]*MassUnits, level, nCreated+1, - ParticleArray->ParticleType[nCreated], - ParticleArray->ParticleMass[nCreated]*MassUnits, - ParticleArray->ParticleAttribute[0][nCreated], - ParticleArray->ParticleAttribute[1][nCreated], - ParticleArray->ParticleAttribute[2][nCreated], - ParticleArray->ParticlePosition[0][nCreated], - ParticleArray->ParticlePosition[1][nCreated], - ParticleArray->ParticlePosition[2][nCreated], - ParticleArray->ParticleVelocity[0][nCreated]*VelocityUnits/1e5, - ParticleArray->ParticleVelocity[1][nCreated]*VelocityUnits/1e5, - ParticleArray->ParticleVelocity[2][nCreated]*VelocityUnits/1e5, - index, GridDimension[0]*GridDimension[2]*GridDimension[3], i,j,k); - nCreated ++; + if (MassShouldForm < 0){ + printf("Negative formation mass: %f %f",shieldedFraction, freeFallTime); + continue; + } + float newMass = min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]); + if (newMass*MassUnits < StarMakerMinimumMass){ + //fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e Mmin = %e\n", + // newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits, StarMakerMinimumMass); + continue; + } + float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; + dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); + // fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); + ParticleArray->ParticleMass[nCreated] = newMass; + if (StarParticleRadiativeFeedback) + ParticleArray->ParticleAttribute[1][nCreated] = huge_number; // need infinite lifetime for radiative feedback i think? + else + ParticleArray->ParticleAttribute[1][nCreated] = 0.0; // Tracking SNE in TDP field dynamicalTime/TimeUnits; + ParticleArray->ParticleAttribute[0][nCreated] = Time; + + ParticleArray->ParticleAttribute[2][nCreated] = totalMetal[index] + /BaryonField[DensNum][index]; + if (StarMakerTypeIaSNe) + ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIaNum][index]; + + ParticleArray->ParticleType[nCreated] = PARTICLE_TYPE_STAR; + BaryonField[DensNum][index] -= newMass; + BaryonField[MetalNum][index] -= newMass*totalMetal[index]/BaryonField[DensNum][index]; + if (SNColourNum > 0) + BaryonField[SNColourNum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[SNColourNum][index]/BaryonField[DensNum][index]; + + + // type IA metal field isnt here right now + // if (StarMakerTypeIASNe) + // ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIANum]; + float vX = 0.0; + float vY = 0.0; + float vZ = 0.0; + if (HydroMethod != 0) + fprintf(stderr,"Mechanical star maker not tested for anything except HydroMethod = 0\n"); + /* average particle velocity over 125 cells to prevent runaway */ + for (int ip = i-2; ip <= i + 2 ; ip++) + for (int jp = j-2; jp <= j+2 ; jp++) + for (int kp = k-2; kp <= k+2; kp++){ + int ind = ip + jp*GridDimension[0]+kp*GridDimension[0]+GridDimension[1]; + vX += BaryonField[Vel1Num][ind]; + vY += BaryonField[Vel2Num][ind]; + vZ += BaryonField[Vel3Num][ind]; + } + float MaxVelocity = 250.*1.0e5/VelocityUnits; + ParticleArray->ParticleVelocity[0][nCreated] = (abs(vX/125.) > MaxVelocity)?(MaxVelocity*((vX > 0)?(1):(-1))):(vX/125.); + ParticleArray->ParticleVelocity[1][nCreated] = (abs(vY/125.) > MaxVelocity)?(MaxVelocity*((vY > 0)?(1):(-1))):(vY/125.); + ParticleArray->ParticleVelocity[2][nCreated] = (abs(vZ/125.) > MaxVelocity)?(MaxVelocity*((vZ > 0)?(1):(-1))):(vZ/125.);; + + /* give it position at center of host cell */ + + ParticleArray->ParticlePosition[0][nCreated] = CellLeftEdge[0][0] + +(dx*(float(i)+0.5)); + ParticleArray->ParticlePosition[1][nCreated] = CellLeftEdge[1][0] + +(dx*(float(j)+0.5)); + ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] + +(dx*(float(k)+0.5)); + if (nCreated >= MaximumNumberOfNewParticles) return nCreated; + if (true) + fprintf(stdout,"Created star: [%f] %e %e ::: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", + Time*TimeUnits/3.1557e13,BaryonField[DensNum][index], + BaryonField[DensNum][index]*MassUnits, level, nCreated+1, + ParticleArray->ParticleType[nCreated], + ParticleArray->ParticleMass[nCreated]*MassUnits, + ParticleArray->ParticleAttribute[0][nCreated], + ParticleArray->ParticleAttribute[1][nCreated], + ParticleArray->ParticleAttribute[2][nCreated], + ParticleArray->ParticlePosition[0][nCreated], + ParticleArray->ParticlePosition[1][nCreated], + ParticleArray->ParticlePosition[2][nCreated], + ParticleArray->ParticleVelocity[0][nCreated]*VelocityUnits/1e5, + ParticleArray->ParticleVelocity[1][nCreated]*VelocityUnits/1e5, + ParticleArray->ParticleVelocity[2][nCreated]*VelocityUnits/1e5, + index, GridDimension[0]*GridDimension[2]*GridDimension[3], i,j,k); + nCreated ++; + } //end if (nCreated == 0) } }//end for k }//end for j diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 458a91dcd..948d54f6c 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -48,8 +48,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, Each vertex particle will then be CIC deposited to the grid! */ //printf("In Feedback deposition\n"); - bool debug = true; - bool criticalDebug = true; + bool debug = false; + bool criticalDebug = false; bool printout = debug && !winds; int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; if (printout) printf("Host index = %d\n", index); @@ -109,7 +109,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* set other units that we need */ MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; //Msun! float EnergyUnits = DensityUnits*pow(LengthUnits*dx, 3) - * VelocityUnits*VelocityUnits;//[g cm^2/s^2] -> code_energy + * pow(LengthUnits/TimeUnits, 2.0);//[g cm^2/s^2] -> code_energy float MomentaUnits = MassUnits*VelocityUnits; /* Make copys of pointers fields to work with (theyre just easier to type!). */ @@ -189,14 +189,18 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, weightsSum += weightsVector[wind]; } for (int wind = 0; wind < nCouple; wind++){ - weightsVector[wind] = weightsSum; + weightsVector[wind] /= weightsSum; + if (weightsVector[wind] == 0 || isnan(weightsVector[wind])){ + ENZO_FAIL("NaN weight Vector!") + } } /* transform to comoving with the star and take velocities to momenta. Take Energy densities to energy */ - transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], + if (!winds) + transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], BaryonField[TENum], BaryonField[GENum], @@ -215,9 +219,9 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, nmean += BaryonField[DensNum][index+GridDimension[0]*ind]*DensityUnits; nmean += BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]*DensityUnits; - mu_mean += muField[index+ind]; - mu_mean += muField[index+GridDimension[0]*ind]; - mu_mean += muField[index+GridDimension[0]*GridDimension[1]*ind]; + // mu_mean += muField[index+ind]; + // mu_mean += muField[index+GridDimension[0]*ind]; + // mu_mean += muField[index+GridDimension[0]*GridDimension[1]*ind]; dmean += BaryonField[DensNum][index+ind]; dmean += BaryonField[DensNum][index+GridDimension[0]*ind]; @@ -247,13 +251,12 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, } vmean = sqrt(vmean)/27.0*VelocityUnits; // cm/s! zmean /= (27.0); - mu_mean/= (dmean); + // mu_mean/= (dmean); // if (abs(mu_mean) > 10){ // mu_mean = 0.6; // } - nmean /= (mu_mean*mh); dmean = dmean*DensityUnits/(27.); - nmean = dmean/mh*mu_mean; + nmean = max(0.01, dmean/mh); //nmean = max(nmean, 1e-1); //if (debug) printf ("Zmean = %e Dmean = %e mu_mean = %e ", zmean, dmean, mu_mean); //if (debug) printf ("Nmean = %f vmean = %f\n", nmean, vmean/1e5); @@ -312,12 +315,13 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, if (cellwidth < r_free){ coupledMomenta = p_free; if(printout)fprintf(stdout, "Coupling free expansion\n");} - if (cellwidth > r_free && cellwidth < r_shellform){ - coupledMomenta = min(p_sedov, p_shellform*cellwidth/r_shellform); - if(printout)fprintf(stdout, "Coupling S-T phase\n");} - if (cellwidth > r_shellform && cellwidth < CoolingRadius){ - coupledMomenta = min(p_shellform+(cellwidth-r_shellform)*(pTerminal-p_shellform)/(CoolingRadius-r_shellform), pTerminal); - if(printout)fprintf(stdout, "Coupling shell-forming stage\n");} + if (cellwidth > r_free && cellwidth < CoolingRadius){ + coupledMomenta = min(p_sedov, pTerminal); + if(printout)fprintf(stdout, "Coupling S-T phase\n"); + } + // if (cellwidth > r_shellform && cellwidth < CoolingRadius){ + // coupledMomenta = min(p_shellform+(cellwidth-r_shellform)*(pTerminal-p_shellform)/(CoolingRadius-r_shellform), pTerminal); + // if(printout)fprintf(stdout, "Coupling shell-forming stage\n");} if (cellwidth > CoolingRadius){ coupledMomenta = pTerminal; if(printout)fprintf(stdout, "Coupling terminal momenta\n");} @@ -353,7 +357,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, shellMass = max(8e3, coupledMomenta/shellVelocity); //Msun /* cant let host cells evacuate completely! - Shell mass will be evacuated from central cells by CIC a negative mass, + 7.974045e+017.974045e+017.974045e+017.974045e+017.974045e+01 Shell mass will be evacuated from central cells by CIC a negative mass, so have to check that the neighbors can handle it too*/ for (int ind = -1; ind<=1; ind++){ float minD = min(BaryonField[DensNum][index+ind],BaryonField[DensNum][index+GridDimension[0]*ind]); @@ -386,10 +390,11 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, coupledGasEnergy = (DepositUnresolvedEnergyAsThermal) ?(coupledGasEnergy) :(coupledGasEnergy*pow(dxRatio, -6.5)); - + if (winds) coupledGasEnergy = ejectaEnergy; float shellMetals = zZsun*0.02 * shellMass; float coupledMetals = 0.0, SNIAmetals = 0.0, SNIImetals = 0.0, P3metals = 0.0; if (winds) coupledMetals = ejectaMetal ;//+ shellMetals; // winds only couple to metallicity + if (AnalyticSNRShellMass) coupledMetals += shellMetals; SNIAmetals = (StarMakerTypeIaSNe) ? nSNIA * 1.4 : 0.0; if (!StarMakerTypeIaSNe) coupledMetals += nSNIA*1.4; @@ -409,7 +414,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0, preZII=0, preZIa = 0; float dsum = 0.0, zsum=0.0, psum=0.0, psqsum =0.0, tesum=0.0, gesum=0.0, kesum=0.0; float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0, postZII=0, postZIa = 0; - if (criticalDebug && !winds){ + if (criticalDebug){ for (int i=0; i 0 && DualEnergyFormalism ){ + if (pX != 0.0){ + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np,&pX, &u[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + } + if (pY != 0.0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&pY, &v[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (pZ != 0.0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&pZ, &w[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (eCouple > 0 && DualEnergyFormalism ){ + if (geCouple > 0) + eCouple += geCouple; + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&eCouple, BaryonField[TENum], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + } if (geCouple > 0) - eCouple += geCouple; - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&eCouple, BaryonField[TENum], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - } - if (geCouple > 0) - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&geCouple, BaryonField[GENum], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (StarMakerTypeIISNeMetalField && zIICouple > 0.0) - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&zIICouple, metalsII, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (StarMakerTypeIaSNe && zIACouple > 0.0) - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&zIACouple, metalsIA, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (MechStarsSeedField && p3Couple > 0.0){ - //if (printout)printf("Coupling %f to pIII metals %d\n",p3Couple*MassUnits, n); - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&p3Couple, metalsIII, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&geCouple, BaryonField[GENum], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (StarMakerTypeIISNeMetalField && zIICouple > 0.0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&zIICouple, metalsII, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (StarMakerTypeIaSNe && zIACouple > 0.0) + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&zIACouple, metalsIA, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (MechStarsSeedField && p3Couple > 0.0){ + //if (printout)printf("Coupling %f to pIII metals %d\n",p3Couple*MassUnits, n); + FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank,&np,&p3Couple, metalsIII, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + } } } // printf("\n"); @@ -519,15 +534,28 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, shellMetals *= -1/MassUnits; FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMetals, &metals[0], LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - - if (criticalDebug && !winds){ + /* + Lots of wind calculations make CIC take too much time, so direct deposit + to the host cell. Doing this also allows us to skip the comoving transformation since + the momentum goes uncoupled. Since the cooling radius is so small for wind enrgy (~10^15 erg), + this is totally appropriate for simulations with dx > 0.25pccm or so. + */ + if (winds){ + float dm = coupledMass/(density[index]+coupledMass); + density[index] += coupledMass; + metals[index] += coupledMetals; + BaryonField[TENum][index] += dm*coupledEnergy/coupledMass; + BaryonField[GENum][index] += dm*coupledEnergy/coupledMass; + } + + if (criticalDebug){ for (int i = 0; i< size ; i++){ postMass += BaryonField[DensNum][i]; postZ += BaryonField[MetalNum][i]; - if (MetalIINum > 0) + if (StarMakerTypeIISNeMetalField) postZII += BaryonField[MetalIINum][i]; - if (MetalIaNum > 0) + if (StarMakerTypeIaSNe) postZIa += BaryonField[MetalIaNum][i]; if (SNColourNum > 0) postZ += BaryonField[SNColourNum][i]; postP += BaryonField[Vel1Num][i]+BaryonField[Vel2Num][i]+BaryonField[Vel3Num][i]; @@ -537,7 +565,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, postTE += BaryonField[TENum][i]; postGE += BaryonField[GENum][i]; } - fprintf(stderr, "Difference quantities: dxRatio = %f dMass = %e dZ = %e dzII = %e dxIa = %e P = %e |P| = %e TE = %e GE = %e coupledGE = %e Ej = %e Mej = %e Zej = %e\n", + if (printout) + fprintf(stderr, "Difference quantities: dxRatio = %f dMass = %e dZ = %e dzII = %e dxIa = %e P = %e |P| = %e TE = %e GE = %e coupledGE = %e Ej = %e Mej = %e Zej = %e\n", dxRatio, (postMass-preMass)*MassUnits, (postZ-preZ)*MassUnits, (postZII-preZII)*MassUnits, (postZIa-preZIa)*MassUnits, (postP - preP)*MomentaUnits, @@ -546,16 +575,20 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, coupledGasEnergy*EnergyUnits, ejectaEnergy, ejectaMass, ejectaMetal); if(isnan(postMass) || isnan(postTE) || isnan(postPmag) || isnan(postZ)){ - fprintf(stderr, "NAN IN GRID: %e %e %e %e\n", postMass, postTE, postZ, postP); + fprintf(stderr, "NAN IN GRID: %f %e %e %e-%e %e\n", postMass, postTE, postZ, preZ, postP); + for (float w: weightsVector){ + fprintf(stderr, "%e\t", w); + } + fprintf(stderr, "\n"); + exit(3); ENZO_FAIL("MechStars_depositFeedback.C: 530\n") - if (postGE-preGE < 0.0) - ENZO_FAIL("471"); + } } /* Transform the grid back */ - - transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], + if (!winds) + transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num], BaryonField[Vel3Num], diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index a38776016..eae51da47 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -116,8 +116,10 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta for (int pIndex=0; pIndex < NumberOfParticles; pIndex++){ if (ParticleType[pIndex] == PARTICLE_TYPE_STAR - && ParticleMass[pIndex] > 0.0 + && ParticleMass[pIndex] > 100.0 && ParticleAttribute[0][pIndex] > 0.0){ + FLOAT age = (Time-ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13;// Myr + if (age > 500) continue; c++; /* get index of cell hosting particle */ @@ -133,7 +135,6 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta /* error check particle position; Cant be on the border or outside grid If on border, reposition to within grid for CIC deposit */ - FLOAT age = (Time-ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13;// Myr float gridDx = GridDimension[0]*dx; float gridDy = GridDimension[1]*dx; @@ -182,14 +183,14 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta zp = CellLeftEdge[2][0]+gridDx-borderDx-0.5*dx; shifted = 1; } - if (shifted > 0){ - if (debug) - fprintf(stderr, "Particle position shifted away from edge: %e: %f %f %f\n%f %f %f\n", - age,xp, yp, zp, CellLeftEdge[0][0]+borderDx, CellLeftEdge[1][0]+borderDx, CellLeftEdge[2][0]+borderDx); - int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; - int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; - int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; - } + // if (shifted > 0){ + // if (debug) + // fprintf(stderr, "Particle position shifted away from edge: %e: %f %f %f\n%f %f %f\n", + // age,xp, yp, zp, CellLeftEdge[0][0]+borderDx, CellLeftEdge[1][0]+borderDx, CellLeftEdge[2][0]+borderDx); + // int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; + // int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; + // int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; + // } /* Check for continual formation. Continually forming new mass allows the star particle count to stay lower, ultimately reducing runtime by having fewer particles to iterate. diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index 5bc01cb2b..5e508dafc 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -1585,14 +1585,14 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, HMNum, H2INum, H2IINum, DINum, DIINum, HDINum) == FAIL) { ENZO_FAIL("Error in grid->IdentifySpeciesFields.\n"); } - - mu_field[index] = BaryonField[DeNum][index] + BaryonField[HINum][index] + BaryonField[HIINum][index] + - (BaryonField[HeINum][index] + BaryonField[HeIINum][index] + BaryonField[HeIIINum][index])/4.0; + float mult = 1.0/BaryonField[DensNum][index]; + mu_field[index] = BaryonField[DeNum][index]*mult + BaryonField[HINum][index]*mult + BaryonField[HIINum][index]*mult + + (BaryonField[HeINum][index]*mult + BaryonField[HeIINum][index]*mult + BaryonField[HeIIINum][index]*mult)/4.0; if (MultiSpecies > 1) { - mu_field[index] += BaryonField[HMNum][index] + (BaryonField[H2INum][index] + BaryonField[H2IINum][index])/2.0; + mu_field[index] += BaryonField[HMNum][index]*mult + (BaryonField[H2INum][index]*mult + BaryonField[H2IINum][index]*mult)/2.0; } if (MultiSpecies > 2) { - mu_field[index] += (BaryonField[DINum][index] + BaryonField[DIINum][index])/2.0 + (BaryonField[HDINum][index]/3.0); + mu_field[index] += (BaryonField[DINum][index]*mult + BaryonField[DIINum][index]*mult)/2.0 + (BaryonField[HDINum][index]*mult/3.0); } } diff --git a/src/enzo/MechStars_determineWinds.C b/src/enzo/MechStars_determineWinds.C index 966dc064a..5f30a0693 100644 --- a/src/enzo/MechStars_determineWinds.C +++ b/src/enzo/MechStars_determineWinds.C @@ -55,7 +55,7 @@ int determineWinds(float age, float* eWinds, float* mWinds, float* zWinds, windM, massMsun, age, zZsun); windM = 0.125*massMsun; // limit loss to huge if necessary. } - windZ = max(zZsun, 0.016+0.0041*max(zZsun, 1.65)+0.0118)*windM; + windZ = max(0.02, 0.016+0.0041*max(zZsun, 1.65)+0.0118)*windM; windE = e_factor * 1e12 * windM; //fprintf(stdout, "Age = %e Ewinds = %e Mwinds = %e Zwinds = %e Zsun = %e\n", // age, windE, windM, windZ, zZsun); diff --git a/src/enzo/MechStars_transformComovingWithStar.C b/src/enzo/MechStars_transformComovingWithStar.C index 65c855928..45ab26d5a 100644 --- a/src/enzo/MechStars_transformComovingWithStar.C +++ b/src/enzo/MechStars_transformComovingWithStar.C @@ -13,7 +13,10 @@ int transformComovingWithStar(float* Density, float* Metals, int sizeX, int sizeY, int sizeZ, int direction){ /* transform velocities to momenta or back and make them comoving with the star particle - Metals are still densities here for CIC deposition + Metals are still densities here for CIC deposition. NB Metal transform to + fractions in Grid_StarParticleHandler is skipped for this method. Energy fields + are transformed from specific energy to just energy to facilitate CIC deposition + */ int size = sizeX*sizeY*sizeZ; if (direction > 0){ From 13ed1716d01fcc6f6f29ce7c3ed4274b0c205bed Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 28 Oct 2019 13:12:48 -0700 Subject: [PATCH 027/115] removed max age on stars; put in resolution check to determine whether winds are deposited NGP or CIC --- src/enzo/Grid_MechStarsDepositFeedback.C | 14 +++++++------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 948d54f6c..353dfb19a 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -197,9 +197,9 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* transform to comoving with the star and take velocities to momenta. - Take Energy densities to energy + Take Energy densities to energy. winds are ngp unless VERY high resolution */ - if (!winds) + if (!winds || dx*LengthUnits/pc_cm < 0.1) transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], @@ -456,9 +456,9 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float eCouple, geCouple, mCouple, zCouple, zIICouple, zIACouple, p3Couple; /* As a computational compromize, supernova are deposited CIC, but winds are - deposited NGP + deposited NGP. At VERY high resolution, well still do CIC for winds */ - if (!winds){ + if (!winds || dx*LengthUnits/pc_cm < 0.1){ for (int n = 0; n < nCouple; ++n){ pX = coupledMomenta*CloudParticleVectorX[n]*weightsVector[n]; pY = coupledMomenta*CloudParticleVectorY[n]*weightsVector[n]; @@ -541,7 +541,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, the momentum goes uncoupled. Since the cooling radius is so small for wind enrgy (~10^15 erg), this is totally appropriate for simulations with dx > 0.25pccm or so. */ - if (winds){ + if (winds && dx*LengthUnits/pc_cm > 0.1){ float dm = coupledMass/(density[index]+coupledMass); density[index] += coupledMass; metals[index] += coupledMetals; @@ -586,8 +586,8 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, } } - /* Transform the grid back */ - if (!winds) + /* Transform the grid back. Skip for winds, unless VERY high resolution*/ + if (!winds || dx*LengthUnits/pc_cm < 0.1) transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num], diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index eae51da47..5e4695782 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -119,7 +119,7 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta && ParticleMass[pIndex] > 100.0 && ParticleAttribute[0][pIndex] > 0.0){ FLOAT age = (Time-ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13;// Myr - if (age > 500) continue; + //if (age > 1000) continue; c++; /* get index of cell hosting particle */ From b0324c1ab4205e86012540a9fa3f278cafcef6d3 Mon Sep 17 00:00:00 2001 From: John Regan Date: Tue, 29 Oct 2019 09:43:13 +0000 Subject: [PATCH 028/115] Updating SS with minor enhancements --- src/enzo/ActiveParticle_SmartStar.C | 80 ++++++++++++++------- src/enzo/ActiveParticle_SmartStar.h | 4 +- src/enzo/DetermineSEDParameters.C | 1 - src/enzo/EvolveLevel.C | 3 +- src/enzo/Grid_Shine.C | 4 ++ src/enzo/RadiativeTransferParameters.h | 4 ++ src/enzo/RadiativeTransferReadParameters.C | 3 + src/enzo/RadiativeTransferWriteParameters.C | 2 + src/enzo/ReadParameterFile.C | 8 +-- 9 files changed, 75 insertions(+), 34 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index f7f6c24a0..9be165611 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -14,7 +14,7 @@ #define DYNAMIC_ACCRETION_RADIUS 0 #define BONDIHOYLERADIUS 0 -#define MINIMUMPOTENTIAL 0 +#define MINIMUMPOTENTIAL 1 #define CALCDIRECTPOTENTIAL 0 #define JEANSREFINEMENT 1 #define MASSTHRESHOLDCHECK 1 @@ -211,8 +211,8 @@ int ActiveParticleType_SmartStar::EvaluateFormation mass = density[index]*dx*dx*dx; #if SSDEBUG - //fprintf(stdout, "%s: Excellent! Density threshold exceeeded - density = %g cm^-3\n", - // __FUNCTION__, density[index]*data.DensityUnits/mh); + fprintf(stdout, "%s: Excellent! Density threshold exceeeded - density = %g cm^-3\n", + __FUNCTION__, density[index]*data.DensityUnits/mh); #endif /* 3. Negative divergence: For ZEUS, the velocities are face-centered, and all of the other routines have @@ -231,13 +231,21 @@ int ActiveParticleType_SmartStar::EvaluateFormation } /* All three components must be negative to pass the test */ if (divx > 0.0 || divy > 0.0 || divz > 0.0) continue; +#if SSDEBUG + fprintf(stdout, "%s: Negative Divergence passed\n", __FUNCTION__); +#endif + /* We now need to define a control volume - this is the region within an accretion radius of the cell identified */ centralpos[0] = thisGrid->CellLeftEdge[0][i] + 0.5*thisGrid->CellWidth[0][i]; centralpos[1] = thisGrid->CellLeftEdge[1][j] + 0.5*thisGrid->CellWidth[1][j]; centralpos[2] = thisGrid->CellLeftEdge[2][k] + 0.5*thisGrid->CellWidth[2][k]; - + #if COOLING_TIME +#if SSDEBUG + fprintf(stdout, "%s: Calculate cooling time\n", __FUNCTION__); +#endif + // 4. t_cool < t_freefall (skip if T > 11000 K) dtot = ( density[index] + data.DarkMatterDensity[index] ) * data.DensityUnits; @@ -246,14 +254,19 @@ int ActiveParticleType_SmartStar::EvaluateFormation data.Temperature[index] > 1.1e4) continue; #endif + #if MASSTHRESHOLDCHECK +#if SSDEBUG + fprintf(stdout, "%s: Calculate Mass Threshold Check\n", __FUNCTION__); +#endif + TotalMass = thisGrid->FindMassinGrid(data.DensNum); /* Mass Threshold check */ /* The control region should contain a mass greater than the mass threshold */ if(TotalMass*ConverttoSolar < (double)MASSTHRESHOLD) { continue; } -#if SSDEBUG_TOTALMASS +#if SSDEBUG printf("%s: Total Mass in Accretion Region = %g Msolar (Threshold = %g)\n", __FUNCTION__, TotalMass*ConverttoSolar, (double)MASSTHRESHOLD); #endif @@ -265,6 +278,10 @@ int ActiveParticleType_SmartStar::EvaluateFormation thisGrid->CalculatePotentialField(PotentialField, data.DensNum, data.DensityUnits, data.TimeUnits,data.LengthUnits); } #endif +#if SSDEBUG + fprintf(stdout, "%s: Calculate Gravitational Potential\n", __FUNCTION__); +#endif + /* 4. Gravitational Minimum Check */ /* * Find the minimum of the potential over a Jeans Length. @@ -324,18 +341,14 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->pos[1] = thisGrid->CellLeftEdge[1][j] + 0.5*thisGrid->CellWidth[1][j]; np->pos[2] = thisGrid->CellLeftEdge[2][k] + 0.5*thisGrid->CellWidth[2][k]; - if (HydroMethod == PPM_DirectEuler) { - np->vel[0] = velx[index]; - np->vel[1] = vely[index]; - np->vel[2] = velz[index]; - } - else if (HydroMethod == Zeus_Hydro) { - np->vel[0] = 0.5 * (velx[index] + velx[index+offset[0]]); - np->vel[1] = 0.5 * (vely[index] + vely[index+offset[1]]); - np->vel[2] = 0.5 * (velz[index] + velz[index+offset[2]]); - } else { - ENZO_FAIL("SmartStar does not support RK Hydro or RK MHD"); - } + float *apvel = new float[MAX_DIMENSION]; + /* Calculate AP velocity by taking average of + * surrounding cells + */ + apvel = thisGrid->AveragedVelocityAtCell(index, data.DensNum, data.Vel1Num); + np->vel[0] = apvel[0]; + np->vel[1] = apvel[1]; + np->vel[2] = apvel[2]; if (HasMetalField) np->Metallicity = data.TotalMetals[index]; @@ -614,7 +627,7 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel double MassConversion; const double LConv = (double) TimeUnits / pow(LengthUnits,3); const double mfactor = double(MassUnits) / SolarMass; - + ActiveParticleType_SmartStar *ThisParticle = NULL; for (ipart = 0; ipart < nParticles; ipart++) { if (SmartStarList[ipart]->IsARadiationSource(Time)) { @@ -627,16 +640,29 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel if( (ThisParticle->ParticleClass == POPIII || ThisParticle->ParticleClass == SMS) && SmartStarStellarRadiativeFeedback == FALSE) continue; //No stellar radiative feedback - - source = ThisParticle->RadiationSourceInitialize(); dx = LevelArray[ThisParticle->level]->GridData->GetCellWidth(0,0); - MassConversion = (float) (dx*dx*dx * mfactor); //Converts to Solar Masses + MassConversion = (double) (dx*dx*dx * mfactor); //Converts to Solar Masses + source = ThisParticle->RadiationSourceInitialize(); + double PMass = 0.0; + if(POPIII == ThisParticle->ParticleClass) { + FLOAT Time = LevelArray[ThisParticle->level]->GridData->ReturnTime(); + float Age = (Time - ThisParticle->BirthTime)*TimeUnits/yr_s; + PMass = min(ThisParticle->Mass*MassConversion, 4000000.0); //cap lum mass at 40 Msolar +#if SSDEBUG + printf("%s: Star Mass set to %f Msolar from %f Msolar for Particle Class %d. " \ + "Age = %f kyrs\n", + __FUNCTION__, PMass, + ThisParticle->Mass*MassConversion, ThisParticle->ParticleClass, Age/1000.0); +#endif + } + else + PMass = ThisParticle->Mass*MassConversion; + /* Call Function to return SED parameters */ if(DetermineSEDParameters(ThisParticle, Time, dx) == FAIL) return FAIL; source->LifeTime = RadiationLifetime; - source->Luminosity = (ThisParticle->LuminosityPerSolarMass * LConv) * - (ThisParticle->Mass * MassConversion); + source->Luminosity = (ThisParticle->LuminosityPerSolarMass * LConv) * PMass; source->EnergyBins = RadiationSEDNumberOfBins; source->Energy = new float[RadiationSEDNumberOfBins]; source->SED = new float[RadiationSEDNumberOfBins]; @@ -645,12 +671,12 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel source->SED[j] = ThisParticle->RadiationSED[j]; } #if SSDEBUG - if(ThisParticle->ParticleClass == BH) { + if(ThisParticle->ParticleClass == SMS) { printf("%s: !!!!!!!!!!!!!!!!!!!!!!!!SRC Luminosity: L=%lg Lcode=%g M=%g Mcode=%g\n", __FUNCTION__, ThisParticle->LuminosityPerSolarMass * ThisParticle->Mass * MassConversion, source->Luminosity, ThisParticle->Mass * MassConversion, ThisParticle->Mass); printf("TimeIndex = %d\n", ThisParticle->TimeIndex); - printf("%s: BH Mass = %e Msolar AccretionRate = %e Msolar/yr\n", __FUNCTION__, + printf("%s: SMS Mass = %e Msolar AccretionRate = %e Msolar/yr\n", __FUNCTION__, ThisParticle->Mass * MassConversion, (ThisParticle->AccretionRate[ThisParticle->TimeIndex]*MassConversion/TimeUnits)*yr_s); printf("%s: ParticleClass = %d\t SEDs = [%f, %f, %f, %f, %f]\n", __FUNCTION__, @@ -985,7 +1011,9 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, } } } - +#if SSDEBUG + printf("Done in %s\n", __FUNCTION__); +#endif return SUCCESS; } diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 0bdc6bd18..3754bea10 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -379,8 +379,8 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( ParticleList.clear(); - if (debug) - printf("Number of particles after merging: %"ISYM"\n",NumberOfMergedParticles); + //if (debug) + // printf("Number of particles after merging: %"ISYM"\n",NumberOfMergedParticles); /* Assign local particles to grids */ diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index 9c1acc837..3143f55bf 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -11,7 +11,6 @@ float PopIIIEnergyBins[NUMRADIATIONBINS] = {2.0, 12.8, 14.0, 25.0, 200.0}; float PopIIISEDFracBins[NUMRADIATIONBINS] = {0.3261, 0.1073, 0.3686, 0.1965, 0.0}; -//float PopIIISEDFracBins[NUMRADIATIONBINS] = {0.3261, 0.1073, 0.0, 0.0, 0.0}; float SMSEnergyBins[NUMRADIATIONBINS] = {2.0, 12.8, 14.0, 25.0, 200.0}; float SMSSEDFracBins[NUMRADIATIONBINS] = {0.9992, 0.0008, 0.0, 0.0, 0.0}; float BHEnergyBins[NUMRADIATIONBINS] = {2.0, 12.8, 19.1, 217.3, 5190.0}; diff --git a/src/enzo/EvolveLevel.C b/src/enzo/EvolveLevel.C index c918fcbdd..0a07e45a3 100644 --- a/src/enzo/EvolveLevel.C +++ b/src/enzo/EvolveLevel.C @@ -743,9 +743,10 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], if (UseMagneticSupernovaFeedback) Grids[grid1]->GridData->MagneticSupernovaList.clear(); + } //end loop over grids ActiveParticleFinalize(Grids, MetaData, NumberOfGrids, LevelArray, level, NumberOfNewActiveParticles); - } //end loop over grids + /* Finalize (accretion, feedback, etc.) star particles */ StarParticleFinalize(Grids, MetaData, NumberOfGrids, LevelArray, diff --git a/src/enzo/Grid_Shine.C b/src/enzo/Grid_Shine.C index 2f7341f77..923a1c5ea 100644 --- a/src/enzo/Grid_Shine.C +++ b/src/enzo/Grid_Shine.C @@ -151,6 +151,10 @@ int grid::Shine(RadiationSourceEntry *RadiationSource) if(RS->Energy[ebin] <= 13.6 && RadiativeTransferOpticallyThinH2 == 1) continue; + /* If we slected no ionising radiation */ + if(RadiativeTransferNoIonisingRadiation == 1 && RS->Energy[ebin] >= 13.6) + continue; + photons_per_package = RampPercent * RS->Luminosity * RS->SED[ebin] * dtPhoton / float(BasePackages); diff --git a/src/enzo/RadiativeTransferParameters.h b/src/enzo/RadiativeTransferParameters.h index e637964ec..7cd9636b7 100644 --- a/src/enzo/RadiativeTransferParameters.h +++ b/src/enzo/RadiativeTransferParameters.h @@ -66,6 +66,10 @@ EXTERN float RadiationPressureScale; EXTERN int RadiativeTransferOpticallyThinH2; +/* Flag to constrain radiation to less than 13.6 eV*/ + +EXTERN int RadiativeTransferNoIonisingRadiation; + /* Sets the characteristic length for the self-shielding of Lyman-Werner Radiation */ EXTERN float RadiativeTransferOpticallyThinH2CharLength; diff --git a/src/enzo/RadiativeTransferReadParameters.C b/src/enzo/RadiativeTransferReadParameters.C index 93e27c32a..1bdae2012 100644 --- a/src/enzo/RadiativeTransferReadParameters.C +++ b/src/enzo/RadiativeTransferReadParameters.C @@ -55,6 +55,7 @@ int RadiativeTransferReadParameters(FILE *fptr) RadiativeTransferCoupledRateSolver = TRUE; RadiativeTransferOpticallyThinH2 = TRUE; RadiativeTransferOpticallyThinH2CharLength = 0.25; + RadiativeTransferNoIonisingRadiation = FALSE; RadiativeTransferFluxBackgroundLimit = 0.01; RadiativeTransferSplitPhotonRadius = FLOAT_UNDEFINED; // kpc RadiativeTransferRaysPerCell = 5.1; @@ -107,6 +108,8 @@ int RadiativeTransferReadParameters(FILE *fptr) &RadiativeTransferOpticallyThinH2); ret += sscanf(line, "RadiativeTransferOpticallyThinH2CharLength = %"FSYM, &RadiativeTransferOpticallyThinH2CharLength); + ret += sscanf(line, "RadiativeTransferNoIonisingRadiation = %"ISYM, + &RadiativeTransferNoIonisingRadiation); ret += sscanf(line, "RadiativeTransferPeriodicBoundary = %"ISYM, &RadiativeTransferPeriodicBoundary); ret += sscanf(line, "RadiativeTransferSplitPhotonRadius = %"FSYM, diff --git a/src/enzo/RadiativeTransferWriteParameters.C b/src/enzo/RadiativeTransferWriteParameters.C index 9c1df990e..d28d8615d 100644 --- a/src/enzo/RadiativeTransferWriteParameters.C +++ b/src/enzo/RadiativeTransferWriteParameters.C @@ -45,6 +45,8 @@ int RadiativeTransferWriteParameters(FILE *fptr) RadiativeTransferOpticallyThinH2); fprintf(fptr, "RadiativeTransferOpticallyThinH2CharLength = %"GOUTSYM"\n", RadiativeTransferOpticallyThinH2CharLength); + fprintf(fptr, "RadiativeTransferNoIonisingRadiation = %"ISYM"\n", + RadiativeTransferNoIonisingRadiation); fprintf(fptr, "RadiativeTransferFLDCallOnLevel = %"ISYM"\n", RadiativeTransferFLDCallOnLevel); fprintf(fptr, "RadiativeTransferPeriodicBoundary = %"ISYM"\n", diff --git a/src/enzo/ReadParameterFile.C b/src/enzo/ReadParameterFile.C index c11c146fe..660356c76 100644 --- a/src/enzo/ReadParameterFile.C +++ b/src/enzo/ReadParameterFile.C @@ -1769,10 +1769,10 @@ int ReadParameterFile(FILE *fptr, TopGridData &MetaData, float *Initialdt) grackle_data->HydrogenFractionByMass = (double) CoolData.HydrogenFractionByMass; grackle_data->DeuteriumToHydrogenRatio = (double) CoolData.DeuteriumToHydrogenRatio; grackle_data->SolarMetalFractionByMass = (double) CoolData.SolarMetalFractionByMass; - grackle_data->UVbackground_redshift_on = (double) CoolData.RadiationRedshiftOn; - grackle_data->UVbackground_redshift_off = (double) CoolData.RadiationRedshiftOff; - grackle_data->UVbackground_redshift_fullon = (double) CoolData.RadiationRedshiftFullOn; - grackle_data->UVbackground_redshift_drop = (double) CoolData.RadiationRedshiftDropOff; + //grackle_data->UVbackground_redshift_on = (double) CoolData.RadiationRedshiftOn; + //grackle_data->UVbackground_redshift_off = (double) CoolData.RadiationRedshiftOff; + //grackle_data->UVbackground_redshift_fullon = (double) CoolData.RadiationRedshiftFullOn; + //grackle_data->UVbackground_redshift_drop = (double) CoolData.RadiationRedshiftDropOff; grackle_data->use_radiative_transfer = (Eint32) RadiativeTransfer; // grackle_data->radiative_transfer_coupled_rate_solver set in RadiativeTransferReadParameters // grackle_data->radiative_transfer_hydrogen_only set in RadiativeTransferReadParameters From 1ef7bcbb70ae21b4158c8a177a6a43c9b7977171 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Wed, 30 Oct 2019 19:45:34 -0700 Subject: [PATCH 029/115] removed testing limitation that only 1 particle created per grid per timestep --- src/enzo/Grid_MechStarsCreation.C | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index 10e9ba310..42d3bd64a 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -129,7 +129,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, I limit star particle creation to 1/grid/step to keep feedback affecting the grid region */ - if (nCreated == 0){ + createStar = checkCreationCriteria(BaryonField[DensNum], totalMetal, Temperature, DMField, BaryonField[Vel1Num], BaryonField[Vel2Num], @@ -229,7 +229,6 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, ParticleArray->ParticleVelocity[2][nCreated]*VelocityUnits/1e5, index, GridDimension[0]*GridDimension[2]*GridDimension[3], i,j,k); nCreated ++; - } //end if (nCreated == 0) } }//end for k }//end for j From 5ee43795d33be4b92bf39f6638c03e17b717ec3a Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 31 Oct 2019 18:41:17 -0500 Subject: [PATCH 030/115] Most recent updates from frontera --- src/enzo/Grid_MechStarsDepositFeedback.C | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 353dfb19a..d97dce00c 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -199,7 +199,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* transform to comoving with the star and take velocities to momenta. Take Energy densities to energy. winds are ngp unless VERY high resolution */ - if (!winds || dx*LengthUnits/pc_cm < 0.1) + if (!winds || dx*LengthUnits/pc_cm < 2) transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], @@ -458,7 +458,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, As a computational compromize, supernova are deposited CIC, but winds are deposited NGP. At VERY high resolution, well still do CIC for winds */ - if (!winds || dx*LengthUnits/pc_cm < 0.1){ + if (!winds || dx*LengthUnits/pc_cm < 2){ for (int n = 0; n < nCouple; ++n){ pX = coupledMomenta*CloudParticleVectorX[n]*weightsVector[n]; pY = coupledMomenta*CloudParticleVectorY[n]*weightsVector[n]; @@ -541,7 +541,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, the momentum goes uncoupled. Since the cooling radius is so small for wind enrgy (~10^15 erg), this is totally appropriate for simulations with dx > 0.25pccm or so. */ - if (winds && dx*LengthUnits/pc_cm > 0.1){ + if (winds && dx*LengthUnits/pc_cm > 2){ float dm = coupledMass/(density[index]+coupledMass); density[index] += coupledMass; metals[index] += coupledMetals; @@ -587,7 +587,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, } /* Transform the grid back. Skip for winds, unless VERY high resolution*/ - if (!winds || dx*LengthUnits/pc_cm < 0.1) + if (!winds || dx*LengthUnits/pc_cm < 2) transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num], From 7be123c72011f8863db99b3c0fc10a89c342ad35 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 1 Nov 2019 11:55:38 -0500 Subject: [PATCH 031/115] Updates from frontera branch--to test on comet --- src/enzo/Grid_MechStarsCreation.C | 16 +++++++--------- src/enzo/Grid_MechStarsDepositFeedback.C | 13 +++++++------ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index 42d3bd64a..bae5455c9 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -40,9 +40,11 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float *DMField, float* totalMetal, int level, float* CoolingTime, int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar) { - if (level < StarMakeLevel) return 0; + /* If limiting timesteps for SNe, return if not the right level */ + if (level < StarMakeLevel && !UnrestrictedSN) return 0; + /* these flags are used to determine if we should set off a seed SNe */ bool gridShouldFormStars=false, notEnoughMetals = true; - float stretchFactor=0.6; + bool debug = true; @@ -125,10 +127,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, float dynamicalTime = 0; float Time = this->Time; int createStar = false; - /* - I limit star particle creation to 1/grid/step to - keep feedback affecting the grid region - */ + createStar = checkCreationCriteria(BaryonField[DensNum], totalMetal, Temperature, DMField, @@ -140,7 +139,6 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, &gridShouldFormStars, ¬EnoughMetals, 0, seedIndex); - //if (createStar && debug) printf ("SMM Criteria passed!\n"); if (createStar){ int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; @@ -153,10 +151,10 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, printf("Negative formation mass: %f %f",shieldedFraction, freeFallTime); continue; } + + /* limit new mass to 1/2 gas in cell */ float newMass = min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]); if (newMass*MassUnits < StarMakerMinimumMass){ - //fprintf(stdout,"NOT ENOUGH MASS IN CELL Mnew = %e f_s = %f Mcell = %e Mmin = %e\n", - // newMass*MassUnits, shieldedFraction, BaryonField[DensNum][index]*MassUnits, StarMakerMinimumMass); continue; } float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index d97dce00c..6023bf7b7 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -50,6 +50,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, //printf("In Feedback deposition\n"); bool debug = false; bool criticalDebug = false; + float min_winds = 1.0; bool printout = debug && !winds; int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; if (printout) printf("Host index = %d\n", index); @@ -199,7 +200,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, /* transform to comoving with the star and take velocities to momenta. Take Energy densities to energy. winds are ngp unless VERY high resolution */ - if (!winds || dx*LengthUnits/pc_cm < 2) + if (!winds || dx*LengthUnits/pc_cm < min_winds) transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], @@ -414,7 +415,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0, preZII=0, preZIa = 0; float dsum = 0.0, zsum=0.0, psum=0.0, psqsum =0.0, tesum=0.0, gesum=0.0, kesum=0.0; float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0, postZII=0, postZIa = 0; - if (criticalDebug){ + if (criticalDebug && !winds){ for (int i=0; i 0.25pccm or so. */ - if (winds && dx*LengthUnits/pc_cm > 2){ + if (winds && dx*LengthUnits/pc_cm > min_winds){ float dm = coupledMass/(density[index]+coupledMass); density[index] += coupledMass; metals[index] += coupledMetals; @@ -549,7 +550,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, BaryonField[GENum][index] += dm*coupledEnergy/coupledMass; } - if (criticalDebug){ + if (criticalDebug && !winds){ for (int i = 0; i< size ; i++){ postMass += BaryonField[DensNum][i]; postZ += BaryonField[MetalNum][i]; @@ -587,7 +588,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, } /* Transform the grid back. Skip for winds, unless VERY high resolution*/ - if (!winds || dx*LengthUnits/pc_cm < 2) + if (!winds || dx*LengthUnits/pc_cm < min_winds) transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], BaryonField[MetalIINum], BaryonField[MetalIaNum], BaryonField[Vel1Num],BaryonField[Vel2Num], From 2c70aee49e60cce336096259351eba97af4de599 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 4 Nov 2019 09:11:27 -0600 Subject: [PATCH 032/115] updated --- src/enzo/MechStars_checkCreationCriteria.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index 07c7260a2..6395bcca4 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -1,4 +1,4 @@ -/* + /* Routine actually checks to see whether the input grid is capable of star formation @@ -161,7 +161,7 @@ int checkCreationCriteria(float* Density, float* Metals, return PASS; } //if (status && debug) fprintf(stdout, "passed creation criteria\n"); - if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity) + if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity && !continuingFormation) *notEnoughMetals = false; if (status && Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity && MechStarsSeedField && !continuingFormation) From ea91e7a31bf5781a5d4328d1bc6894df46d16080 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 7 Nov 2019 12:46:49 -0600 Subject: [PATCH 033/115] debugging branch merged in. still has particles drifting out of grid --- src/enzo/Grid_MechStarsCreation.C | 61 +- src/enzo/Grid_MechStarsDepositFeedback.C | 740 ++++++++++++----------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 429 +++++++------ src/enzo/MechStars_determineSN.C | 4 +- 4 files changed, 673 insertions(+), 561 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index bae5455c9..eb3e992b5 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -41,8 +41,13 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar) { /* If limiting timesteps for SNe, return if not the right level */ - if (level < StarMakeLevel && !UnrestrictedSN) return 0; - /* these flags are used to determine if we should set off a seed SNe */ + if (level < StarMakeLevel) return 0; + + /* + these flags are used to determine if we should set off a seed SNe + if (gridShouldFormStars && !notEnoughMetals) at the end, we'll seed + with P3 SNe if requested + */ bool gridShouldFormStars=false, notEnoughMetals = true; bool debug = true; @@ -81,12 +86,6 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, int size =1; for (int dim = 0; dim < GridRank; dim ++) size *= GridDimension[dim]; - // float* totalMetal = new float [size]; - // for (int i = 0; i< size; i++){ - // totalMetal[i] = BaryonField[MetalNum][i]; - // if (MechStarsSeedField) totalMetal[i] += BaryonField[SNColourNum][i]; - // } - int rank = GridRank; float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, @@ -97,20 +96,21 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, return FAIL; } -/* Define MassUnits so that code * mass = physical (Msun) + /* + ReDefine MassUnits so that code * mass = physical (Msun) and physical(Msun) / MassUnits = code */ MassUnits = DensityUnits*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass; /* Index of last cell that was capable of star formation but has no metals */ int *seedIndex = new int [3]; - float dx = CellWidth[0][0]; + FLOAT dx = CellWidth[0][0]; int GZ = int(NumberOfGhostZones); int nCreated = *NumberOfParticlesSoFar; //fprintf(stdout, "Starting creation with %d prior particles\n",nCreated); - for (int i = GZ; i < GridDimension[0]-GZ; i++){ + for (int k = GZ; k< GridDimension[2]-GZ; k++){ for(int j = GZ; j < GridDimension[1]-GZ; j++){ - for (int k = GZ; k< GridDimension[2]-GZ; k++){ + for (int i = GZ; i < GridDimension[0]-GZ; i++){ /* Particle creation has several criteria: @@ -144,7 +144,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, /* Determine Mass of new particle */ - float MassShouldForm =(shieldedFraction * BaryonField[DensNum][index] + float MassShouldForm = (shieldedFraction * BaryonField[DensNum][index] * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13); if (MassShouldForm < 0){ @@ -154,6 +154,9 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, /* limit new mass to 1/2 gas in cell */ float newMass = min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]); + + // only if mass is large enough + if (newMass*MassUnits < StarMakerMinimumMass){ continue; } @@ -162,7 +165,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, // fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); ParticleArray->ParticleMass[nCreated] = newMass; if (StarParticleRadiativeFeedback) - ParticleArray->ParticleAttribute[1][nCreated] = huge_number; // need infinite lifetime for radiative feedback i think? + ParticleArray->ParticleAttribute[1][nCreated] = 27*TimeUnits*3.1517e6; // need 27 Myr lifetime for ray tracing feedback else ParticleArray->ParticleAttribute[1][nCreated] = 0.0; // Tracking SNE in TDP field dynamicalTime/TimeUnits; ParticleArray->ParticleAttribute[0][nCreated] = Time; @@ -188,32 +191,38 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, if (HydroMethod != 0) fprintf(stderr,"Mechanical star maker not tested for anything except HydroMethod = 0\n"); /* average particle velocity over 125 cells to prevent runaway */ - for (int ip = i-2; ip <= i + 2 ; ip++) + for (int kp = k-2; kp <= k+2; kp++) for (int jp = j-2; jp <= j+2 ; jp++) - for (int kp = k-2; kp <= k+2; kp++){ + for (int ip = i-2; ip <= i + 2 ; ip++) + { int ind = ip + jp*GridDimension[0]+kp*GridDimension[0]+GridDimension[1]; vX += BaryonField[Vel1Num][ind]; vY += BaryonField[Vel2Num][ind]; vZ += BaryonField[Vel3Num][ind]; } float MaxVelocity = 250.*1.0e5/VelocityUnits; - ParticleArray->ParticleVelocity[0][nCreated] = (abs(vX/125.) > MaxVelocity)?(MaxVelocity*((vX > 0)?(1):(-1))):(vX/125.); - ParticleArray->ParticleVelocity[1][nCreated] = (abs(vY/125.) > MaxVelocity)?(MaxVelocity*((vY > 0)?(1):(-1))):(vY/125.); - ParticleArray->ParticleVelocity[2][nCreated] = (abs(vZ/125.) > MaxVelocity)?(MaxVelocity*((vZ > 0)?(1):(-1))):(vZ/125.);; + ParticleArray->ParticleVelocity[0][nCreated] = + (abs(vX/125.) > MaxVelocity)?(MaxVelocity*((vX > 0)?(1):(-1))):(vX/125.); + ParticleArray->ParticleVelocity[1][nCreated] = + (abs(vY/125.) > MaxVelocity)?(MaxVelocity*((vY > 0)?(1):(-1))):(vY/125.); + ParticleArray->ParticleVelocity[2][nCreated] = + (abs(vZ/125.) > MaxVelocity)?(MaxVelocity*((vZ > 0)?(1):(-1))):(vZ/125.); /* give it position at center of host cell */ ParticleArray->ParticlePosition[0][nCreated] = CellLeftEdge[0][0] - +(dx*(float(i)+0.5)); + +(dx*(FLOAT(i)-0.5)); ParticleArray->ParticlePosition[1][nCreated] = CellLeftEdge[1][0] - +(dx*(float(j)+0.5)); + +(dx*(FLOAT(j)-0.5)); ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] - +(dx*(float(k)+0.5)); + +(dx*(FLOAT(k)-0.5)); if (nCreated >= MaximumNumberOfNewParticles) return nCreated; - if (true) - fprintf(stdout,"Created star: [%f] %e %e ::: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f ::: %d %d ::: %d %d %d\n", - Time*TimeUnits/3.1557e13,BaryonField[DensNum][index], - BaryonField[DensNum][index]*MassUnits, level, nCreated+1, + if (debug) + fprintf(stdout,"Created star: [%f] %e %e ::: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f \t::: %d %d ::: %d %d %d\n", + Time*TimeUnits/3.1557e13, + BaryonField[DensNum][index], + BaryonField[DensNum][index]*MassUnits, + level, nCreated+1, ParticleArray->ParticleType[nCreated], ParticleArray->ParticleMass[nCreated]*MassUnits, ParticleArray->ParticleAttribute[0][nCreated], diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 6023bf7b7..693228e79 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -15,32 +15,32 @@ #include "StarParticleData.h" #include "phys_constants.h" - extern "C" void FORTRAN_NAME(cic_deposit)(float* xPosition, float* yPosition, - float* zPosition, int* gridRank, int* nParticles, - float* DepositQuantity, float* FieldToDepositTo, - float* leftEdge, int* xGridDim, int* yGridDim, - int* zGridDim, float* gridDx, float* cloudsize); - int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, float *MassUnits, float Time); - int transformComovingWithStar(float* Density, float* Metals, - float* MetalsSNII, float* MetalsSNIA, - float* Vel1, float* Vel2, float* Vel3, - float* TE, float* GE, - float up, float vp, float wp, - int sizeX, int sizeY, int sizeZ, int direction); - int FindField(int field, int farray[], int numfields); - - -int grid::MechStars_DepositFeedback(float ejectaEnergy, - float ejectaMass, float ejectaMetal, - float* totalMetals, float* temperature, - float* up, float* vp, float* wp, - float* xp, float* yp, float* zp, - int ip, int jp, int kp, - int size, float* muField, int winds, int nSNII, - int nSNIA, float starMetal, int isP3){ - +extern "C" void FORTRAN_NAME(cic_deposit)(float *xPosition, float *yPosition, + float *zPosition, int *gridRank, int *nParticles, + float *DepositQuantity, float *FieldToDepositTo, + float *leftEdge, int *xGridDim, int *yGridDim, + int *zGridDim, float *gridDx, float *cloudsize); +int GetUnits(float *DensityUnits, float *LengthUnits, + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, float *MassUnits, float Time); +int transformComovingWithStar(float *Density, float *Metals, + float *MetalsSNII, float *MetalsSNIA, + float *Vel1, float *Vel2, float *Vel3, + float *TE, float *GE, + float up, float vp, float wp, + int sizeX, int sizeY, int sizeZ, int direction); +int FindField(int field, int farray[], int numfields); + +int grid::MechStars_DepositFeedback(float ejectaEnergy, + float ejectaMass, float ejectaMetal, + float *totalMetals, float *temperature, + float *up, float *vp, float *wp, + float *xp, float *yp, float *zp, + int ip, int jp, int kp, + int size, float *muField, int winds, int nSNII, + int nSNIA, float starMetal, int isP3) +{ + /* This routine will create an isocahedron of coupling particles, where we determine the feedback quantities. The vertices of the isocahedron are ~coupled particles @@ -49,285 +49,287 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, */ //printf("In Feedback deposition\n"); bool debug = false; - bool criticalDebug = false; + bool criticalDebug = true; float min_winds = 1.0; bool printout = debug && !winds; - int index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; - if (printout) printf("Host index = %d\n", index); + int index = ip + jp * GridDimension[0] + kp * GridDimension[0] * GridDimension[1]; + if (printout) + printf("Host index = %d\n", index); int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; - + /* Compute size (in floats) of the current grid. */ - float stretchFactor =1.0;//1.5/sin(M_PI/10.0); // How far should cloud particles be from their host - // in units of dx. Since the cloud forms a sphere shell, stretchFactor > 1 is not recommended + float stretchFactor = 1.0; //1.5/sin(M_PI/10.0); // How far should cloud particles be from their host + // in units of dx. Since the cloud forms a sphere shell, stretchFactor > 1 is not recommended size = 1; for (int dim = 0; dim < GridRank; dim++) size *= GridDimension[dim]; float DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, - HMNum, H2INum, H2IINum, DINum, DIINum, HDINum; + HMNum, H2INum, H2IINum, DINum, DIINum, HDINum; /* Find fields: density, total energy, velocity1-3. */ if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) { + Vel3Num, TENum) == FAIL) + { fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); return FAIL; } /* Set the units */ float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; + TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, - &MassUnits, this->Time) == FAIL) { + &TimeUnits, &VelocityUnits, + &MassUnits, this->Time) == FAIL) + { fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } - FLOAT dx = CellWidth[0][0]; + return FAIL; + } + FLOAT dx = CellWidth[0][0]; if (printout) printf("depositing quantities: Energy %e, Mass %e, Metals %e\n", - ejectaEnergy, ejectaMass, ejectaMetal); + ejectaEnergy, ejectaMass, ejectaMetal); /* get metallicity field and set flag; assumed true thoughout feedback since so many quantities are metallicity dependent */ - int MetallicityField = FALSE, MetalNum=-1, MetalIaNum=-1, MetalIINum=-1, SNColourNum=-1; - if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) - != -1) + int MetallicityField = FALSE, MetalNum = -1, MetalIaNum = -1, MetalIINum = -1, SNColourNum = -1; + if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) MetallicityField = TRUE; - else{ + else + { fprintf(stdout, "MechStars only functions with metallicity field enabled!"); ENZO_FAIL("Grid_MechStarsDepositFeedback: 91"); MetalNum = 0; } - if(StarMakerTypeIaSNe) + if (StarMakerTypeIaSNe) MetalIaNum = FindField(MetalSNIaDensity, FieldType, NumberOfBaryonFields); if (StarMakerTypeIISNeMetalField) MetalIINum = FindField(MetalSNIIDensity, FieldType, NumberOfBaryonFields); if (MechStarsSeedField) SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); - - if (MechStarsSeedField && SNColourNum<0) ENZO_FAIL("Cant use Seed Field without SNColour field"); + + if (MechStarsSeedField && SNColourNum < 0) + ENZO_FAIL("Cant use Seed Field without SNColour field"); /* set other units that we need */ - MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; //Msun! - float EnergyUnits = DensityUnits*pow(LengthUnits*dx, 3) - * pow(LengthUnits/TimeUnits, 2.0);//[g cm^2/s^2] -> code_energy - float MomentaUnits = MassUnits*VelocityUnits; + MassUnits = DensityUnits * pow(LengthUnits * dx, 3) / SolarMass; //Msun! + float EnergyUnits = DensityUnits * pow(LengthUnits * dx, 3) * pow(LengthUnits / TimeUnits, 2.0); //[g cm^2/s^2] -> code_energy + float MomentaUnits = MassUnits * VelocityUnits; /* Make copys of pointers fields to work with (theyre just easier to type!). */ - float* density = BaryonField[DensNum]; - float* metals = BaryonField[MetalNum]; - float* metalsII=NULL; - float* metalsIA=NULL; - float* metalsIII = NULL; + float *density = BaryonField[DensNum]; + float *metals = BaryonField[MetalNum]; + float *metalsII = NULL; + float *metalsIA = NULL; + float *metalsIII = NULL; if (StarMakerTypeIISNeMetalField) - metalsII = BaryonField[MetalIINum]; + metalsII = BaryonField[MetalIINum]; if (StarMakerTypeIaSNe) - metalsIA = BaryonField[MetalIaNum]; + metalsIA = BaryonField[MetalIaNum]; if (MechStarsSeedField) - metalsIII = BaryonField[SNColourNum]; - float* u = BaryonField[Vel1Num]; - float* v = BaryonField[Vel2Num]; - float* w = BaryonField[Vel3Num]; - float* totalEnergy = BaryonField[TENum]; - float* gasEnergy = BaryonField[GENum]; - - - float phi = (1.0+sqrt(5))/2.0; //Golden Ratio - float iphi = 1.0/phi; // inverse GR - /* Particle Vectors */ - - + metalsIII = BaryonField[SNColourNum]; + float *u = BaryonField[Vel1Num]; + float *v = BaryonField[Vel2Num]; + float *w = BaryonField[Vel3Num]; + float *totalEnergy = BaryonField[TENum]; + float *gasEnergy = BaryonField[GENum]; + + float phi = (1.0 + sqrt(5)) / 2.0; //Golden Ratio + float iphi = 1.0 / phi; // inverse GR + /* Particle Vectors */ + /* A DODECAHEDRON+ISOCAHEDRON */ - int nCouple = 26; - float A = stretchFactor*dx; - float cloudSize=stretchFactor*dx; - if (printout) printf("Making cloud n=%d", nCouple); - - /* each coupled particle is at the vertex of a compound of a dodecahedron and isocahedron */ - - FLOAT CloudParticleVectorX [] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - // {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, - // iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, - // 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; - FLOAT CloudParticleVectorY [] = {1,1,1,0,0,-1,-1,-1,0,1,1,1,0,0,-1,-1,-1,1,1,1,0,0,-1,-1,-1,0}; - // {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, - // phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, - // phi, -phi, -phi, phi, 0, 0, 0, 0}; - FLOAT CloudParticleVectorZ [] = {1,0,-1,1,-1,1,0,-1,0,1,0,-1,1,-1,1,0,-1,1,0,-1,1,-1,1,0,-1,0}; - // {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, - // 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, - // phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; - float weightsVector [nCouple]; - /* Set position of feedback cloud particles */ - - FLOAT CloudParticlePositionX [nCouple]; - FLOAT CloudParticlePositionY [nCouple]; - FLOAT CloudParticlePositionZ [nCouple]; - - /*all possible values of x,y,z with origin particle at x=y=z=0.0 */ - - for (int cpInd = 0; cpInd < nCouple; cpInd++){ - FLOAT norm = sqrt(CloudParticleVectorX[cpInd]*CloudParticleVectorX[cpInd] - + CloudParticleVectorY[cpInd]*CloudParticleVectorY[cpInd] - + CloudParticleVectorZ[cpInd]*CloudParticleVectorZ[cpInd]); - float xbaMag = A*A*norm*norm; - /* in this cloud, take the coupling particle position as 0.5, 0.5, 0.5 */ - CloudParticlePositionX[cpInd] = *xp-CloudParticleVectorX[cpInd]/norm* - A; - CloudParticlePositionY[cpInd] = *yp-CloudParticleVectorY[cpInd]/norm* - A; - CloudParticlePositionZ[cpInd] = *zp-CloudParticleVectorZ[cpInd]/norm* - A; - weightsVector[cpInd] = 0.5*(1.-1./(1.+1./4./M_PI/26./xbaMag/M_PI)); - /* turn the vectors back into unit-vectors */ - CloudParticleVectorZ[cpInd] /= norm; - CloudParticleVectorY[cpInd] /= norm; - CloudParticleVectorX[cpInd] /= norm; - - } - float weightsSum = 0.0; - for (int wind = 0; wind < nCouple; wind++){ - weightsSum += weightsVector[wind]; - } - for (int wind = 0; wind < nCouple; wind++){ - weightsVector[wind] /= weightsSum; - if (weightsVector[wind] == 0 || isnan(weightsVector[wind])){ - ENZO_FAIL("NaN weight Vector!") - } - } + int nCouple = 26; + float A = stretchFactor * dx; + FLOAT cloudSize = stretchFactor * dx; + /* + Make a cloud of coupling particles; + each is on a grid with dx spacing + from the host particles. + */ + + FLOAT CloudParticleVectorX[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + // {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, + // iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, + // 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; + FLOAT CloudParticleVectorY[] = {1, 1, 1, 0, 0, -1, -1, -1, 0, 1, 1, 1, 0, 0, -1, -1, -1, 1, 1, 1, 0, 0, -1, -1, -1, 0}; + // {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, + // phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, + // phi, -phi, -phi, phi, 0, 0, 0, 0}; + FLOAT CloudParticleVectorZ[] = {1, 0, -1, 1, -1, 1, 0, -1, 0, 1, 0, -1, 1, -1, 1, 0, -1, 1, 0, -1, 1, -1, 1, 0, -1, 0}; + // {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, + // 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, + // phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; + float weightsVector[nCouple]; + /* Set position of feedback cloud particles */ + + FLOAT CloudParticlePositionX[nCouple]; + FLOAT CloudParticlePositionY[nCouple]; + FLOAT CloudParticlePositionZ[nCouple]; + + /*all possible values of x,y,z with origin particle at x=y=z=0.0 */ + + for (int cpInd = 0; cpInd < nCouple; cpInd++) + { + float norm = sqrt(CloudParticleVectorX[cpInd] * CloudParticleVectorX[cpInd] + CloudParticleVectorY[cpInd] * CloudParticleVectorY[cpInd] + CloudParticleVectorZ[cpInd] * CloudParticleVectorZ[cpInd]); + float xbaMag = A * A * norm * norm; + /* in this cloud, take the coupling particle position as 0.5, 0.5, 0.5 */ + CloudParticlePositionX[cpInd] = *xp - CloudParticleVectorX[cpInd] / norm * + A; + CloudParticlePositionY[cpInd] = *yp - CloudParticleVectorY[cpInd] / norm * + A; + CloudParticlePositionZ[cpInd] = *zp - CloudParticleVectorZ[cpInd] / norm * + A; + weightsVector[cpInd] = 0.5 * (1. - 1. / (1. + 1. / 4. / M_PI / 26. / xbaMag / M_PI)); + /* turn the vectors back into unit-vectors */ + CloudParticleVectorZ[cpInd] /= norm; + CloudParticleVectorY[cpInd] /= norm; + CloudParticleVectorX[cpInd] /= norm; + } + float weightsSum = 0.0; + for (int wind = 0; wind < nCouple; wind++) + { + weightsSum += weightsVector[wind]; + } + for (int wind = 0; wind < nCouple; wind++) + { + weightsVector[wind] /= weightsSum; + if (weightsVector[wind] == 0 || isnan(weightsVector[wind])) + { + ENZO_FAIL("NaN weight Vector!") + } + } /* transform to comoving with the star and take velocities to momenta. Take Energy densities to energy. winds are ngp unless VERY high resolution */ - if (!winds || dx*LengthUnits/pc_cm < min_winds) - transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], - BaryonField[MetalIINum], BaryonField[MetalIaNum], - BaryonField[Vel1Num],BaryonField[Vel2Num],BaryonField[Vel3Num], - BaryonField[TENum], BaryonField[GENum], - *up, *vp, *wp, GridDimension[0], GridDimension[1], - GridDimension[2], 1); + if (!winds || dx * LengthUnits / pc_cm < min_winds) + transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], + BaryonField[MetalIINum], BaryonField[MetalIaNum], + BaryonField[Vel1Num], BaryonField[Vel2Num], BaryonField[Vel3Num], + BaryonField[TENum], BaryonField[GENum], + *up, *vp, *wp, GridDimension[0], GridDimension[1], + GridDimension[2], 1); /* Use averaged quantities across multiple cells so that deposition is stable. vmean is used to determine whether the supernova shell calculation should proceed: M_shell > 0 iff v_shell > v_gas */ - float zmean=0, dmean=0, nmean=0, vmean=0, mu_mean = 0; - for (int ind = -1; ind <= 1; ind++){ - zmean += totalMetals[index+ind]/BaryonField[DensNum][index+ind]; - zmean += totalMetals[index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind]; - zmean += totalMetals[index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + float zmean = 0, dmean = 0, nmean = 0, vmean = 0, mu_mean = 0; + for (int ind = -1; ind <= 1; ind++) + { + zmean += totalMetals[index + ind] / BaryonField[DensNum][index + ind]; + zmean += totalMetals[index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind]; + zmean += totalMetals[index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; - nmean += BaryonField[DensNum][index+ind]*DensityUnits; - nmean += BaryonField[DensNum][index+GridDimension[0]*ind]*DensityUnits; - nmean += BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]*DensityUnits; + nmean += BaryonField[DensNum][index + ind] * DensityUnits; + nmean += BaryonField[DensNum][index + GridDimension[0] * ind] * DensityUnits; + nmean += BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind] * DensityUnits; // mu_mean += muField[index+ind]; // mu_mean += muField[index+GridDimension[0]*ind]; // mu_mean += muField[index+GridDimension[0]*GridDimension[1]*ind]; - dmean += BaryonField[DensNum][index+ind]; - dmean += BaryonField[DensNum][index+GridDimension[0]*ind]; - dmean += BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; - - vmean += BaryonField[Vel1Num][index+ind]/BaryonField[DensNum][index+ind] - *BaryonField[Vel1Num][index+ind]/BaryonField[DensNum][index+ind]; - vmean += BaryonField[Vel1Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind] - *BaryonField[Vel1Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind]; - vmean += BaryonField[Vel1Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind] - *BaryonField[Vel1Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; - - vmean += BaryonField[Vel2Num][index+ind]/BaryonField[DensNum][index+ind] - *BaryonField[Vel2Num][index+ind]/BaryonField[DensNum][index+ind]; - vmean += BaryonField[Vel2Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind] - *BaryonField[Vel2Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind]; - vmean += BaryonField[Vel2Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind] - *BaryonField[Vel2Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; - - vmean += BaryonField[Vel3Num][index+ind]/BaryonField[DensNum][index+ind] - *BaryonField[Vel3Num][index+ind]/BaryonField[DensNum][index+ind]; - vmean += BaryonField[Vel3Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind] - *BaryonField[Vel3Num][index+GridDimension[0]*ind]/BaryonField[DensNum][index+GridDimension[0]*ind]; - vmean += BaryonField[Vel3Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind] - *BaryonField[Vel3Num][index+GridDimension[0]*GridDimension[1]*ind]/BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]; + dmean += BaryonField[DensNum][index + ind]; + dmean += BaryonField[DensNum][index + GridDimension[0] * ind]; + dmean += BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; + vmean += BaryonField[Vel1Num][index + ind] / BaryonField[DensNum][index + ind] * BaryonField[Vel1Num][index + ind] / BaryonField[DensNum][index + ind]; + vmean += BaryonField[Vel1Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind] * BaryonField[Vel1Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind]; + vmean += BaryonField[Vel1Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind] * BaryonField[Vel1Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; + + vmean += BaryonField[Vel2Num][index + ind] / BaryonField[DensNum][index + ind] * BaryonField[Vel2Num][index + ind] / BaryonField[DensNum][index + ind]; + vmean += BaryonField[Vel2Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind] * BaryonField[Vel2Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind]; + vmean += BaryonField[Vel2Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind] * BaryonField[Vel2Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; + + vmean += BaryonField[Vel3Num][index + ind] / BaryonField[DensNum][index + ind] * BaryonField[Vel3Num][index + ind] / BaryonField[DensNum][index + ind]; + vmean += BaryonField[Vel3Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind] * BaryonField[Vel3Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind]; + vmean += BaryonField[Vel3Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind] * BaryonField[Vel3Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; } - vmean = sqrt(vmean)/27.0*VelocityUnits; // cm/s! + vmean = sqrt(vmean) / 27.0 * VelocityUnits; // cm/s! zmean /= (27.0); // mu_mean/= (dmean); // if (abs(mu_mean) > 10){ // mu_mean = 0.6; // } - dmean = dmean*DensityUnits/(27.); - nmean = max(0.01, dmean/mh); + dmean = dmean * DensityUnits / (27.); + nmean = max(0.01, dmean / mh); //nmean = max(nmean, 1e-1); //if (debug) printf ("Zmean = %e Dmean = %e mu_mean = %e ", zmean, dmean, mu_mean); //if (debug) printf ("Nmean = %f vmean = %f\n", nmean, vmean/1e5); float zZsun = max(zmean, 1e-8); - float fz = (zZsun < 0.01)? (2.0): (pow(zZsun, -0.14)); + float fz = (zZsun < 0.01) ? (2.0) : (pow(zZsun, -0.14)); /* Cooling radius as in Hopkins, but as an average over cells */ - + float CoolingRadius = 28.4 * - pow(max(0.1,nmean), -3.0/7.0) - *pow(ejectaEnergy/1.0e51, 2.0/7.0)* fz; - if (printout)fprintf(stdout, "cooling radius [pc] = %e\n %f %e %f %e %e \n", - CoolingRadius, nmean, ejectaEnergy/1e51, fz, zmean, dmean); - + pow(max(0.1, nmean), -3.0 / 7.0) * pow(ejectaEnergy / 1.0e51, 2.0 / 7.0) * fz; + if (printout) + fprintf(stdout, "cooling radius [pc] = %e\n %f %e %f %e %e \n", + CoolingRadius, nmean, ejectaEnergy / 1e51, fz, zmean, dmean); + float coupledEnergy = ejectaEnergy; - if (printout)fprintf(stdout, "Dx [pc] = %f\n", dx*LengthUnits/pc_cm); - - float dxRatio = stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius; - if (winds) dxRatio = min(stretchFactor*dx*LengthUnits/pc_cm/CoolingRadius, 50); - float pEjectMod = pow(2.0*ejectaEnergy*(ejectaMass*SolarMass), 0.5)/SolarMass/1e5; - + if (printout) + fprintf(stdout, "Dx [pc] = %f\n", dx * LengthUnits / pc_cm); + + float dxRatio = stretchFactor * dx * LengthUnits / pc_cm / CoolingRadius; + if (winds) + dxRatio = min(stretchFactor * dx * LengthUnits / pc_cm / CoolingRadius, 50); + float pEjectMod = pow(2.0 * ejectaEnergy * (ejectaMass * SolarMass), 0.5) / SolarMass / 1e5; + /* We want to couple one of four phases: free expansion, Sedov-taylor, shell formation, or terminal The first three phases are take forms from Kim & Ostriker 2015, the last from Cioffi 1988*/ - - float cellwidth = stretchFactor*dx*LengthUnits/pc_cm; - + + float cellwidth = stretchFactor * dx * LengthUnits / pc_cm; + // if we resolve free expansion, all energy is thermally coupled - float p_free = 0.0;//sqrt(ejectaMass*SolarMass*ejectaEnergy)/SolarMass/1e5;//1.73e4*sqrt(ejectaMass*ejectaEnergy/1e51/3.); // free exp. momentum eq 15 - float r_free = 2.75*pow(ejectaMass/3/nmean, 1./3.); // free exp radius eq 2 - - + float p_free = 0.0; //sqrt(ejectaMass*SolarMass*ejectaEnergy)/SolarMass/1e5;//1.73e4*sqrt(ejectaMass*ejectaEnergy/1e51/3.); // free exp. momentum eq 15 + float r_free = 2.75 * pow(ejectaMass / 3 / nmean, 1. / 3.); // free exp radius eq 2 + // assuming r_sedov == dx, solve for t3 - - float t3_sedov = pow( cellwidth*pc_cm - /(5.0*pc_cm*pow(ejectaEnergy/1e51/nmean, 1.0/5.0)), 5./2.); - float p_sedov = 2.21e4*pow(ejectaEnergy/1e51, 4./5.) - * pow(nmean, 1./5.)* pow(t3_sedov, 3./5.); // eq 16 + + float t3_sedov = pow(cellwidth * pc_cm / (5.0 * pc_cm * pow(ejectaEnergy / 1e51 / nmean, 1.0 / 5.0)), 5. / 2.); + float p_sedov = 2.21e4 * pow(ejectaEnergy / 1e51, 4. / 5.) * pow(nmean, 1. / 5.) * pow(t3_sedov, 3. / 5.); // eq 16 // shell formation radius eq 8 - float r_shellform = 22.6*pow(ejectaEnergy/1e51, 0.29)*pow(nmean, -0.42); + float r_shellform = 22.6 * pow(ejectaEnergy / 1e51, 0.29) * pow(nmean, -0.42); // p_sf = m_sf*v_sf eq 9,11 - float p_shellform = 3.1e5*pow(ejectaEnergy/1e51, 0.94)*pow(nmean, -0.13) ; // p_sf = m_sf*v_sf eq 9,11 - + float p_shellform = 3.1e5 * pow(ejectaEnergy / 1e51, 0.94) * pow(nmean, -0.13); // p_sf = m_sf*v_sf eq 9,11 + /* termninal momentum */ - float pTerminal = 4.8e5*pow(nmean, -1.0/7.0) - * pow(ejectaEnergy/1e51, 13.0/14.0) * fz; // cioffi 1988, as written in Hopkins 2018 + float pTerminal = 4.8e5 * pow(nmean, -1.0 / 7.0) * pow(ejectaEnergy / 1e51, 13.0 / 14.0) * fz; // cioffi 1988, as written in Hopkins 2018 float coupledMomenta = 0.0; float eKinetic = 0.0; - if(printout)fprintf(stdout, "RADII: %e %e %e t_3=%e\n", r_free, r_shellform, CoolingRadius, t3_sedov); - + if (printout) + fprintf(stdout, "RADII: %e %e %e t_3=%e\n", r_free, r_shellform, CoolingRadius, t3_sedov); + /* Select the mode of coupling */ - if (cellwidth < r_free){ + if (cellwidth < r_free) + { coupledMomenta = p_free; - if(printout)fprintf(stdout, "Coupling free expansion\n");} - if (cellwidth > r_free && cellwidth < CoolingRadius){ + if (printout) + fprintf(stdout, "Coupling free expansion\n"); + } + if (cellwidth > r_free && cellwidth < CoolingRadius) + { coupledMomenta = min(p_sedov, pTerminal); - if(printout)fprintf(stdout, "Coupling S-T phase\n"); - } + if (printout) + fprintf(stdout, "Coupling S-T phase\n"); + } // if (cellwidth > r_shellform && cellwidth < CoolingRadius){ // coupledMomenta = min(p_shellform+(cellwidth-r_shellform)*(pTerminal-p_shellform)/(CoolingRadius-r_shellform), pTerminal); // if(printout)fprintf(stdout, "Coupling shell-forming stage\n");} - if (cellwidth > CoolingRadius){ + if (cellwidth > CoolingRadius) + { coupledMomenta = pTerminal; - if(printout)fprintf(stdout, "Coupling terminal momenta\n");} - if (printout)fprintf(stdout, "Calculated p = %e\n", coupledMomenta); - + if (printout) + fprintf(stdout, "Coupling terminal momenta\n"); + } + if (printout) + fprintf(stdout, "Calculated p = %e\n", coupledMomenta); /* fading radius of a SNR. For real scale invariance, the momentum deposited should go to zero for large dx!*/ // float *temperature = new float[size]; @@ -341,94 +343,108 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, // coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3/2)):(coupledMomenta); float shellMass = 0.0, shellVelocity = 0.0; - if(printout) printf("Coupled momentum: %e\n", coupledMomenta); + if (printout) + printf("Coupled momentum: %e\n", coupledMomenta); /* If resolution is in a range comparable to Rcool and Analytic SNR shell mass is on, adjust the shell mass upper range of applicability for shell mass is determined by local average gas velocity (v_shell ~ v_gas = no shell) */ - if (cellwidth > r_shellform && coupledEnergy > 0 - && AnalyticSNRShellMass){ - shellVelocity = 413.0 *pow(nmean, 1.0/7.0) - *pow(zZsun, 3.0/14.0)*pow(coupledEnergy/EnergyUnits/1e51, 1.0/14.0) - *pow(dxRatio, -7.0/3.0);//km/s - - if (shellVelocity > vmean/1e5){ - shellMass = max(8e3, coupledMomenta/shellVelocity); //Msun - - /* cant let host cells evacuate completely! + if (cellwidth > r_shellform && coupledEnergy > 0 && AnalyticSNRShellMass) + { + shellVelocity = 413.0 * pow(nmean, 1.0 / 7.0) * pow(zZsun, 3.0 / 14.0) * pow(coupledEnergy / EnergyUnits / 1e51, 1.0 / 14.0) * pow(dxRatio, -7.0 / 3.0); //km/s + + if (shellVelocity > vmean / 1e5) + { + shellMass = max(8e3, coupledMomenta / shellVelocity); //Msun + + /* cant let host cells evacuate completely! 7.974045e+017.974045e+017.974045e+017.974045e+017.974045e+01 Shell mass will be evacuated from central cells by CIC a negative mass, so have to check that the neighbors can handle it too*/ - for (int ind = -1; ind<=1; ind++){ - float minD = min(BaryonField[DensNum][index+ind],BaryonField[DensNum][index+GridDimension[0]*ind]); - minD = min(minD,BaryonField[DensNum][index+GridDimension[0]*GridDimension[1]*ind]); - if (shellMass >= 0.25*minD*MassUnits) - shellMass = 0.25*minD*MassUnits; - } - - + for (int ind = -1; ind <= 1; ind++) + { + float minD = min(BaryonField[DensNum][index + ind], BaryonField[DensNum][index + GridDimension[0] * ind]); + minD = min(minD, BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]); + if (shellMass >= 0.25 * minD * MassUnits) + shellMass = 0.25 * minD * MassUnits; } - + } } - if (shellMass < 0.0){ - fprintf(stdout, "Shell mass = %e Velocity= %e P = %e", - shellMass, shellVelocity, coupledMomenta); - ENZO_FAIL("SM_deposit: 252"); + if (shellMass < 0.0) + { + fprintf(stdout, "Shell mass = %e Velocity= %e P = %e", + shellMass, shellVelocity, coupledMomenta); + ENZO_FAIL("SM_deposit: 252"); + } + float coupledMass = shellMass + ejectaMass; + eKinetic = coupledMomenta * coupledMomenta / (2.0 * dmean * pow(LengthUnits * CellWidth[0][0], 3) / SolarMass) * SolarMass * 1e10; + if (printout) + fprintf(stdout, "Ekinetic = %e Mass = %e\n", + eKinetic, dmean * pow(LengthUnits * CellWidth[0][0], 3) / SolarMass); + if (eKinetic > 1e60 && winds) + { + fprintf(stdout, "Ekinetic = %e Mass = %e\n", + eKinetic, dmean * pow(LengthUnits * CellWidth[0][0], 3) / SolarMass); + ENZO_FAIL("winds Ekinetic > reasonability!\n"); + } + if (eKinetic > 1e60 && !winds) + { + fprintf(stdout, "Ekinetic = %e Mass = %e\n", + eKinetic, dmean * pow(LengthUnits * CellWidth[0][0], 3) / SolarMass); + ENZO_FAIL("SNE Ekinetic > reasonability!\n"); } - float coupledMass = shellMass+ejectaMass; - eKinetic = coupledMomenta*coupledMomenta - /(2.0*dmean*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass)*SolarMass*1e10; - if (printout)fprintf(stdout, "Ekinetic = %e Mass = %e\n", - eKinetic, dmean*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass); - if (eKinetic > 1e60) ENZO_FAIL("Ekinetic > reasonability!\n"); - - float coupledGasEnergy = max(ejectaEnergy-eKinetic, 0); - if (printout)fprintf(stdout, "Coupled Gas Energy = %e\n",coupledGasEnergy); + float coupledGasEnergy = max(ejectaEnergy - eKinetic, 0); + if (printout) + fprintf(stdout, "Coupled Gas Energy = %e\n", coupledGasEnergy); if (dxRatio > 1.0) - coupledGasEnergy = (DepositUnresolvedEnergyAsThermal) - ?(coupledGasEnergy) - :(coupledGasEnergy*pow(dxRatio, -6.5)); - if (winds) coupledGasEnergy = ejectaEnergy; - float shellMetals = zZsun*0.02 * shellMass; + coupledGasEnergy = (DepositUnresolvedEnergyAsThermal) + ? (coupledGasEnergy) + : (coupledGasEnergy * pow(dxRatio, -6.5)); + if (winds) + coupledGasEnergy = ejectaEnergy; + float shellMetals = zZsun * 0.02 * shellMass; float coupledMetals = 0.0, SNIAmetals = 0.0, SNIImetals = 0.0, P3metals = 0.0; - if (winds) coupledMetals = ejectaMetal ;//+ shellMetals; // winds only couple to metallicity - if (AnalyticSNRShellMass) coupledMetals += shellMetals; + if (winds) + coupledMetals = ejectaMetal; //+ shellMetals; // winds only couple to metallicity + if (AnalyticSNRShellMass) + coupledMetals += shellMetals; SNIAmetals = (StarMakerTypeIaSNe) ? nSNIA * 1.4 : 0.0; if (!StarMakerTypeIaSNe) - coupledMetals += nSNIA*1.4; - SNIImetals = (StarMakerTypeIISNeMetalField)? nSNII*(1.91+0.0479*max(starMetal, 1.65)) : 0.0; + coupledMetals += nSNIA * 1.4; + SNIImetals = (StarMakerTypeIISNeMetalField) ? nSNII * (1.91 + 0.0479 * max(starMetal, 1.65)) : 0.0; if (!StarMakerTypeIISNeMetalField) - coupledMetals += nSNII*(1.91+0.0479*max(starMetal, 1.65)); - if (isP3 && MechStarsSeedField) P3metals = ejectaMetal; - + coupledMetals += nSNII * (1.91 + 0.0479 * max(starMetal, 1.65)); + if (isP3 && MechStarsSeedField) + P3metals = ejectaMetal; - - if (printout) fprintf(stdout, "Coupled Metals: %e %e %e %e %e %e\n", ejectaMetal, SNIAmetals, SNIImetals, shellMetals, P3metals, coupledMetals); + if (printout) + fprintf(stdout, "Coupled Metals: %e %e %e %e %e %e\n", ejectaMetal, SNIAmetals, SNIImetals, shellMetals, P3metals, coupledMetals); /* Critical debug compares the pre-feedback and post-feedback field sums. Note that this doesn't work well on vector quantities outside of an ideal test. */ - float preMass = 0, preZ = 0, preP = 0, prePmag=0, preTE = 0, preGE = 0, preZII=0, preZIa = 0; - float dsum = 0.0, zsum=0.0, psum=0.0, psqsum =0.0, tesum=0.0, gesum=0.0, kesum=0.0; - float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0, postZII=0, postZIa = 0; - if (criticalDebug && !winds){ - for (int i=0; i 0 && DualEnergyFormalism ){ + FORTRAN_NAME(cic_deposit) + (&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np, &pZ, &w[0], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (eCouple > 0 && DualEnergyFormalism) + { if (geCouple > 0) eCouple += geCouple; - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&eCouple, BaryonField[TENum], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + FORTRAN_NAME(cic_deposit) + (&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np, &eCouple, BaryonField[TENum], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); } if (geCouple > 0) - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&geCouple, BaryonField[GENum], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + FORTRAN_NAME(cic_deposit) + (&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np, &geCouple, BaryonField[GENum], LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (StarMakerTypeIISNeMetalField && zIICouple > 0.0) - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&zIICouple, metalsII, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + FORTRAN_NAME(cic_deposit) + (&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np, &zIICouple, metalsII, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); if (StarMakerTypeIaSNe && zIACouple > 0.0) - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&zIACouple, metalsIA, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (MechStarsSeedField && p3Couple > 0.0){ + FORTRAN_NAME(cic_deposit) + (&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np, &zIACouple, metalsIA, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + if (MechStarsSeedField && p3Couple > 0.0) + { //if (printout)printf("Coupling %f to pIII metals %d\n",p3Couple*MassUnits, n); - FORTRAN_NAME(cic_deposit)(&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank,&np,&p3Couple, metalsIII, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); + FORTRAN_NAME(cic_deposit) + (&CloudParticlePositionX[n], &CloudParticlePositionY[n], + &CloudParticlePositionZ[n], &GridRank, &np, &p3Couple, metalsIII, LeftEdge, + &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); } } } - // printf("\n"); + // printf("\n"); /* Deposit one negative mass particle centered on star to account for shell mass leaving host cells . Same for metals that were evacuated*/ int np = 1; - shellMass *= -1/MassUnits; - FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMass, &density[0], LeftEdge, + shellMass *= -1 / MassUnits; + FORTRAN_NAME(cic_deposit) + (xp, yp, zp, &GridRank, &np, &shellMass, density, LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - shellMetals *= -1/MassUnits; - FORTRAN_NAME(cic_deposit)(xp, yp, zp, &GridRank,&np,&shellMetals, &metals[0], LeftEdge, + shellMetals *= -1 / MassUnits; + FORTRAN_NAME(cic_deposit) + (xp, yp, zp, &GridRank, &np, &shellMetals, metals, LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); /* @@ -542,62 +575,65 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, the momentum goes uncoupled. Since the cooling radius is so small for wind enrgy (~10^15 erg), this is totally appropriate for simulations with dx > 0.25pccm or so. */ - if (winds && dx*LengthUnits/pc_cm > min_winds){ - float dm = coupledMass/(density[index]+coupledMass); + if (winds && dx * LengthUnits / pc_cm > min_winds) + { + float dm = coupledMass / (density[index] + coupledMass); density[index] += coupledMass; metals[index] += coupledMetals; - BaryonField[TENum][index] += dm*coupledEnergy/coupledMass; - BaryonField[GENum][index] += dm*coupledEnergy/coupledMass; + BaryonField[TENum][index] += dm * coupledEnergy / coupledMass; + BaryonField[GENum][index] += dm * coupledEnergy / coupledMass; } - if (criticalDebug && !winds){ - for (int i = 0; i< size ; i++){ + if (criticalDebug && !winds) + { + for (int i = 0; i < size; i++) + { postMass += BaryonField[DensNum][i]; postZ += BaryonField[MetalNum][i]; if (StarMakerTypeIISNeMetalField) postZII += BaryonField[MetalIINum][i]; if (StarMakerTypeIaSNe) postZIa += BaryonField[MetalIaNum][i]; - if (SNColourNum > 0) postZ += BaryonField[SNColourNum][i]; - postP += BaryonField[Vel1Num][i]+BaryonField[Vel2Num][i]+BaryonField[Vel3Num][i]; - postPmag += pow(BaryonField[Vel1Num][i]*MomentaUnits,2)+ - pow(BaryonField[Vel2Num][i]*MomentaUnits,2) - +pow(BaryonField[Vel3Num][i]*MomentaUnits,2); + if (SNColourNum > 0) + postZ += BaryonField[SNColourNum][i]; + postP += BaryonField[Vel1Num][i] + BaryonField[Vel2Num][i] + BaryonField[Vel3Num][i]; + postPmag += pow(BaryonField[Vel1Num][i] * MomentaUnits, 2) + + pow(BaryonField[Vel2Num][i] * MomentaUnits, 2) + pow(BaryonField[Vel3Num][i] * MomentaUnits, 2); postTE += BaryonField[TENum][i]; postGE += BaryonField[GENum][i]; } - if (printout) + if (printout) fprintf(stderr, "Difference quantities: dxRatio = %f dMass = %e dZ = %e dzII = %e dxIa = %e P = %e |P| = %e TE = %e GE = %e coupledGE = %e Ej = %e Mej = %e Zej = %e\n", - dxRatio, (postMass-preMass)*MassUnits, (postZ-preZ)*MassUnits, - (postZII-preZII)*MassUnits, (postZIa-preZIa)*MassUnits, - (postP - preP)*MomentaUnits, - (sqrt(postPmag) - sqrt(prePmag)), - (postTE-preTE)*EnergyUnits, (postGE-preGE)*EnergyUnits, - coupledGasEnergy*EnergyUnits, ejectaEnergy, - ejectaMass, ejectaMetal); - if(isnan(postMass) || isnan(postTE) || isnan(postPmag) || isnan(postZ)){ + dxRatio, (postMass - preMass) * MassUnits, (postZ - preZ) * MassUnits, + (postZII - preZII) * MassUnits, (postZIa - preZIa) * MassUnits, + (postP - preP) * MomentaUnits, + (sqrt(postPmag) - sqrt(prePmag)), + (postTE - preTE) * EnergyUnits, (postGE - preGE) * EnergyUnits, + coupledGasEnergy * EnergyUnits, ejectaEnergy, + ejectaMass, ejectaMetal); + if (isnan(postMass) || isnan(postTE) || isnan(postPmag) || isnan(postZ)) + { fprintf(stderr, "NAN IN GRID: %f %e %e %e-%e %e\n", postMass, postTE, postZ, preZ, postP); - for (float w: weightsVector){ + for (float w : weightsVector) + { fprintf(stderr, "%e\t", w); } fprintf(stderr, "\n"); exit(3); ENZO_FAIL("MechStars_depositFeedback.C: 530\n") - } } /* Transform the grid back. Skip for winds, unless VERY high resolution*/ - if (!winds || dx*LengthUnits/pc_cm < min_winds) - transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], - BaryonField[MetalIINum], BaryonField[MetalIaNum], - BaryonField[Vel1Num],BaryonField[Vel2Num], - BaryonField[Vel3Num], - BaryonField[TENum], BaryonField[GENum], - *up, *vp, *wp, - GridDimension[0], GridDimension[1], - GridDimension[2], -1); - + if (!winds || dx * LengthUnits / pc_cm < min_winds) + transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], + BaryonField[MetalIINum], BaryonField[MetalIaNum], + BaryonField[Vel1Num], BaryonField[Vel2Num], + BaryonField[Vel3Num], + BaryonField[TENum], BaryonField[GENum], + *up, *vp, *wp, + GridDimension[0], GridDimension[1], + GridDimension[2], -1); // delete [] u,v,w, gasEnergy, totalEnergy; return SUCCESS; diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 5e4695782..718eb42f8 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -8,6 +8,7 @@ #include #include #include +#include #include "ErrorExceptions.h" #include "macros_and_parameters.h" #include "typedefs.h" @@ -21,39 +22,35 @@ #include "StarParticleData.h" #include "phys_constants.h" +int determineSN(float age, int *nSNII, int *nSNIA, float massMsun, + float TimeUnits, float dtFixed); +int determineWinds(float age, float *eWinds, float *zWinds, float *mWinds, + float massMsun, float zZsun, float TimeUnits, float dtFixed); +int checkCreationCriteria(float *Density, float *Metals, + float *Temperature, float *DMField, + float *Vel1, float *Vel2, float *Vel3, + float *CoolingTime, int *GridDim, + float *shieldedFraction, float *freeFallTime, + float *dynamicalTime, int i, int j, int k, + float Time, float *RefinementField, float CellWidth, + bool *gridShouldFormStars, bool *notEnoughMetals, + int continuingFormation, int *seedIndex); +int FindField(int field, int farray[], int numfields); +int GetUnits(float *DensityUnits, float *LengthUnits, + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, float *MassUnits, FLOAT Time); +int MechStars_depositEmissivityField(int index, float cellwidth, + float *emissivity0, float age, float mass, + float TimeUnits, float dt); - int determineSN(float age, int* nSNII, int* nSNIA, float massMsun, - float TimeUnits, float dtFixed); - int determineWinds(float age, float* eWinds, float* zWinds, float* mWinds, - float massMsun, float zZsun, float TimeUnits, float dtFixed); - int checkCreationCriteria(float* Density, float* Metals, - float* Temperature,float* DMField, - float* Vel1, float* Vel2, float* Vel3, - float* CoolingTime, int* GridDim, - float* shieldedFraction, float* freeFallTime, - float* dynamicalTime, int i, int j, int k, - float Time, float* RefinementField, float CellWidth, - bool* gridShouldFormStars, bool* notEnoughMetals, - int continuingFormation, int* seedIndex); - int FindField(int field, int farray[], int numfields); - int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, float *MassUnits, FLOAT Time); - int MechStars_depositEmissivityField(int index, float cellwidth, - float* emissivity0, float age, float mass, - float TimeUnits, float dt); - - - - -int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMetal, - float* Temperature, float* CoolingTime, float* DMField) +int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMetal, + float *Temperature, float *CoolingTime, float *DMField) { //fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", - //SingleSN, StellarWinds, UnrestrictedSN); - float stretchFactor = 1.0;// radius from star particle to feedback cloud particle (in units of dx) - bool debug = true; + //SingleSN, StellarWinds, UnrestrictedSN); + float stretchFactor = 1.0; // radius from star particle to feedback cloud particle (in units of dx) + bool debug = false; float startFB = MPI_Wtime(); int dim, i, j, k, index, size, field, GhostZones = NumberOfGhostZones; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; @@ -64,40 +61,42 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta for (dim = 0; dim < GridRank; dim++) size *= GridDimension[dim]; int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, - HMNum, H2INum, H2IINum, DINum, DIINum, HDINum; + HMNum, H2INum, H2IINum, DINum, DIINum, HDINum; /* Find fields: density, total energy, velocity1-3. */ if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) { + Vel3Num, TENum) == FAIL) + { fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); return FAIL; } /* Set the units */ float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; + TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { + &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) + { fprintf(stderr, "Error in GetUnits.\n"); return FAIL; } - double dx = CellWidth[0][0]; - MassUnits = DensityUnits*pow(LengthUnits*dx, 3)/SolarMass; + FLOAT dx = CellWidth[0][0]; + MassUnits = DensityUnits * pow(LengthUnits * dx, 3) / SolarMass; /* get metallicity field and set flag; assumed true thoughout feedback since so many quantities are metallicity dependent */ - int MetallicityField = FALSE, MetalNum, SNColourNum=-1; - if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) - != -1) + int MetallicityField = FALSE, MetalNum, SNColourNum = -1; + if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) MetallicityField = TRUE; else MetalNum = 0; - if (MechStarsSeedField) + if (MechStarsSeedField) SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); /* Find and set emissivity field if being used */ int EmisNum = -1; - if (StarMakerEmissivityField){ + if (StarMakerEmissivityField) + { EmisNum = FindField(Emissivity0, FieldType, NumberOfBaryonFields); } if (EmisNum > 0) @@ -108,230 +107,298 @@ int grid::MechStars_FeedbackRoutine(int level, float* mu_field, float* totalMeta } int numSN = 0; // counter of events - int c = 0; // counter of particles - float maxD = 0.0; - int maxI=0, maxJ=0, maxK=0; - int maxindex=0; + int c = 0; // counter of particles // printf("\nIterating all particles "); - for (int pIndex=0; pIndex < NumberOfParticles; pIndex++){ + for (int pIndex = 0; pIndex < NumberOfParticles; pIndex++) + { - if (ParticleType[pIndex] == PARTICLE_TYPE_STAR - && ParticleMass[pIndex] > 100.0 - && ParticleAttribute[0][pIndex] > 0.0){ - FLOAT age = (Time-ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13;// Myr - //if (age > 1000) continue; + if (ParticleType[pIndex] == PARTICLE_TYPE_STAR && ParticleMass[pIndex] > 00.0 && ParticleAttribute[0][pIndex] > 0.0) + { + float age = (Time - ParticleAttribute[0][pIndex]) * TimeUnits / 3.1557e13; // Myr + if (age > 2500) continue; //Let really old particles become inert c++; /* get index of cell hosting particle */ - float xp = ParticlePosition[0][pIndex]; - float yp = ParticlePosition[1][pIndex]; - float zp = ParticlePosition[2][pIndex]; - - int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; - int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; - int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; - + FLOAT xp = ParticlePosition[0][pIndex]; + FLOAT yp = ParticlePosition[1][pIndex]; + FLOAT zp = ParticlePosition[2][pIndex]; + int ip = (xp - CellLeftEdge[0][0] - 0.5 * dx) / dx; + int jp = (yp - CellLeftEdge[1][0] - 0.5 * dx) / dx; + int kp = (zp - CellLeftEdge[2][0] - 0.5 * dx) / dx; /* error check particle position; Cant be on the border or outside grid If on border, reposition to within grid for CIC deposit */ - float gridDx = GridDimension[0]*dx; - float gridDy = GridDimension[1]*dx; - float gridDz = GridDimension[2]*dx; - /* Keep particle 2 cells from edge since we cant transfer to + FLOAT gridDx = GridDimension[0] * dx; + FLOAT gridDy = GridDimension[1] * dx; + FLOAT gridDz = GridDimension[2] * dx; + /* Keep particle 2 cells from edge since we cant transfer to neighboring grids */ - float borderDx = (stretchFactor+1)*dx; - if (xp > CellLeftEdge[0][0]+gridDx - || xp < CellLeftEdge[0][0] - || yp > CellLeftEdge[1][0]+gridDy - || yp < CellLeftEdge[1][0] - || zp > CellLeftEdge[2][0]+gridDz - || zp < CellLeftEdge[2][0]){ - fprintf(stderr, "Particle %d with type %d out of grid! Mass: %e\nage: %d, pos: %f, %f, %f Vel: %f %f %f\nGridEdge: %f %f %f\nGridEdge: %f %f %f\n", pIndex, - ParticleType[pIndex], age, ParticleMass[pIndex]*MassUnits, - xp, yp, zp, CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0], - ParticleVelocity[0][pIndex], ParticleVelocity[1][pIndex], ParticleVelocity[2][pIndex], - CellLeftEdge[0][0]*GridDimension[0]*CellWidth[0][0], - CellLeftEdge[1][0]*GridDimension[1]*CellWidth[0][0], - CellLeftEdge[2][0]*GridDimension[2]*CellWidth[0][0]); - EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); + FLOAT borderDx = (stretchFactor)*dx; + if (xp > CellLeftEdge[0][0] + gridDx || xp < CellLeftEdge[0][0] || yp > CellLeftEdge[1][0] + gridDy || yp < CellLeftEdge[1][0] || zp > CellLeftEdge[2][0] + gridDz || zp < CellLeftEdge[2][0]) + { + fprintf(stderr, "Particle %" ISYM " with type %" ISYM " out of grid! Mass: %" GSYM " age: %" FSYM "\npos: %" FSYM ", %" FSYM " %" FSYM ", Vel: %" FSYM " %" FSYM " %f\nLeftEdge: %" FSYM " %" FSYM " %" FSYM "\nRightEdge: %" FSYM " %" FSYM " %" FSYM "\n", + pIndex, ParticleType[pIndex], ParticleMass[pIndex] * MassUnits, + age, xp, yp, zp, + ParticleVelocity[0][pIndex] * VelocityUnits / 1e5, + ParticleVelocity[1][pIndex] * VelocityUnits / 1e5, + ParticleVelocity[2][pIndex] * VelocityUnits / 1e5, + CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0], + CellLeftEdge[0][0] + GridDimension[0] * CellWidth[0][0], + CellLeftEdge[1][0] + GridDimension[1] * CellWidth[0][0], + CellLeftEdge[2][0] + GridDimension[2] * CellWidth[0][0]); + fprintf(stderr, "Particle %d: Ct = %f Zzsun = %f TDP = %f\n", + pIndex, ParticleAttribute[0][pIndex], + ParticleAttribute[2][pIndex], + ParticleAttribute[1][pIndex]); + // EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); + FLOAT epsilon = dx; + FLOAT diff = 0.0; + /* + TEST!!!! + if the particle is only just out of grid, forcibly shift + it back to the grid. Ie., does this error compound and continue, or + is it a one-off calculation mistake?? + + */ + if (xp > CellLeftEdge[0][0] + gridDx) + { + diff = (xp - CellLeftEdge[0][0] - gridDx) / dx; + // kill if the particle is too + // far out of grid, thats a bigger problem + if (diff > 5) + raise(SIGABRT); + ParticlePosition[0][pIndex] = CellLeftEdge[0][0] + gridDx - dx; + } + if (xp < CellLeftEdge[0][0]) + { + diff = (CellLeftEdge[0][0] - xp) / dx; + if (diff > 5) + raise(SIGABRT); + ParticlePosition[0][pIndex] = CellLeftEdge[0][0] + (dx); + } + // update to y,z terms + if (yp > CellLeftEdge[1][0] + gridDy) + { + diff = (yp - CellLeftEdge[1][0] - gridDy) / dx; + if (diff > 5) + raise(SIGABRT); + ParticlePosition[1][pIndex] = CellLeftEdge[1][0] + gridDy - dx; } + if (yp < CellLeftEdge[1][0]) + { + diff = (CellLeftEdge[1][0] - yp) / dx; + if (diff > 5) + raise(SIGABRT); + ParticlePosition[1][pIndex] = CellLeftEdge[1][0] + (dx); + } + + if (zp > CellLeftEdge[2][0] + gridDz) + { + diff = (zp - CellLeftEdge[2][0] - gridDz) / dx; + if (diff > 5) + raise(SIGABRT); + ParticlePosition[2][pIndex] = CellLeftEdge[2][0] + gridDz - dx; + } + if (zp < CellLeftEdge[2][0]) + { + diff = (CellLeftEdge[2][0] - zp) / dx; + if (diff > 5) + raise(SIGABRT); + ParticlePosition[2][pIndex] = CellLeftEdge[2][0] + (dx); + } + } int shifted = 0; - if (xp < CellLeftEdge[0][0]+borderDx){ - xp = CellLeftEdge[0][0]+borderDx+0.5*dx; - shifted ++; + if (xp < CellLeftEdge[0][0] + borderDx) + { + xp = CellLeftEdge[0][0] + borderDx + 0.5 * dx; + shifted++; } - if (xp > CellLeftEdge[0][0]+gridDx-borderDx){ - xp = CellLeftEdge[0][0]+gridDx-borderDx-0.5*dx; + if (xp > CellLeftEdge[0][0] + gridDx - borderDx) + { + xp = CellLeftEdge[0][0] + gridDx - borderDx - 0.5 * dx; shifted = 1; } - if (yp < CellLeftEdge[1][0]+borderDx){ - yp = CellLeftEdge[1][0]+borderDx+0.5*dx; + if (yp < CellLeftEdge[1][0] + borderDx) + { + yp = CellLeftEdge[1][0] + borderDx + 0.5 * dx; shifted = 1; } - if (yp > CellLeftEdge[1][0]+gridDx-borderDx){ - yp = CellLeftEdge[1][0]+gridDx-borderDx-0.5*dx; + if (yp > CellLeftEdge[1][0] + gridDx - borderDx) + { + yp = CellLeftEdge[1][0] + gridDx - borderDx - 0.5 * dx; shifted = 1; } - if (zp < CellLeftEdge[2][0]+borderDx){ - zp = CellLeftEdge[2][0]+borderDx+0.5*dx; + if (zp < CellLeftEdge[2][0] + borderDx) + { + zp = CellLeftEdge[2][0] + borderDx + 0.5 * dx; shifted = 1; } - if (zp > CellLeftEdge[2][0]+gridDx-borderDx){ - zp = CellLeftEdge[2][0]+gridDx-borderDx-0.5*dx; + if (zp > CellLeftEdge[2][0] + gridDx - borderDx) + { + zp = CellLeftEdge[2][0] + gridDx - borderDx - 0.5 * dx; shifted = 1; } - // if (shifted > 0){ - // if (debug) - // fprintf(stderr, "Particle position shifted away from edge: %e: %f %f %f\n%f %f %f\n", - // age,xp, yp, zp, CellLeftEdge[0][0]+borderDx, CellLeftEdge[1][0]+borderDx, CellLeftEdge[2][0]+borderDx); - // int ip = (xp-CellLeftEdge[0][0]-0.5*dx)/dx; - // int jp = (yp-CellLeftEdge[1][0]-0.5*dx)/dx; - // int kp = (zp-CellLeftEdge[2][0]-0.5*dx)/dx; - // } - /* Check for continual formation. Continually forming new mass allows the - star particle count to stay lower, ultimately reducing runtime by having - fewer particles to iterate. - */ - index = ip+jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; + + index = ip + jp * GridDimension[0] + kp * GridDimension[0] * GridDimension[1]; float shieldedFraction = 0, dynamicalTime = 0, freeFallTime = 0; - bool gridShouldFormStars = true, notEnoughMetals=false; + bool gridShouldFormStars = true, notEnoughMetals = false; float zFraction = totalMetal[index]; - if (ParticleMass[pIndex]*MassUnits < StarMakerMaximumMass && ProblemType != 90){ - int createStar = checkCreationCriteria(BaryonField[DensNum], - &zFraction, Temperature, DMField, - BaryonField[Vel1Num], BaryonField[Vel2Num], - BaryonField[Vel3Num], - CoolingTime, GridDimension, &shieldedFraction, - &freeFallTime, &dynamicalTime, ip,jp,kp,Time, - BaryonField[NumberOfBaryonFields], CellWidth[0][0], - &gridShouldFormStars, ¬EnoughMetals, 1, NULL); - if(createStar){ - float MassShouldForm =min((shieldedFraction * BaryonField[DensNum][index] - * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13), - 0.5*BaryonField[DensNum][index]*MassUnits); + if (ParticleMass[pIndex] * MassUnits < StarMakerMaximumMass && ProblemType != 90) + /* + Check for continual formation. Continually forming new mass allows the + star particle count to stay lower, ultimately reducing runtime by having + fewer particles to iterate. + */ + { + int createStar = 0; + /* + if the age is relatively low, calculate continuing formation. + if the age is old, we'd rather form a new particle to get some more + supernova and high-power winds popping off. + */ + if (age < 50) + createStar = checkCreationCriteria(BaryonField[DensNum], + &zFraction, Temperature, DMField, + BaryonField[Vel1Num], BaryonField[Vel2Num], + BaryonField[Vel3Num], + CoolingTime, GridDimension, &shieldedFraction, + &freeFallTime, &dynamicalTime, ip, jp, kp, Time, + BaryonField[NumberOfBaryonFields], CellWidth[0][0], + &gridShouldFormStars, ¬EnoughMetals, 1, NULL); + if (createStar) + { + float MassShouldForm = min((shieldedFraction * BaryonField[DensNum][index] * MassUnits / freeFallTime * this->dtFixed * TimeUnits / 3.1557e13), + 0.5 * BaryonField[DensNum][index] * MassUnits); //printf("Adding new mass %e\n",MassShouldForm); /* Dont allow negative mass, or taking all gas in cell */ - if (MassShouldForm < 0 ) + if (MassShouldForm < 0) MassShouldForm = 0; - if (MassShouldForm > 0.5*BaryonField[DensNum][index]*MassUnits) - MassShouldForm = 0.5*BaryonField[DensNum][index]*MassUnits; + if (MassShouldForm > 0.5 * BaryonField[DensNum][index] * MassUnits) + MassShouldForm = 0.5 * BaryonField[DensNum][index] * MassUnits; // Set units and modify particle MassShouldForm /= MassUnits; - if (MassShouldForm > 0){ - float delta = MassShouldForm/(ParticleMass[pIndex]+MassShouldForm); + if (MassShouldForm > 0) + { + float delta = MassShouldForm / (ParticleMass[pIndex] + MassShouldForm); - /* modify metallicity */ + /* fractional metallicity */ zFraction /= BaryonField[DensNum][index]; // update mass-weighted metallicity fraction of star particle - ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex]*ParticleMass[pIndex]+zFraction*MassShouldForm)/ - (ParticleMass[pIndex] + MassShouldForm); - // update mass-weighted age of star particle - // if (age > 3.5) // only update if particle is old enough for SNe - // ParticleAttribute[0][pIndex] = (ParticleAttribute[0][pIndex]*(1.-delta)+Time*delta); + ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex] * ParticleMass[pIndex] + zFraction * MassShouldForm) / + (ParticleMass[pIndex] + MassShouldForm); /* Add new formation mass to particle */ - if (MassShouldForm < 0.5*BaryonField[DensNum][index]){ - ParticleMass[pIndex] += MassShouldForm; - printf("[%f] added new mass %e + %e = %e newZ = %f newAge = %f\n", - Time*TimeUnits/3.1557e13, (ParticleMass[pIndex]-MassShouldForm)*MassUnits, - MassShouldForm*MassUnits, ParticleMass[pIndex]*MassUnits, - ParticleAttribute[2][pIndex],(Time- ParticleAttribute[0][pIndex])*TimeUnits/3.1557e13); - + if (MassShouldForm < 0.5 * BaryonField[DensNum][index]) + { + ParticleMass[pIndex] += MassShouldForm; + printf("[%f] added new mass %e + %e = %e newZ = %f newAge = %f\n", + Time * TimeUnits / 3.1557e13, (ParticleMass[pIndex] - MassShouldForm) * MassUnits, + MassShouldForm * MassUnits, ParticleMass[pIndex] * MassUnits, + ParticleAttribute[2][pIndex], (Time - ParticleAttribute[0][pIndex]) * TimeUnits / 3.1557e13); + /* Take formed mass out of grid cell */ - + BaryonField[DensNum][index] -= MassShouldForm; - + /* Take metals out of host cell too! */ - BaryonField[MetalNum][index] -= BaryonField[MetalNum][index]/BaryonField[DensNum][index]*MassShouldForm; + BaryonField[MetalNum][index] -= BaryonField[MetalNum][index] / BaryonField[DensNum][index] * MassShouldForm; if (MechStarsSeedField) - BaryonField[SNColourNum][index] -= BaryonField[SNColourNum][index]/BaryonField[DensNum][index]*MassShouldForm; + BaryonField[SNColourNum][index] -= BaryonField[SNColourNum][index] / BaryonField[DensNum][index] * MassShouldForm; } } } } - + /* Start actual feedback: Supernova calculations */ + int nSNII = 0; int nSNIA = 0; float SNMassEjected = 0, SNMetalEjected = 0; - //fprintf(stdout, "Checking particle: %f %e \n", age, ParticleMass[pIndex]*MassUnits); + /* determine how many supernova events */ + if (SingleSN) { - // fprintf(stdout,"Checking for SN age = %f\n", age); - determineSN(age, &nSNII, &nSNIA, ParticleMass[pIndex]*MassUnits, + /* + Determine SN events from rates (currently taken from + Hopkins, 2018) + */ + determineSN(age, &nSNII, &nSNIA, ParticleMass[pIndex] * MassUnits, TimeUnits, dtFixed); - numSN += nSNII+nSNIA; - if ((nSNII > 0 || nSNIA > 0) && debug) - fprintf(stdout,"SUPERNOVAE!!!! %d %d level = %d age = %f\n", nSNII, nSNIA, level, age); - if (nSNII > 0 || nSNIA > 0){ + numSN += nSNII + nSNIA; + if ((nSNII > 0 || nSNIA > 0) && debug) + fprintf(stdout, "SUPERNOVAE!!!! %d %d level = %d age = %f\n", nSNII, nSNIA, level, age); + if (nSNII > 0 || nSNIA > 0) + { /* set feedback qtys based on number and types of events */ - /* 1e51 erg per sn */ - float energySN = (nSNII + nSNIA)*1e51; + /* 1e51 erg per sn */ + float energySN = (nSNII + nSNIA) * 1e51; - /*10.5 Msun ejecta for type II and IA*/ - SNMassEjected = (nSNII+nSNIA)*10.5; - float starMetal = (ParticleAttribute[2][pIndex]/0.02); //determines metal content of SNeII + /*10.5 Msun ejecta for type II and IA*/ + SNMassEjected = (nSNII + nSNIA) * 10.5; + float starMetal = (ParticleAttribute[2][pIndex] / 0.02); //determines metal content of SNeII MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, Temperature, - &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], - &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], - ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, starMetal, 0); + &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], + &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], + ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, starMetal, 0); + // can only track number of events in dynamical time if not using it to determine lifetime + if (!StarParticleRadiativeFeedback) - ParticleAttribute[1][pIndex] += nSNII+nSNIA; + ParticleAttribute[1][pIndex] += nSNII + nSNIA; } } /* Do the same for winds. Cooling Radius is very small, So almost no energy is coupled, but some mass may be. */ - float windEnergy=0, windMass=0, windMetals=0; + float windEnergy = 0, windMass = 0, windMetals = 0; /* Ignore very old stars, veryvery young stars, and ones whose mass is depleted */ - if (StellarWinds && age > 0.001 && ParticleMass[pIndex]*MassUnits > 1) + if (StellarWinds && age > 0.001 && ParticleMass[pIndex] * MassUnits > 1) { // printf("Checking Winds\n"); - float zZsun = min(ParticleAttribute[2][pIndex]/0.02, MechStarsCriticalMetallicity); + float zZsun = min(ParticleAttribute[2][pIndex] / 0.02, MechStarsCriticalMetallicity); determineWinds(age, &windEnergy, &windMass, &windMetals, - ParticleMass[pIndex]*MassUnits, zZsun, - TimeUnits, dtFixed); - if (windMass > 10) fprintf(stdout,"Really High Wind Mass!!\n"); - if (windEnergy > 1e5){ + ParticleMass[pIndex] * MassUnits, zZsun, + TimeUnits, dtFixed); + if (windMass > 100) + fprintf(stdout, "Really High Wind Mass = %e\n", windMass); + if (windEnergy > 1e5) + { //printf("Winds: M = %e E=%e\n", windMass, windEnergy); MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, Temperature, - &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], - &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], - ip, jp, kp, size, mu_field, 1, 0, 0, 0.0, 0); + &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], + &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], + ip, jp, kp, size, mu_field, 1, 0, 0, 0.0, 0); } - } - if (windMass > 0.0 || SNMassEjected > 0){ - ParticleMass[pIndex] -= (windMass+SNMassEjected)/MassUnits; + if (windMass > 0.0 || SNMassEjected > 0) + { + ParticleMass[pIndex] -= (windMass + SNMassEjected) / MassUnits; } - /* if these stars are used in conjunction with FLDImplicit or FLDSplit. This - functionality has not been verified + /* + if these stars are used in conjunction with FLDImplicit or FLDSplit. This functionality has not been verified */ - if (StarMakerEmissivityField){ - MechStars_depositEmissivityField(index, CellWidth[0][0], BaryonField[EmisNum], - age, ParticleMass[pIndex]*MassUnits, TimeUnits, dtFixed); + if (StarMakerEmissivityField) + { + MechStars_depositEmissivityField(index, CellWidth[0][0], BaryonField[EmisNum], + age, ParticleMass[pIndex] * MassUnits, TimeUnits, dtFixed); } - // printf("Post-feedback MP = %e\n", ParticleMass[pIndex]*MassUnits); } - }// end iteration over particles - if (c > 0){ + } // end iteration over particles + if (c > 0) + { fprintf(stdout, "Ptcl Number = %d Events = %d FeedbackTime = %e Size = %d\n", - c, numSN, MPI_Wtime()-startFB, GridDimension[0]*GridDimension[1]*GridDimension[2]); + c, numSN, MPI_Wtime() - startFB, GridDimension[0] * GridDimension[1] * GridDimension[2]); } - /* to avoid iterating deposition over 10k particles, do ONE winds feedback that is summed all wind feedback in the region, - centered on the most massive cell in the grid*/ - // delete [] totalMetal; return SUCCESS; } diff --git a/src/enzo/MechStars_determineSN.C b/src/enzo/MechStars_determineSN.C index 90bbd93c1..fafae8c7d 100644 --- a/src/enzo/MechStars_determineSN.C +++ b/src/enzo/MechStars_determineSN.C @@ -92,8 +92,8 @@ int determineSN(float age, int* nSNII, int* nSNIA, if (random < PIA) *nSNIA = psn+1; - if (*nSNIA > 0) - fprintf(stdout, "PIA = %f\n", PIA); + // if (*nSNIA > 0) + // fprintf(stdout, "PIA = %f\n", PIA); } } return SUCCESS; From 52dd8d1d3e6ccfd91b20d898a0ac626393c49354 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 7 Nov 2019 13:12:21 -0600 Subject: [PATCH 034/115] removed debug sections that should exist on the debug branch only --- src/enzo/Grid_MechStarsFeedbackRoutine.C | 57 +----------------------- 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 718eb42f8..322bb6780 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -115,7 +115,6 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta if (ParticleType[pIndex] == PARTICLE_TYPE_STAR && ParticleMass[pIndex] > 00.0 && ParticleAttribute[0][pIndex] > 0.0) { float age = (Time - ParticleAttribute[0][pIndex]) * TimeUnits / 3.1557e13; // Myr - if (age > 2500) continue; //Let really old particles become inert c++; /* get index of cell hosting particle */ @@ -153,61 +152,7 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta ParticleAttribute[2][pIndex], ParticleAttribute[1][pIndex]); // EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); - FLOAT epsilon = dx; - FLOAT diff = 0.0; - /* - TEST!!!! - if the particle is only just out of grid, forcibly shift - it back to the grid. Ie., does this error compound and continue, or - is it a one-off calculation mistake?? - - */ - if (xp > CellLeftEdge[0][0] + gridDx) - { - diff = (xp - CellLeftEdge[0][0] - gridDx) / dx; - // kill if the particle is too - // far out of grid, thats a bigger problem - if (diff > 5) - raise(SIGABRT); - ParticlePosition[0][pIndex] = CellLeftEdge[0][0] + gridDx - dx; - } - if (xp < CellLeftEdge[0][0]) - { - diff = (CellLeftEdge[0][0] - xp) / dx; - if (diff > 5) - raise(SIGABRT); - ParticlePosition[0][pIndex] = CellLeftEdge[0][0] + (dx); - } - // update to y,z terms - if (yp > CellLeftEdge[1][0] + gridDy) - { - diff = (yp - CellLeftEdge[1][0] - gridDy) / dx; - if (diff > 5) - raise(SIGABRT); - ParticlePosition[1][pIndex] = CellLeftEdge[1][0] + gridDy - dx; - } - if (yp < CellLeftEdge[1][0]) - { - diff = (CellLeftEdge[1][0] - yp) / dx; - if (diff > 5) - raise(SIGABRT); - ParticlePosition[1][pIndex] = CellLeftEdge[1][0] + (dx); - } - - if (zp > CellLeftEdge[2][0] + gridDz) - { - diff = (zp - CellLeftEdge[2][0] - gridDz) / dx; - if (diff > 5) - raise(SIGABRT); - ParticlePosition[2][pIndex] = CellLeftEdge[2][0] + gridDz - dx; - } - if (zp < CellLeftEdge[2][0]) - { - diff = (CellLeftEdge[2][0] - zp) / dx; - if (diff > 5) - raise(SIGABRT); - ParticlePosition[2][pIndex] = CellLeftEdge[2][0] + (dx); - } + raise(SIGABRT); // fails more quickly and puts out a core dump for analysis } int shifted = 0; From d509b05ed3560beabf85fda5deffeaf0a9638060 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 8 Nov 2019 13:32:25 -0600 Subject: [PATCH 035/115] repurposed DepositUnresolvedEnergyAsThermal parameter; now controls whether winds are deposited CIC (0) or NGP (1) --- src/enzo/Grid_MechStarsDepositFeedback.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 693228e79..fa3c89d84 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -475,7 +475,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, As a computational compromize, supernova are deposited CIC, but winds are deposited NGP. At VERY high resolution, well still do CIC for winds */ - if (!winds || dx * LengthUnits / pc_cm < min_winds) + if (!DepositUnresolvedEnergyAsThermal) { for (int n = 0; n < nCouple; ++n) { @@ -575,7 +575,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, the momentum goes uncoupled. Since the cooling radius is so small for wind enrgy (~10^15 erg), this is totally appropriate for simulations with dx > 0.25pccm or so. */ - if (winds && dx * LengthUnits / pc_cm > min_winds) + if (DepositUnresolvedEnergyAsThermal) { float dm = coupledMass / (density[index] + coupledMass); density[index] += coupledMass; From 26b63617ea5a6cf6586dbfe130909ae6ca6c36f7 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 8 Nov 2019 13:39:16 -0600 Subject: [PATCH 036/115] edited bounds check of particle position to check against grid edge instead of cell edge --- src/enzo/Grid_MechStarsFeedbackRoutine.C | 26 +++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 322bb6780..2ef425ad8 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -135,22 +135,28 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta /* Keep particle 2 cells from edge since we cant transfer to neighboring grids */ FLOAT borderDx = (stretchFactor)*dx; - if (xp > CellLeftEdge[0][0] + gridDx || xp < CellLeftEdge[0][0] || yp > CellLeftEdge[1][0] + gridDy || yp < CellLeftEdge[1][0] || zp > CellLeftEdge[2][0] + gridDz || zp < CellLeftEdge[2][0]) + if (xp > GridRightEdge[0] + || xp < GridLeftEdge[0] + || yp > GridRightEdge[1] + || yp < GridLeftEdge[1] + || zp > GridRightEdge[2] + || zp < GridLeftEdge[2]) { - fprintf(stderr, "Particle %" ISYM " with type %" ISYM " out of grid! Mass: %" GSYM " age: %" FSYM "\npos: %" FSYM ", %" FSYM " %" FSYM ", Vel: %" FSYM " %" FSYM " %f\nLeftEdge: %" FSYM " %" FSYM " %" FSYM "\nRightEdge: %" FSYM " %" FSYM " %" FSYM "\n", - pIndex, ParticleType[pIndex], ParticleMass[pIndex] * MassUnits, + fprintf(stderr, "[%d--%e] Particle %" ISYM " with type %" ISYM " out of grid! Mass: %" GSYM " age: %" FSYM "\npos: %" FSYM ", %" FSYM " %" FSYM ", Vel: %" FSYM " %" FSYM " %f\nLeftEdge: %" FSYM " %" FSYM " %" FSYM "\nRightEdge: %" FSYM " %" FSYM " %" FSYM "\n", + level, dx, pIndex, ParticleType[pIndex], ParticleMass[pIndex] * MassUnits, age, xp, yp, zp, - ParticleVelocity[0][pIndex] * VelocityUnits / 1e5, - ParticleVelocity[1][pIndex] * VelocityUnits / 1e5, - ParticleVelocity[2][pIndex] * VelocityUnits / 1e5, - CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0], - CellLeftEdge[0][0] + GridDimension[0] * CellWidth[0][0], - CellLeftEdge[1][0] + GridDimension[1] * CellWidth[0][0], - CellLeftEdge[2][0] + GridDimension[2] * CellWidth[0][0]); + ParticleVelocity[0][pIndex], + ParticleVelocity[1][pIndex], + ParticleVelocity[2][pIndex], + GridLeftEdge[0], GridLeftEdge[1], GridLeftEdge[2], + GridRightEdge[0], GridRightEdge[1], GridRightEdge[2]); fprintf(stderr, "Particle %d: Ct = %f Zzsun = %f TDP = %f\n", pIndex, ParticleAttribute[0][pIndex], ParticleAttribute[2][pIndex], ParticleAttribute[1][pIndex]); + fprintf(stderr, "Accelerations: %"FSYM", %"FSYM", %"FSYM"\n", + ParticleAcceleration[0][pIndex], ParticleAcceleration[1][pIndex], + ParticleAcceleration[2][pIndex]); // EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); raise(SIGABRT); // fails more quickly and puts out a core dump for analysis } From fb93a2f595ff770f6e88ac215816f37dd8f7609d Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 9 Nov 2019 11:05:33 -0600 Subject: [PATCH 037/115] Removed enforced failure for stars being out of grid; this is resulting from the enzo algorithm and isn't actually a failure--the stars should be corrected/communicated at the next step, and if they arent its an entirely different problem --- src/enzo/Grid_MechStarsFeedbackRoutine.C | 53 +++++++++++++----------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 2ef425ad8..3d206701d 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -135,31 +135,34 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta /* Keep particle 2 cells from edge since we cant transfer to neighboring grids */ FLOAT borderDx = (stretchFactor)*dx; - if (xp > GridRightEdge[0] - || xp < GridLeftEdge[0] - || yp > GridRightEdge[1] - || yp < GridLeftEdge[1] - || zp > GridRightEdge[2] - || zp < GridLeftEdge[2]) - { - fprintf(stderr, "[%d--%e] Particle %" ISYM " with type %" ISYM " out of grid! Mass: %" GSYM " age: %" FSYM "\npos: %" FSYM ", %" FSYM " %" FSYM ", Vel: %" FSYM " %" FSYM " %f\nLeftEdge: %" FSYM " %" FSYM " %" FSYM "\nRightEdge: %" FSYM " %" FSYM " %" FSYM "\n", - level, dx, pIndex, ParticleType[pIndex], ParticleMass[pIndex] * MassUnits, - age, xp, yp, zp, - ParticleVelocity[0][pIndex], - ParticleVelocity[1][pIndex], - ParticleVelocity[2][pIndex], - GridLeftEdge[0], GridLeftEdge[1], GridLeftEdge[2], - GridRightEdge[0], GridRightEdge[1], GridRightEdge[2]); - fprintf(stderr, "Particle %d: Ct = %f Zzsun = %f TDP = %f\n", - pIndex, ParticleAttribute[0][pIndex], - ParticleAttribute[2][pIndex], - ParticleAttribute[1][pIndex]); - fprintf(stderr, "Accelerations: %"FSYM", %"FSYM", %"FSYM"\n", - ParticleAcceleration[0][pIndex], ParticleAcceleration[1][pIndex], - ParticleAcceleration[2][pIndex]); - // EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); - raise(SIGABRT); // fails more quickly and puts out a core dump for analysis - } + if (xp > GridRightEdge[0] + || xp < GridLeftEdge[0] + || yp > GridRightEdge[1] + || yp < GridLeftEdge[1] + || zp > GridRightEdge[2] + || zp < GridLeftEdge[2]) + { + if (debug){ + fprintf(stderr, "[%d--%e] Particle %" ISYM " with type %" ISYM " out of grid! Mass: %" GSYM " age: %" FSYM "\npos: %" FSYM ", %" FSYM " %" FSYM ", Vel: %" FSYM " %" FSYM " %f\nLeftEdge: %" FSYM " %" FSYM " %" FSYM "\nRightEdge: %" FSYM " %" FSYM " %" FSYM "\n", + level, dx, pIndex, ParticleType[pIndex], ParticleMass[pIndex] * MassUnits, + age, xp, yp, zp, + ParticleVelocity[0][pIndex], + ParticleVelocity[1][pIndex], + ParticleVelocity[2][pIndex], + GridLeftEdge[0], GridLeftEdge[1], GridLeftEdge[2], + GridRightEdge[0], GridRightEdge[1], GridRightEdge[2]); + fprintf(stderr, "Particle %d: Ct = %f Zzsun = %f TDP = %f\n", + pIndex, ParticleAttribute[0][pIndex], + ParticleAttribute[2][pIndex], + ParticleAttribute[1][pIndex]); + fprintf(stderr, "Accelerations: %"FSYM", %"FSYM", %"FSYM"\n", + ParticleAcceleration[0][pIndex], ParticleAcceleration[1][pIndex], + ParticleAcceleration[2][pIndex]); + } + continue; + // EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); + //raise(SIGABRT); // fails more quickly and puts out a core dump for analysis + } int shifted = 0; if (xp < CellLeftEdge[0][0] + borderDx) From 16192143d72f4638c2a032d9c0e030d8bb7b4aa2 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sun, 24 Nov 2019 20:17:21 -0600 Subject: [PATCH 038/115] Corrected calculation of f_shielded --- src/enzo/MechStars_checkCreationCriteria.C | 34 +++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index 6395bcca4..703b097e8 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -43,6 +43,7 @@ int checkCreationCriteria(float* Density, float* Metals, fprintf(stderr, "Error in GetUnits.\n"); return FAIL; } + MassUnits = DensityUnits*pow(LengthUnits*CellWidth, 3); int index = i+j*GridDim[0]+k*GridDim[0]*GridDim[1]; int iminus = index-1; int iplus = index+1; @@ -63,7 +64,7 @@ int checkCreationCriteria(float* Density, float* Metals, + Density[kplus])/17.0; if (dmean < StarMakerOverDensityThreshold) { - status = FAIL; + return FAIL; } // if (debug && status) fprintf(stdout, "Passed Density: %e: %e\n", // dmean,StarMakerOverDensityThreshold); @@ -92,7 +93,7 @@ int checkCreationCriteria(float* Density, float* Metals, /* Chck for converging flow */ div = dxvx+dyvy+dzvz; - if (div > 0.0) status = FAIL; + if (div > 0.0) return FAIL; /* check for virial parameter */ @@ -109,17 +110,17 @@ int checkCreationCriteria(float* Density, float* Metals, - if (alpha > 1.0) status = FAIL; + if (alpha > 1.0) return FAIL; /* Is cooling time < dynamical time or temperature < 1e4 */ if (Temperature[index] > 1e4) { - if (MultiSpecies > 0) status = FAIL; //no hot gas forming stars! + if (MultiSpecies > 0) return FAIL; //no hot gas forming stars! float totalDensity = (Density[index] +DMField[index])*DensityUnits; *dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); if (*dynamicalTime/TimeUnits < CoolingTime[index]) - status = FAIL; + return FAIL; } /* is gas mass > critical jeans mass? */ @@ -130,7 +131,7 @@ int checkCreationCriteria(float* Density, float* Metals, float IsoSndSpeed = 1.3095e8 * Temperature[index]; float jeansMass = pi/(6.0*pow(Density[index]*DensityUnits, 0.5)) *pow(pi*IsoSndSpeed/GravConst, 1.5)/SolarMass; - if (jeansMass > max(baryonMass, 1e3)) status = FAIL; + if (jeansMass > max(baryonMass, 1e3)) return FAIL; /* Is self Shielded fraction > 0.0 by Krumholz & Gnedin */ @@ -142,23 +143,27 @@ int checkCreationCriteria(float* Density, float* Metals, *(Density[kplus]-Density[kminus]); gradRho = pow(gradRho, 0.5); // factors were given in physical units - float TauFactor = 434.8 *LengthUnits*LengthUnits / MassUnits; + float TauFactor = 434.8/*cm**2/g*/ * MassUnits/pow(LengthUnits*CellWidth, 2); // cm**2/g float Tau = TauFactor * Density[index] *(CellWidth+Density[index]/gradRho); float Phi = 0.756*pow(1+3.1*Metals[index]/Density[index]/0.02, 0.365); float Psi = 0.6*Tau*(0.01+Metals[index]/Density[index]/0.02)/ log(1+0.6*Phi+0.01*Phi*Phi); - - *shieldedFraction = 1 - 3/(1+4*Psi); + *shieldedFraction = 1.0 - 3.0/(1.0+4.0*Psi); + fprintf(stdout, "FS parts: Tau = %"GSYM" Phi = %"GSYM" Psi = %"GSYM" FS = %"GSYM"\n", + Tau, Phi, Psi, *shieldedFraction); + if (*shieldedFraction < 0) status = FAIL; *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; - - if (status && debug && (Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity || !MechStarsSeedField)){ - //printf("CreationCriteria f_s = %f vf = %e cs = %e Gcode = %e Alpha = %e Z-sun=%e localRho = %f\n", - // *shieldedFraction, vfactor, cSound, Gcode, alpha, Metals[index]/Density[index]/0.02, Density[index]); - return PASS; + if (status && debug) + { + fprintf(stdout, "Check Creation positive! rho = %"GSYM" gradRho = %"GSYM" Fs = %"FSYM" M_j = %"GSYM" VirialPar = %"FSYM" divergence = %"FSYM" Temperature = %"GSYM"\n", + Density[index], gradRho, *shieldedFraction, jeansMass, alpha, div, Temperature[index]); + } + if (status && (Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity || !MechStarsSeedField)){ + return status; } //if (status && debug) fprintf(stdout, "passed creation criteria\n"); if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity && !continuingFormation) @@ -177,6 +182,7 @@ int checkCreationCriteria(float* Density, float* Metals, seedIndex[1] = j; seedIndex[2] = k; } + return status; } From 6eb6b04f64b0681d0e29305a9b26cebb02e0b22f Mon Sep 17 00:00:00 2001 From: John Regan Date: Mon, 2 Dec 2019 11:34:23 +0000 Subject: [PATCH 039/115] Updating some minor SS parameters --- src/enzo/ActiveParticle.h | 2 +- src/enzo/SetDefaultGlobalValues.C | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enzo/ActiveParticle.h b/src/enzo/ActiveParticle.h index f0ffeecd6..3920d52ab 100644 --- a/src/enzo/ActiveParticle.h +++ b/src/enzo/ActiveParticle.h @@ -23,7 +23,7 @@ #include "ParticleAttributeHandler.h" #include "h5utilities.h" #include -#define NTIMES 2000 +#define NTIMES 10000 template class ActiveParticleList; struct ActiveParticleFormationData; struct ActiveParticleFormationDataFlags; diff --git a/src/enzo/SetDefaultGlobalValues.C b/src/enzo/SetDefaultGlobalValues.C index 3060ce161..d9bb87ccd 100644 --- a/src/enzo/SetDefaultGlobalValues.C +++ b/src/enzo/SetDefaultGlobalValues.C @@ -1067,7 +1067,7 @@ int SetDefaultGlobalValues(TopGridData &MetaData) SmartStarJetVelocity = 1e-1; //as a fraction of clight SmartStarSuperEddingtonAdjustment = TRUE; SmartStarSpin = 0.7; - SmartStarSMSLifetime = 1e6; //1 Myr + SmartStarSMSLifetime = 2e6; //2 Myr /* Gas drag parameters */ UseGasDrag = 0; GasDragCoefficient = 0.; From 384a7621b0162efd6103b6fe2af6bd3b1678ada3 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sun, 8 Dec 2019 08:48:44 -0800 Subject: [PATCH 040/115] Added new refinement criteria to refine PopIII stars; also added section to check and rescale densities of Pop III deposition to ensure mass/metal conservation --- src/enzo/Grid.h | 4 + src/enzo/Grid_AddFeedbackSphere.C | 1788 ++++++++++-------- src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C | 144 ++ src/enzo/Grid_SetFlaggingField.C | 9 + src/enzo/Star.h | 1 + 5 files changed, 1126 insertions(+), 820 deletions(-) create mode 100644 src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index 338da59d8..842752c9f 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -973,6 +973,10 @@ gradient force to gravitational force for one-zone collapse test. */ int FlagCellsToBeRefinedByMetalMass(int level); +/* Flag cells surrounding PopIII stars */ + + int FlagCellsToBeRefinedByPopIII(int level); + /* Flagging all cell adjacent to a previous flagged cell. Also, remove all Flagged cells in the boundary zones and within one zone of the boundary. */ diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 6a16ebd18..46b3022b3 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -8,7 +8,9 @@ / July, 2009 / modified2: Ji-hoon Kim to include MBH_JETS feedback / November, 2009 -/ +/ modified3: Azton Wells; corrected supernova deposition to +/ be mass and energy conserving. +/ December 2019 / PURPOSE: / ************************************************************************/ @@ -44,608 +46,732 @@ int FindField(int field, int farray[], int numfields); -int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityUnits, - float LengthUnits, float VelocityUnits, - float TemperatureUnits, float TimeUnits, double EjectaDensity, - double EjectaMetalDensity, double EjectaThermalEnergy, - double Q_HI, double sigma_HI, float deltaE, int &CellsModified) +int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityUnits, + float LengthUnits, float VelocityUnits, + float TemperatureUnits, float TimeUnits, double EjectaDensity, + double EjectaMetalDensity, double EjectaThermalEnergy, + double Q_HI, double sigma_HI, float deltaE, int &CellsModified) { - const float WhalenMaxVelocity = 35; // km/s + const float WhalenMaxVelocity = 35; // km/s + + int dim, i, j, k, index; + int sx, sy, sz; + FLOAT delx, dely, delz, radius2, Radius, DomainWidth[MAX_DIMENSION]; + float coef, speed, maxVelocity; + float OldDensity; + float r1, norm, ramp, factor, newGE, fh; + double increase; + + if (MyProcessorNumber != ProcessorNumber) + return SUCCESS; - int dim, i, j, k, index; - int sx, sy, sz; - FLOAT delx, dely, delz, radius2, Radius, DomainWidth[MAX_DIMENSION]; - float coef, speed, maxVelocity; - float OldDensity; - float r1, norm, ramp, factor, newGE, fh; - double increase; + /* If the radius is less than the cell width, return */ - if (MyProcessorNumber != ProcessorNumber) - return SUCCESS; + if (radius < CellWidth[0][0]) + return SUCCESS; - /* If the radius is less than the cell width, return */ - - if (radius < CellWidth[0][0]) - return SUCCESS; + /* Check if sphere overlaps with this grid */ - /* Check if sphere overlaps with this grid */ + for (dim = 0; dim < GridRank; dim++) + if (cstar->pos[dim] - radius > GridRightEdge[dim] || + cstar->pos[dim] + radius < GridLeftEdge[dim]) + return SUCCESS; - for (dim = 0; dim < GridRank; dim++) - if (cstar->pos[dim] - radius > GridRightEdge[dim] || - cstar->pos[dim] + radius < GridLeftEdge[dim]) - return SUCCESS; + for (dim = 0; dim < GridRank; dim++) + DomainWidth[dim] = DomainRightEdge[dim] - DomainLeftEdge[dim]; - for (dim = 0; dim < GridRank; dim++) - DomainWidth[dim] = DomainRightEdge[dim] - DomainLeftEdge[dim]; + /* Find fields: density, total energy, velocity1-3. */ - /* Find fields: density, total energy, velocity1-3. */ + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) + { + ENZO_FAIL("Error in IdentifyPhysicalQuantities."); + } - int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; - if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) { - ENZO_FAIL("Error in IdentifyPhysicalQuantities."); - } - - /* Find Multi-species fields. */ + /* Find Multi-species fields. */ - int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, - DINum, DIINum, HDINum; - if (MultiSpecies) - if (this->IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, - HeIIINum, HMNum, H2INum, H2IINum, DINum, - DIINum, HDINum) == FAIL) { - ENZO_FAIL("Error in grid->IdentifySpeciesFields."); - } + int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, + DINum, DIINum, HDINum; + if (MultiSpecies) + if (this->IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, + HeIIINum, HMNum, H2INum, H2IINum, DINum, + DIINum, HDINum) == FAIL) + { + ENZO_FAIL("Error in grid->IdentifySpeciesFields."); + } - fh = CoolData.HydrogenFractionByMass; + fh = CoolData.HydrogenFractionByMass; - /* Find Metallicity or SNColour field and set flag. */ + /* Find Metallicity or SNColour field and set flag. */ - int SNColourNum, MetalNum, Metal2Num, MBHColourNum, Galaxy1ColourNum, - Galaxy2ColourNum, MetalIaNum, MetalIINum; - int MetallicityField = FALSE; + int SNColourNum, MetalNum, Metal2Num, MBHColourNum, Galaxy1ColourNum, + Galaxy2ColourNum, MetalIaNum, MetalIINum; + int MetallicityField = FALSE; - if (this->IdentifyColourFields(SNColourNum, Metal2Num, MetalIaNum, - MetalIINum, MBHColourNum, Galaxy1ColourNum, - Galaxy2ColourNum) == FAIL) - ENZO_FAIL("Error in grid->IdentifyColourFields.\n"); + if (this->IdentifyColourFields(SNColourNum, Metal2Num, MetalIaNum, + MetalIINum, MBHColourNum, Galaxy1ColourNum, + Galaxy2ColourNum) == FAIL) + ENZO_FAIL("Error in grid->IdentifyColourFields.\n"); - MetalNum = max(Metal2Num, SNColourNum); - MetallicityField = (MetalNum > 0) ? TRUE : FALSE; - if (MetalNum > 0 && SNColourNum > 0 && cstar->type == PopIII) - MetalNum = SNColourNum; + MetalNum = max(Metal2Num, SNColourNum); + MetallicityField = (MetalNum > 0) ? TRUE : FALSE; + if (MetalNum > 0 && SNColourNum > 0 && cstar->type == PopIII) + MetalNum = SNColourNum; - float BubbleVolume = (4.0 * pi / 3.0) * radius * radius * radius; + float BubbleVolume = (4.0 * pi / 3.0) * radius * radius * radius; - /*********************************************************************** + /*********************************************************************** SUPERNOVAE ************************************************************************/ - // Assume that the remnant is still in the free expansion stage and - // hasn't had any radiative losses. In this case, the ejecta will - // be at 3/4 the radius of the shock front (see Ostriker & McKee - // 1988 or Tenorio-Tagle 1996). + // Assume that the remnant is still in the free expansion stage and + // hasn't had any radiative losses. In this case, the ejecta will + // be at 3/4 the radius of the shock front (see Ostriker & McKee + // 1988 or Tenorio-Tagle 1996). - //const float MetalRadius = 0.75; - const float MetalRadius = 1.0; - float ionizedFraction = 0.999; // Assume supernova is ionized - float maxGE, MetalRadius2, PrimordialDensity, metallicity, fhz, fhez; - float outerRadius2, delta_fz; + //const float MetalRadius = 0.75; + const float MetalRadius = 1.0; + float ionizedFraction = 0.999; // Assume supernova is ionized + float maxGE, MetalRadius2, PrimordialDensity, metallicity, fhz, fhez; + float outerRadius2, delta_fz; - if (cstar->FeedbackFlag == SUPERNOVA || - cstar->FeedbackFlag == CONT_SUPERNOVA) { + if (cstar->FeedbackFlag == SUPERNOVA || + cstar->FeedbackFlag == CONT_SUPERNOVA) + { - // Correct for exaggerated influence radius for pair-instability supernovae - if (cstar->FeedbackFlag == SUPERNOVA) - radius /= 1.0; + // Correct for exaggerated influence radius for pair-instability supernovae + if (cstar->FeedbackFlag == SUPERNOVA) + radius /= 1.0; - // Correct if the volume with 27 cells is larger than the energy bubble volume + // Correct if the volume with 27 cells is larger than the energy bubble volume #ifdef UNUSED - float BoxVolume = 27 * CellWidth[0][0] * CellWidth[0][0] * CellWidth[0][0]; - float BubbleVolume = (4.0 * pi / 3.0) * radius * radius * radius; - //printf("BoxVolume = %lg, BubbleVolume = %lg\n", BoxVolume, BubbleVolume); - if (BoxVolume > BubbleVolume) { - //printf("Reducing ejecta density by %g\n", BubbleVolume / BoxVolume); - EjectaDensity *= BubbleVolume / BoxVolume; - EjectaMetalDensity *= BubbleVolume / BoxVolume; - EjectaThermalEnergy *= BubbleVolume / BoxVolume; - } + float BoxVolume = 27 * CellWidth[0][0] * CellWidth[0][0] * CellWidth[0][0]; + float BubbleVolume = (4.0 * pi / 3.0) * radius * radius * radius; + //printf("BoxVolume = %lg, BubbleVolume = %lg\n", BoxVolume, BubbleVolume); + if (BoxVolume > BubbleVolume) + { + //printf("Reducing ejecta density by %g\n", BubbleVolume / BoxVolume); + EjectaDensity *= BubbleVolume / BoxVolume; + EjectaMetalDensity *= BubbleVolume / BoxVolume; + EjectaThermalEnergy *= BubbleVolume / BoxVolume; + } #endif -// if (cstar->level > level) { -// printf("Reducing ejecta density and energy by 10%% on " -// "level %"ISYM" to avoid crashing.\n", level); -// EjectaDensity *= 0.1; -// EjectaMetalDensity *= 0.1; -// EjectaThermalEnergy *= 0.1; -// } - - // Correct for smaller enrichment radius - EjectaMetalDensity *= pow(MetalRadius, -3.0); - PrimordialDensity = EjectaDensity - EjectaMetalDensity; - MetalRadius2 = radius * radius * MetalRadius * MetalRadius; - outerRadius2 = 1.2 * 1.2 * radius * radius; - - /* Remove mass from the star that will now be added to grids. + // if (cstar->level > level) { + // printf("Reducing ejecta density and energy by 10%% on " + // "level %"ISYM" to avoid crashing.\n", level); + // EjectaDensity *= 0.1; + // EjectaMetalDensity *= 0.1; + // EjectaThermalEnergy *= 0.1; + // } +/* + + In principle, the feedback metal and mass density are depending on + a sphere with radius = radius. Since the grid is NOT spherical, + we need to find the actual volume that will be deposited into, and + rescale the densities to fill that volume with the correct mass. + */ + //1) First loop to calculate number of cells that will be deposited into + outerRadius2 = radius * radius; + int NumAffectedCells = 0; + for (k = 0; k < GridDimension[2]; k++) + { + + delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; + sz = sign(delz); + delz = fabs(delz); + delz = min(delz, DomainWidth[2] - delz); + + for (j = 0; j < GridDimension[1]; j++) + { + + dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; + sy = sign(dely); + dely = fabs(dely); + dely = min(dely, DomainWidth[1] - dely); + + index = (k * GridDimension[1] + j) * GridDimension[0]; + for (i = 0; i < GridDimension[0]; i++, index++) + { + + delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; + sx = sign(delx); + delx = fabs(delx); + delx = min(delx, DomainWidth[0] - delx); + + radius2 = delx * delx + dely * dely + delz * delz; + if (radius2 <= outerRadius2) + { + + NumAffectedCells++; + } + } + } + } + //2) rescale EjectaMetalDensity and EjectaDensity + FLOAT V_new = NumAffectedCells*pow(CellWidth[0][0],3); + FLOAT V_old = BubbleVolume; + float MassUnits = DensityUnits*pow(LengthUnits, 3); // needs factor dx^3 to get to physical mass + // if (debug) + fprintf(stdout, "Prescaled EjectaDensity=%f EjectaMetalDensity=%f\n", EjectaDensity, EjectaMetalDensity); + bool rescale = V_new > V_old; + // EjectaMetalDensity = (rescale)?(EjectaMetalDensity * pow(V_old/V_new,3)): (EjectaMetalDensity); + // EjectaDensity = (rescale)?(EjectaDensity * pow(V_old/V_new,3)):(EjectaDensity); + if (rescale){ + fprintf(stdout, "Scaling P3 Feedback: N_aff=%"ISYM" V_new=%"GSYM" V_old=%"GSYM"\n", NumAffectedCells,V_new*pow(LengthUnits,3), + 4.0/3.0*pi*pow(radius,3)*pow(LengthUnits,3)); + fprintf(stdout, "New EjectaMetalDensity = %"GSYM"\n", EjectaMetalDensity); + fprintf(stdout, "New EjectaDensity = %"GSYM"\n",EjectaDensity); + fprintf(stdout, "Mass to deposit = %f\n", EjectaDensity*V_new*MassUnits/SolarMass); + fprintf(stdout, "Metal to deposit = %f\n", EjectaMetalDensity*V_new*MassUnits/SolarMass); + } + //3) Continue on and profit with mass conserving feedback! + + // Correct for smaller enrichment radius + EjectaMetalDensity *= pow(MetalRadius, -3.0); + PrimordialDensity = EjectaDensity - EjectaMetalDensity; + MetalRadius2 = radius * radius * MetalRadius * MetalRadius; + outerRadius2 = 1.2 * 1.2 * radius * radius; + + + /* Remove mass from the star that will now be added to grids. Also, because EjectaDensity will be added with zero net momentum, increase the particle's velocity accordingly. - Ji-hoon Kim, Sep.2009 */ -// printf("grid::AFS: before: cstar->Mass = %lf\n", cstar->Mass); - if (cstar->FeedbackFlag != SUPERNOVA) { - float old_mass = (float)(cstar->Mass); - cstar->Mass -= EjectaDensity * DensityUnits * BubbleVolume * pow(LengthUnits,3.0) / SolarMass; - float frac = old_mass / cstar->Mass; - cstar->vel[0] *= frac; - cstar->vel[1] *= frac; - cstar->vel[2] *= frac; - } // ENDIF !Supernova - - maxGE = MAX_TEMPERATURE / (TemperatureUnits * (Gamma-1.0) * 0.6); - - for (k = 0; k < GridDimension[2]; k++) { - - delz = CellLeftEdge[2][k] + 0.5*CellWidth[2][k] - cstar->pos[2]; - sz = sign(delz); - delz = fabs(delz); - delz = min(delz, DomainWidth[2]-delz); - - for (j = 0; j < GridDimension[1]; j++) { - - dely = CellLeftEdge[1][j] + 0.5*CellWidth[1][j] - cstar->pos[1]; - sy = sign(dely); - dely = fabs(dely); - dely = min(dely, DomainWidth[1]-dely); - - index = (k*GridDimension[1] + j)*GridDimension[0]; - for (i = 0; i < GridDimension[0]; i++, index++) { - - delx = CellLeftEdge[0][i] + 0.5*CellWidth[0][i] - cstar->pos[0]; - sx = sign(delx); - delx = fabs(delx); - delx = min(delx, DomainWidth[0]-delx); - - radius2 = delx*delx + dely*dely + delz*delz; - if (radius2 <= outerRadius2) { - - r1 = sqrt(radius2) / radius; - norm = 0.98; - ramp = norm*(0.5 - 0.5 * tanh(10.0*(r1-1.0))); -// ramp = min(max(1.0 - (r1 - 0.8)/0.4, 0.01), 1.0); - - /* 1/1.2^3 factor to dilute the density since we're - depositing a uniform ejecta in a sphere of 1.2*radius - without a ramp. The ramp is only applied to the - energy*density factor. */ - factor = 0.578704; - - OldDensity = BaryonField[DensNum][index]; - BaryonField[DensNum][index] += factor*EjectaDensity; - - /* Add total energies of spheres together, then divide by + // printf("grid::AFS: before: cstar->Mass = %lf\n", cstar->Mass); + float depositedMass = 0.0; + float depositedMetal= 0.0; + float depositedEnergy = 0.0; + FLOAT depositedVolume = 0.0; + if (cstar->FeedbackFlag != SUPERNOVA) + { + float old_mass = (float)(cstar->Mass); + cstar->Mass -= EjectaDensity * DensityUnits * BubbleVolume * pow(LengthUnits, 3.0) / SolarMass; + float frac = old_mass / cstar->Mass; + cstar->vel[0] *= frac; + cstar->vel[1] *= frac; + cstar->vel[2] *= frac; + } // ENDIF !Supernova + + maxGE = MAX_TEMPERATURE / (TemperatureUnits * (Gamma - 1.0) * 0.6); + + for (k = 0; k < GridDimension[2]; k++) + { + + delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; + sz = sign(delz); + delz = fabs(delz); + delz = min(delz, DomainWidth[2] - delz); + + for (j = 0; j < GridDimension[1]; j++) + { + + dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; + sy = sign(dely); + dely = fabs(dely); + dely = min(dely, DomainWidth[1] - dely); + + index = (k * GridDimension[1] + j) * GridDimension[0]; + for (i = 0; i < GridDimension[0]; i++, index++) + { + + delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; + sx = sign(delx); + delx = fabs(delx); + delx = min(delx, DomainWidth[0] - delx); + + radius2 = delx * delx + dely * dely + delz * delz; + if (radius2 <= outerRadius2) + { + depositedVolume += CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + r1 = sqrt(radius2) / radius; + norm = 0.98; + ramp = norm * (0.5 - 0.5 * tanh(10.0 * (r1 - 1.0))); + // ramp = min(max(1.0 - (r1 - 0.8)/0.4, 0.01), 1.0); + + /* 1/1.2^3 factor to dilute the density since we're + depositing a uniform ejecta in a sphere of 1.2*radius + without a ramp. The ramp is only applied to the + energy*density factor. + */ + factor = 0.578704; + + OldDensity = BaryonField[DensNum][index]; + BaryonField[DensNum][index] += factor * EjectaDensity; + depositedMass += factor*EjectaDensity*pow(CellWidth[0][0], 3); + + /* Add total energies of spheres together, then divide by density to get specific energy */ - if (GENum >= 0 && DualEnergyFormalism) { - - newGE = (OldDensity * BaryonField[GENum][index] + - ramp * factor * EjectaDensity * EjectaThermalEnergy) / - BaryonField[DensNum][index]; - newGE = min(newGE, maxGE); - BaryonField[GENum][index] = newGE; - BaryonField[TENum][index] = newGE; - - for (dim = 0; dim < GridRank; dim++) - BaryonField[TENum][index] += - 0.5 * BaryonField[Vel1Num+dim][index] * - BaryonField[Vel1Num+dim][index]; - - } else { - - newGE = (OldDensity * BaryonField[TENum][index] + - ramp * factor * EjectaDensity * EjectaThermalEnergy) / - BaryonField[DensNum][index]; - - newGE = min(newGE, maxGE); - BaryonField[TENum][index] = newGE; - - } //end if(GENum >= 0 && DualEnergyFormalism) - - /* Update species and colour fields */ - - if (MetallicityField == TRUE && radius2 <= MetalRadius2) - delta_fz = EjectaMetalDensity / OldDensity; - else - delta_fz = 0.0; - increase = BaryonField[DensNum][index] / OldDensity - delta_fz; - - if (MultiSpecies) { - BaryonField[DeNum][index] *= increase; - BaryonField[HINum][index] *= increase; - BaryonField[HIINum][index] *= increase; - BaryonField[HeINum][index] *= increase; - BaryonField[HeIINum][index] *= increase; - BaryonField[HeIIINum][index] *= increase; - } - if (MultiSpecies > 1) { - BaryonField[HMNum][index] *= increase; - BaryonField[H2INum][index] *= increase; - BaryonField[H2IINum][index] *= increase; - } - if (MultiSpecies > 2) { - BaryonField[DINum][index] *= increase; - BaryonField[DIINum][index] *= increase; - BaryonField[HDINum][index] *= increase; - } - - if (MetallicityField == TRUE) - BaryonField[MetalNum][index] += EjectaMetalDensity; - - CellsModified++; - - } // END if inside radius - } // END i-direction - } // END j-direction - } // END k-direction - - } // END Supernova - - /*********************************************************************** + if (GENum >= 0 && DualEnergyFormalism) + { + + newGE = (OldDensity * BaryonField[GENum][index] + + ramp * factor * EjectaDensity * EjectaThermalEnergy) / + BaryonField[DensNum][index]; + depositedEnergy += ramp * factor * EjectaDensity * EjectaThermalEnergy; + newGE = min(newGE, maxGE); + BaryonField[GENum][index] = newGE; + BaryonField[TENum][index] = newGE; + + for (dim = 0; dim < GridRank; dim++) + BaryonField[TENum][index] += + 0.5 * BaryonField[Vel1Num + dim][index] * + BaryonField[Vel1Num + dim][index]; + } + else + { + + newGE = (OldDensity * BaryonField[TENum][index] + + ramp * factor * EjectaDensity * EjectaThermalEnergy) / + BaryonField[DensNum][index]; + + newGE = min(newGE, maxGE); + BaryonField[TENum][index] = newGE; + + } //end if(GENum >= 0 && DualEnergyFormalism) + + /* Update species and colour fields */ + + if (MetallicityField == TRUE && radius2 <= MetalRadius2) + delta_fz = EjectaMetalDensity / OldDensity; + else + delta_fz = 0.0; + increase = BaryonField[DensNum][index] / OldDensity - delta_fz; + + if (MultiSpecies) + { + BaryonField[DeNum][index] *= increase; + BaryonField[HINum][index] *= increase; + BaryonField[HIINum][index] *= increase; + BaryonField[HeINum][index] *= increase; + BaryonField[HeIINum][index] *= increase; + BaryonField[HeIIINum][index] *= increase; + } + if (MultiSpecies > 1) + { + BaryonField[HMNum][index] *= increase; + BaryonField[H2INum][index] *= increase; + BaryonField[H2IINum][index] *= increase; + } + if (MultiSpecies > 2) + { + BaryonField[DINum][index] *= increase; + BaryonField[DIINum][index] *= increase; + BaryonField[HDINum][index] *= increase; + } + + if (MetallicityField == TRUE) + BaryonField[MetalNum][index] += factor*EjectaMetalDensity; + depositedMetal += factor*EjectaMetalDensity*pow(CellWidth[0][0], 3); + + CellsModified++; + + } // END if inside radius + } // END i-direction + } // END j-direction + } // END k-direction + // if (debug){ + fprintf(stdout, "[ %d ]Coupling feedback on level %d for star assigned to level %d\n", cstar->ReturnGridID(), level, cstar->ReturnLevel()); + fprintf(stdout, "Deposited Vol = %e\n", depositedVolume*pow(LengthUnits,3)); + fprintf(stdout, "Deposited Vol/Vold = %f\n", depositedVolume/V_old); + fprintf(stdout, "Deposited Vol/Vnew = %f\n", depositedVolume/V_new); + fprintf(stdout, "Deposited mass = %f\n", depositedMass*MassUnits/SolarMass); + fprintf(stdout, "Mass Error = %f\n", 1.0-depositedMass/(EjectaDensity*V_new)); + fprintf(stdout, "Deposited metal = %f\n", depositedMetal*MassUnits/SolarMass); + fprintf(stdout, "Metal Error = %f\n", 1.0-depositedMetal/(EjectaMetalDensity*V_new)); + fprintf(stdout, "Energy Deposit = %"GSYM"\n", depositedEnergy*MassUnits*pow(CellWidth[0][0], 3)/TimeUnits/TimeUnits); + // } + + } // END Supernova + + /*********************************************************************** MBH_THERMAL ************************************************************************/ - // Similar to Supernova, but here we assume the followings: - // EjectaDensity = 0.0 - // EjectaMetalDensity = 0.0 - // The unit of EjectaThermalEnergy = ergs/cm^3, not ergs/g + // Similar to Supernova, but here we assume the followings: + // EjectaDensity = 0.0 + // EjectaMetalDensity = 0.0 + // The unit of EjectaThermalEnergy = ergs/cm^3, not ergs/g - if (cstar->FeedbackFlag == MBH_THERMAL) { + if (cstar->FeedbackFlag == MBH_THERMAL) + { - maxGE = MAX_TEMPERATURE / (TemperatureUnits * (Gamma-1.0) * 0.6); + maxGE = MAX_TEMPERATURE / (TemperatureUnits * (Gamma - 1.0) * 0.6); - for (k = 0; k < GridDimension[2]; k++) { + for (k = 0; k < GridDimension[2]; k++) + { - delz = CellLeftEdge[2][k] + 0.5*CellWidth[2][k] - cstar->pos[2]; - sz = sign(delz); - delz = fabs(delz); - delz = min(delz, DomainWidth[2]-delz); + delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; + sz = sign(delz); + delz = fabs(delz); + delz = min(delz, DomainWidth[2] - delz); - for (j = 0; j < GridDimension[1]; j++) { + for (j = 0; j < GridDimension[1]; j++) + { - dely = CellLeftEdge[1][j] + 0.5*CellWidth[1][j] - cstar->pos[1]; - sy = sign(dely); - dely = fabs(dely); - dely = min(dely, DomainWidth[1]-dely); + dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; + sy = sign(dely); + dely = fabs(dely); + dely = min(dely, DomainWidth[1] - dely); - index = (k*GridDimension[1] + j)*GridDimension[0]; - for (i = 0; i < GridDimension[0]; i++, index++) { + index = (k * GridDimension[1] + j) * GridDimension[0]; + for (i = 0; i < GridDimension[0]; i++, index++) + { - delx = CellLeftEdge[0][i] + 0.5*CellWidth[0][i] - cstar->pos[0]; - sx = sign(delx); - delx = fabs(delx); - delx = min(delx, DomainWidth[0]-delx); + delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; + sx = sign(delx); + delx = fabs(delx); + delx = min(delx, DomainWidth[0] - delx); - radius2 = delx*delx + dely*dely + delz*delz; - if (radius2 <= outerRadius2) { + radius2 = delx * delx + dely * dely + delz * delz; + if (radius2 <= outerRadius2) + { - r1 = sqrt(radius2) / radius; - norm = 0.98; - ramp = norm*(0.5 - 0.5 * tanh(10.0*(r1-1.0))); -// ramp = min(max(1.0 - (r1 - 0.8)/0.4, 0.01), 1.0); + r1 = sqrt(radius2) / radius; + norm = 0.98; + ramp = norm * (0.5 - 0.5 * tanh(10.0 * (r1 - 1.0))); + // ramp = min(max(1.0 - (r1 - 0.8)/0.4, 0.01), 1.0); - /* 1/1.2^3 factor to dilute the density since we're + /* 1/1.2^3 factor to dilute the density since we're depositing a uniform ejecta in a sphere of 1.2*radius without a ramp. The ramp is only applied to the energy*density factor. */ - factor = 0.578704; + factor = 0.578704; - OldDensity = BaryonField[DensNum][index]; - BaryonField[DensNum][index] += factor*EjectaDensity; + OldDensity = BaryonField[DensNum][index]; + BaryonField[DensNum][index] += factor * EjectaDensity; - /* Get specific energy */ + /* Get specific energy */ - if (GENum >= 0 && DualEnergyFormalism) { + if (GENum >= 0 && DualEnergyFormalism) + { - /* When injected energy is uniform throughout the volume; + /* When injected energy is uniform throughout the volume; EjectaThermalEnergy in ergs/cm3 */ - newGE = (OldDensity * BaryonField[GENum][index] + - ramp * factor * EjectaThermalEnergy) / - BaryonField[DensNum][index]; + newGE = (OldDensity * BaryonField[GENum][index] + + ramp * factor * EjectaThermalEnergy) / + BaryonField[DensNum][index]; #ifdef USE_ONE_OVER_RSQUARED - /* When injected energy is proportional to 1/R^2; + /* When injected energy is proportional to 1/R^2; EjectaThermalEnergy in ergs/cm3/(1/cm^2) */ - newGE = (OldDensity * BaryonField[GENum][index] + - ramp * factor * EjectaThermalEnergy * - min(1.0/radius2, 1.0/(4.0*CellWidth[0][0]*CellWidth[0][0]))) / - BaryonField[DensNum][index]; + newGE = (OldDensity * BaryonField[GENum][index] + + ramp * factor * EjectaThermalEnergy * + min(1.0 / radius2, 1.0 / (4.0 * CellWidth[0][0] * CellWidth[0][0]))) / + BaryonField[DensNum][index]; #endif #ifdef CONSTANT_SPECIFIC - /* When injected energy is proportional to the cell mass; + /* When injected energy is proportional to the cell mass; EjectaThermalEnergy in ergs/g = cm2/s2 */ - newGE = (BaryonField[GENum][index] + EjectaThermalEnergy) * - OldDensity / BaryonField[DensNum][index]; + newGE = (BaryonField[GENum][index] + EjectaThermalEnergy) * + OldDensity / BaryonField[DensNum][index]; #endif - newGE = min(newGE, maxGE); + newGE = min(newGE, maxGE); - BaryonField[GENum][index] = newGE; - BaryonField[TENum][index] = newGE; + BaryonField[GENum][index] = newGE; + BaryonField[TENum][index] = newGE; - for (dim = 0; dim < GridRank; dim++) - BaryonField[TENum][index] += - 0.5 * BaryonField[Vel1Num+dim][index] * - BaryonField[Vel1Num+dim][index]; + for (dim = 0; dim < GridRank; dim++) + BaryonField[TENum][index] += + 0.5 * BaryonField[Vel1Num + dim][index] * + BaryonField[Vel1Num + dim][index]; + } + else + { - } else { - - newGE = (OldDensity * BaryonField[TENum][index] + - ramp * factor * EjectaThermalEnergy) / - BaryonField[DensNum][index]; + newGE = (OldDensity * BaryonField[TENum][index] + + ramp * factor * EjectaThermalEnergy) / + BaryonField[DensNum][index]; #ifdef USE_ONE_OVER_RSQUARED - newGE = (OldDensity * BaryonField[TENum][index] + - ramp * factor * EjectaThermalEnergy * - min(1.0/radius2, 1.0/(4.0*CellWidth[0][0]*CellWidth[0][0]))) / - BaryonField[DensNum][index]; + newGE = (OldDensity * BaryonField[TENum][index] + + ramp * factor * EjectaThermalEnergy * + min(1.0 / radius2, 1.0 / (4.0 * CellWidth[0][0] * CellWidth[0][0]))) / + BaryonField[DensNum][index]; #endif - + #ifdef CONSTANT_SPECIFIC - newGE = (BaryonField[TENum][index] + EjectaThermalEnergy) * - OldDensity / BaryonField[DensNum][index]; + newGE = (BaryonField[TENum][index] + EjectaThermalEnergy) * + OldDensity / BaryonField[DensNum][index]; #endif -// printf("grid::AddFS: rho= %"GSYM"->%"GSYM", TE= %"GSYM"->%"GSYM", drho= %"GSYM", dE= %"GSYM"\n", -// OldDensity, BaryonField[DensNum][index], -// BaryonField[TENum][index], newGE, EjectaDensity, EjectaThermalEnergy * 1/radius2); - - newGE = min(newGE, maxGE); - BaryonField[TENum][index] = newGE; - - } //end if(GENum >= 0 && DualEnergyFormalism) - - /* Update species and colour fields */ - - if (MetallicityField == TRUE && radius2 <= MetalRadius2) - delta_fz = EjectaMetalDensity / OldDensity; - else - delta_fz = 0.0; - increase = BaryonField[DensNum][index] / OldDensity - delta_fz; - - if (MultiSpecies) { - BaryonField[DeNum][index] *= increase; - BaryonField[HINum][index] *= increase; - BaryonField[HIINum][index] *= increase; - BaryonField[HeINum][index] *= increase; - BaryonField[HeIINum][index] *= increase; - BaryonField[HeIIINum][index] *= increase; - } - if (MultiSpecies > 1) { - BaryonField[HMNum][index] *= increase; - BaryonField[H2INum][index] *= increase; - BaryonField[H2IINum][index] *= increase; - } - if (MultiSpecies > 2) { - BaryonField[DINum][index] *= increase; - BaryonField[DIINum][index] *= increase; - BaryonField[HDINum][index] *= increase; - } - - if (MetallicityField == TRUE) - BaryonField[MetalNum][index] += EjectaMetalDensity; - - /* MBHColour injected */ - if (MBHColourNum > 0) - BaryonField[MBHColourNum][index] += factor*EjectaDensity; - - CellsModified++; - - } // END if inside radius - } // END i-direction - } // END j-direction - } // END k-direction - - } // END MBH_THERMAL - - /*********************************************************************** + // printf("grid::AddFS: rho= %"GSYM"->%"GSYM", TE= %"GSYM"->%"GSYM", drho= %"GSYM", dE= %"GSYM"\n", + // OldDensity, BaryonField[DensNum][index], + // BaryonField[TENum][index], newGE, EjectaDensity, EjectaThermalEnergy * 1/radius2); + + newGE = min(newGE, maxGE); + BaryonField[TENum][index] = newGE; + + } //end if(GENum >= 0 && DualEnergyFormalism) + + /* Update species and colour fields */ + + if (MetallicityField == TRUE && radius2 <= MetalRadius2) + delta_fz = EjectaMetalDensity / OldDensity; + else + delta_fz = 0.0; + increase = BaryonField[DensNum][index] / OldDensity - delta_fz; + + if (MultiSpecies) + { + BaryonField[DeNum][index] *= increase; + BaryonField[HINum][index] *= increase; + BaryonField[HIINum][index] *= increase; + BaryonField[HeINum][index] *= increase; + BaryonField[HeIINum][index] *= increase; + BaryonField[HeIIINum][index] *= increase; + } + if (MultiSpecies > 1) + { + BaryonField[HMNum][index] *= increase; + BaryonField[H2INum][index] *= increase; + BaryonField[H2IINum][index] *= increase; + } + if (MultiSpecies > 2) + { + BaryonField[DINum][index] *= increase; + BaryonField[DIINum][index] *= increase; + BaryonField[HDINum][index] *= increase; + } + + if (MetallicityField == TRUE) + BaryonField[MetalNum][index] += EjectaMetalDensity; + + /* MBHColour injected */ + if (MBHColourNum > 0) + BaryonField[MBHColourNum][index] += factor * EjectaDensity; + + CellsModified++; + + } // END if inside radius + } // END i-direction + } // END j-direction + } // END k-direction + + } // END MBH_THERMAL + + /*********************************************************************** MBH_JETS ************************************************************************/ - // Inject bipolar jets along the direction of the angular momentum - // vector L of the MBH particle (angular momentum accreted thus far) - // or along the z-axis - Ji-hoon Kim, Nov.2009 + // Inject bipolar jets along the direction of the angular momentum + // vector L of the MBH particle (angular momentum accreted thus far) + // or along the z-axis - Ji-hoon Kim, Nov.2009 #define MAX_SUPERCELL_NUMBER 1000 - int SUPERCELL = 2; //2 for supercell of 5 cells wide = 5^3 - int ind_cell_inside[MAX_SUPERCELL_NUMBER], ind_cell_edge[MAX_SUPERCELL_NUMBER]; - float nx_cell_edge[MAX_SUPERCELL_NUMBER], ny_cell_edge[MAX_SUPERCELL_NUMBER], - nz_cell_edge[MAX_SUPERCELL_NUMBER]; - int n_cell_inside = 0, n_cell_edge = 0, ibuff = NumberOfGhostZones; - int ii, jj, kk, r_s, ic, sign; - float m_cell_inside = 0.0, metal_cell_inside = 0.0, colour_cell_inside = 0.0, - metallicity_inside = 0.0, colour_inside = 0.0, rho_inside, rho_metal_inside, rho_colour_inside; - float m_cell_edge = 0.0, metal_cell_edge = 0.0, colour_cell_edge = 0.0, - metallicity_edge = 0.0, colour_edge = 0.0, rho_jet, rho_metal_jet, rho_colour_jet; - float L_x, L_y, L_z, L_s, nx_L = 0.0, ny_L = 0.0, nz_L = 0.0, costheta = cos(pi/3.9); - float EjectaMass, EjectaMetalMass, MBHJetsVelocity; - - if (cstar->FeedbackFlag == MBH_JETS) { - - /* Calculate star indicies */ - - float CellWidthTemp = float(CellWidth[0][0]); - i = (int)((cstar->pos[0] - CellLeftEdge[0][0]) / CellWidthTemp); - j = (int)((cstar->pos[1] - CellLeftEdge[1][0]) / CellWidthTemp); - k = (int)((cstar->pos[2] - CellLeftEdge[2][0]) / CellWidthTemp); - - /* Note that we need to inject feedback only for the finest grid the MBH belongs to */ - - if (i < ibuff || i > GridDimension[0]-ibuff-1 || - j < ibuff || j > GridDimension[1]-ibuff-1 || - k < ibuff || k > GridDimension[2]-ibuff-1 || - cstar->ReturnCurrentGrid() == NULL || - cstar->level > level) { -// fprintf(stdout, "grid::AddFS: MBH_JETS - MBH doesn't belong to this grid.\n"); - return SUCCESS; - } - - /* Calculate mass that has accumulated thus far; since EjectaDensity is calculated + int SUPERCELL = 2; //2 for supercell of 5 cells wide = 5^3 + int ind_cell_inside[MAX_SUPERCELL_NUMBER], ind_cell_edge[MAX_SUPERCELL_NUMBER]; + float nx_cell_edge[MAX_SUPERCELL_NUMBER], ny_cell_edge[MAX_SUPERCELL_NUMBER], + nz_cell_edge[MAX_SUPERCELL_NUMBER]; + int n_cell_inside = 0, n_cell_edge = 0, ibuff = NumberOfGhostZones; + int ii, jj, kk, r_s, ic, sign; + float m_cell_inside = 0.0, metal_cell_inside = 0.0, colour_cell_inside = 0.0, + metallicity_inside = 0.0, colour_inside = 0.0, rho_inside, rho_metal_inside, rho_colour_inside; + float m_cell_edge = 0.0, metal_cell_edge = 0.0, colour_cell_edge = 0.0, + metallicity_edge = 0.0, colour_edge = 0.0, rho_jet, rho_metal_jet, rho_colour_jet; + float L_x, L_y, L_z, L_s, nx_L = 0.0, ny_L = 0.0, nz_L = 0.0, costheta = cos(pi / 3.9); + float EjectaMass, EjectaMetalMass, MBHJetsVelocity; + + if (cstar->FeedbackFlag == MBH_JETS) + { + + /* Calculate star indicies */ + + float CellWidthTemp = float(CellWidth[0][0]); + i = (int)((cstar->pos[0] - CellLeftEdge[0][0]) / CellWidthTemp); + j = (int)((cstar->pos[1] - CellLeftEdge[1][0]) / CellWidthTemp); + k = (int)((cstar->pos[2] - CellLeftEdge[2][0]) / CellWidthTemp); + + /* Note that we need to inject feedback only for the finest grid the MBH belongs to */ + + if (i < ibuff || i > GridDimension[0] - ibuff - 1 || + j < ibuff || j > GridDimension[1] - ibuff - 1 || + k < ibuff || k > GridDimension[2] - ibuff - 1 || + cstar->ReturnCurrentGrid() == NULL || + cstar->level > level) + { + // fprintf(stdout, "grid::AddFS: MBH_JETS - MBH doesn't belong to this grid.\n"); + return SUCCESS; + } + + /* Calculate mass that has accumulated thus far; since EjectaDensity is calculated for isotropic MBH_THERMAL, we use it only to compute EjectaMass, not apply it directly. */ - cstar->NotEjectedMass += EjectaDensity * DensityUnits * BubbleVolume * pow(LengthUnits,3.0) / SolarMass; - -// fprintf(stdout, "d1, d2, d3, i, j, k = %d %d %d / %d %d %d\n", -// GridDimension[0], GridDimension[1], GridDimension[2], i,j,k); - - /* If NotEjectedMass is still smaller than the threshold, return */ - - if (cstar->NotEjectedMass <= MBHFeedbackJetsThresholdMass) { - fprintf(stdout, "grid::AddFS: MBH_JETS - accumulated mass (%g Ms) not passed threshold.\n", - cstar->NotEjectedMass); - return SUCCESS; - } - - /* If the current grid cannot contain the whole supercell, return */ - - if (i < ibuff+SUPERCELL || i > GridDimension[0]-ibuff-SUPERCELL-1 || - j < ibuff+SUPERCELL || j > GridDimension[1]-ibuff-SUPERCELL-1 || - k < ibuff+SUPERCELL || k > GridDimension[2]-ibuff-SUPERCELL-1) { - fprintf(stdout, "grid::AddFS: MBH_JETS - supercell not contained; accumulated mass (%g Ms).\n", - cstar->NotEjectedMass); - - // if the supercell issue hasn't allowed the jet injection for too long, - // issue an warning signal and output the current hierarchy at CheckForOutput - if (cstar->NotEjectedMass > 2.0 * MBHFeedbackJetsThresholdMass) { - fprintf(stdout, "grid::AddFS: MBH_JETS - jets haven't been ejected for too long!\n"); - OutputWhenJetsHaveNotEjected = TRUE; - } - - // otherwise, just proceed and do it later - return SUCCESS; - } - - /* Find ejecta mass */ - - EjectaMass = cstar->NotEjectedMass * SolarMass / DensityUnits / pow(LengthUnits,3.0); - EjectaMetalMass = EjectaMass * MBHFeedbackMetalYield; - OutputWhenJetsHaveNotEjected = FALSE; - - /* Find the directional vector n_L of angular momentum accreted thus far */ - - L_x = cstar->accreted_angmom[0]; - L_y = cstar->accreted_angmom[1]; - L_z = cstar->accreted_angmom[2]; - L_s = sqrt(pow(L_x,2) + pow(L_y,2) + pow(L_z,2)); - nx_L = L_x/L_s; //normalized directional vector - ny_L = L_y/L_s; - nz_L = L_z/L_s; - - // if MBHFeedback = 3, direct the jets always along the z-axis - if (MBHFeedback == 3) { - nx_L = 0.0; - ny_L = 0.0; - nz_L = 1.0; - } - - // if MBHFeedback = 4 or 5, provide the jet direction with a random noise - if (MBHFeedback == 4 || MBHFeedback == 5) { - - float theta, phi, MaximumNoiseAngle; - if (MBHFeedback == 4) MaximumNoiseAngle = 10.0; - if (MBHFeedback == 5) MaximumNoiseAngle = 90.0; //launching in random direction - - //find angles in spherical coordinate; n_L's are already normalized - theta = atan(ny_L/nx_L); - phi = acos(nz_L); - printf("before: n_L = (%g, %g, %g) with theta,phi = (%g, %g)\n", nx_L, ny_L, nz_L, theta, phi); - - //add random noise to theta and phi - srand(time(NULL)); - theta += MaximumNoiseAngle * pi / 180.0 * ((2.0*(float)rand()/((float)(RAND_MAX)+(float)(1))) - 1.0); - phi += MaximumNoiseAngle * pi / 180.0 * ((2.0*(float)rand()/((float)(RAND_MAX)+(float)(1))) - 1.0); - - //get back to Cartesian coordinate; some tricks needed to preserve the signs of nx_L and ny_L - nx_L = sign(nx_L) * fabs(cos(theta))*sin(phi); - ny_L = sign(ny_L) * fabs(sin(theta))*sin(phi); - nz_L = cos(phi); - printf("after : n_L = (%g, %g, %g) with theta,phi = (%g, %g) and random angle example = %g deg\n", - nx_L, ny_L, nz_L, theta, phi, - MaximumNoiseAngle * ((2.0*(float)rand()/((float)(RAND_MAX)+(float)(1))) - 1.0)); - } - - /* Loop over the supercell around the MBH particle (5 * 5 * 5 = 125 cells, + cstar->NotEjectedMass += EjectaDensity * DensityUnits * BubbleVolume * pow(LengthUnits, 3.0) / SolarMass; + + // fprintf(stdout, "d1, d2, d3, i, j, k = %d %d %d / %d %d %d\n", + // GridDimension[0], GridDimension[1], GridDimension[2], i,j,k); + + /* If NotEjectedMass is still smaller than the threshold, return */ + + if (cstar->NotEjectedMass <= MBHFeedbackJetsThresholdMass) + { + fprintf(stdout, "grid::AddFS: MBH_JETS - accumulated mass (%g Ms) not passed threshold.\n", + cstar->NotEjectedMass); + return SUCCESS; + } + + /* If the current grid cannot contain the whole supercell, return */ + + if (i < ibuff + SUPERCELL || i > GridDimension[0] - ibuff - SUPERCELL - 1 || + j < ibuff + SUPERCELL || j > GridDimension[1] - ibuff - SUPERCELL - 1 || + k < ibuff + SUPERCELL || k > GridDimension[2] - ibuff - SUPERCELL - 1) + { + fprintf(stdout, "grid::AddFS: MBH_JETS - supercell not contained; accumulated mass (%g Ms).\n", + cstar->NotEjectedMass); + + // if the supercell issue hasn't allowed the jet injection for too long, + // issue an warning signal and output the current hierarchy at CheckForOutput + if (cstar->NotEjectedMass > 2.0 * MBHFeedbackJetsThresholdMass) + { + fprintf(stdout, "grid::AddFS: MBH_JETS - jets haven't been ejected for too long!\n"); + OutputWhenJetsHaveNotEjected = TRUE; + } + + // otherwise, just proceed and do it later + return SUCCESS; + } + + /* Find ejecta mass */ + + EjectaMass = cstar->NotEjectedMass * SolarMass / DensityUnits / pow(LengthUnits, 3.0); + EjectaMetalMass = EjectaMass * MBHFeedbackMetalYield; + OutputWhenJetsHaveNotEjected = FALSE; + + /* Find the directional vector n_L of angular momentum accreted thus far */ + + L_x = cstar->accreted_angmom[0]; + L_y = cstar->accreted_angmom[1]; + L_z = cstar->accreted_angmom[2]; + L_s = sqrt(pow(L_x, 2) + pow(L_y, 2) + pow(L_z, 2)); + nx_L = L_x / L_s; //normalized directional vector + ny_L = L_y / L_s; + nz_L = L_z / L_s; + + // if MBHFeedback = 3, direct the jets always along the z-axis + if (MBHFeedback == 3) + { + nx_L = 0.0; + ny_L = 0.0; + nz_L = 1.0; + } + + // if MBHFeedback = 4 or 5, provide the jet direction with a random noise + if (MBHFeedback == 4 || MBHFeedback == 5) + { + + float theta, phi, MaximumNoiseAngle; + if (MBHFeedback == 4) + MaximumNoiseAngle = 10.0; + if (MBHFeedback == 5) + MaximumNoiseAngle = 90.0; //launching in random direction + + //find angles in spherical coordinate; n_L's are already normalized + theta = atan(ny_L / nx_L); + phi = acos(nz_L); + printf("before: n_L = (%g, %g, %g) with theta,phi = (%g, %g)\n", nx_L, ny_L, nz_L, theta, phi); + + //add random noise to theta and phi + srand(time(NULL)); + theta += MaximumNoiseAngle * pi / 180.0 * ((2.0 * (float)rand() / ((float)(RAND_MAX) + (float)(1))) - 1.0); + phi += MaximumNoiseAngle * pi / 180.0 * ((2.0 * (float)rand() / ((float)(RAND_MAX) + (float)(1))) - 1.0); + + //get back to Cartesian coordinate; some tricks needed to preserve the signs of nx_L and ny_L + nx_L = sign(nx_L) * fabs(cos(theta)) * sin(phi); + ny_L = sign(ny_L) * fabs(sin(theta)) * sin(phi); + nz_L = cos(phi); + printf("after : n_L = (%g, %g, %g) with theta,phi = (%g, %g) and random angle example = %g deg\n", + nx_L, ny_L, nz_L, theta, phi, + MaximumNoiseAngle * ((2.0 * (float)rand() / ((float)(RAND_MAX) + (float)(1))) - 1.0)); + } + + /* Loop over the supercell around the MBH particle (5 * 5 * 5 = 125 cells, but only the edges), and record the cells eligible for jet injection */ - for (kk = -SUPERCELL; kk <= SUPERCELL; kk++) { - for (jj = -SUPERCELL; jj <= SUPERCELL; jj++) { - for (ii = -SUPERCELL; ii <= SUPERCELL; ii++) { - - if (ABS(ii) != SUPERCELL && ABS(jj) != SUPERCELL && ABS(kk) != SUPERCELL) { //if not on edges - - ind_cell_inside[n_cell_inside] = i+ii+(j+jj+(k+kk)*GridDimension[1])*GridDimension[0]; - m_cell_inside += BaryonField[DensNum][ind_cell_inside[n_cell_inside]] * - pow(CellWidth[0][0], 3); - if (MetallicityField == TRUE) - metal_cell_inside += BaryonField[MetalNum][ind_cell_inside[n_cell_inside]] * - pow(CellWidth[0][0], 3); - if (MBHColourNum > 0) - colour_cell_inside += BaryonField[MBHColourNum][ind_cell_inside[n_cell_inside]] * - pow(CellWidth[0][0], 3); - n_cell_inside++; - - } else { //if on edges - - r_s = sqrt(pow(ii,2) + pow(jj,2) + pow(kk,2)); - - if (fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s) > costheta) { - - ind_cell_edge[n_cell_edge] = i+ii+(j+jj+(k+kk)*GridDimension[1])*GridDimension[0]; - nx_cell_edge[n_cell_edge] = ii / r_s; //directional vector - ny_cell_edge[n_cell_edge] = jj / r_s; - nz_cell_edge[n_cell_edge] = kk / r_s; - m_cell_edge += BaryonField[DensNum][ind_cell_edge[n_cell_edge]] * - pow(CellWidth[0][0], 3); - if (MetallicityField == TRUE) - metal_cell_edge += BaryonField[MetalNum][ind_cell_edge[n_cell_edge]] * - pow(CellWidth[0][0], 3); - if (MBHColourNum > 0) - colour_cell_edge += BaryonField[MBHColourNum][ind_cell_edge[n_cell_edge]] * - pow(CellWidth[0][0], 3); - n_cell_edge++; - } - - } - - } // END ii-direction - } // END jj-direction - } // END kk-direction - -// printf("EjectaM in SolarMass = %g, EjectaM = %g, EjectaMetalM = %g, m_cell_edge = %g, n_cell_edge = %d\n", -// cstar->NotEjectedMass, EjectaMass, EjectaMetalMass, m_cell_edge, n_cell_edge); - - /* Calculate the jet density */ - - rho_jet = (m_cell_edge + EjectaMass) / - (n_cell_edge * pow(CellWidth[0][0], 3)); - - if (MetallicityField == TRUE) { - rho_metal_jet = (metal_cell_edge + EjectaMetalMass) / - (n_cell_edge * pow(CellWidth[0][0], 3)); - metallicity_edge = rho_metal_jet / rho_jet; - } else - metallicity_edge = 0.0; - - if (MBHColourNum > 0) { - rho_colour_jet = (colour_cell_edge + EjectaMass) / - (n_cell_edge * pow(CellWidth[0][0], 3)); - colour_edge = rho_colour_jet / rho_jet; - } else - colour_edge = 0.0; - -// printf("rho_jet_prev = %g\n", m_cell_edge / (n_cell_edge * pow(CellWidth[0][0], 3))); -// printf("rho_jet =%g, rho_metal_jet = %g, rho_colour_jet = %g, metallicity_edge = %g\n", -// rho_jet, rho_metal_jet, rho_colour_jet, metallicity_edge); - - /* Calculate MBHJetsVelocity using energy conservation below: + for (kk = -SUPERCELL; kk <= SUPERCELL; kk++) + { + for (jj = -SUPERCELL; jj <= SUPERCELL; jj++) + { + for (ii = -SUPERCELL; ii <= SUPERCELL; ii++) + { + + if (ABS(ii) != SUPERCELL && ABS(jj) != SUPERCELL && ABS(kk) != SUPERCELL) + { //if not on edges + + ind_cell_inside[n_cell_inside] = i + ii + (j + jj + (k + kk) * GridDimension[1]) * GridDimension[0]; + m_cell_inside += BaryonField[DensNum][ind_cell_inside[n_cell_inside]] * + pow(CellWidth[0][0], 3); + if (MetallicityField == TRUE) + metal_cell_inside += BaryonField[MetalNum][ind_cell_inside[n_cell_inside]] * + pow(CellWidth[0][0], 3); + if (MBHColourNum > 0) + colour_cell_inside += BaryonField[MBHColourNum][ind_cell_inside[n_cell_inside]] * + pow(CellWidth[0][0], 3); + n_cell_inside++; + } + else + { //if on edges + + r_s = sqrt(pow(ii, 2) + pow(jj, 2) + pow(kk, 2)); + + if (fabs((ii * nx_L + jj * ny_L + kk * nz_L) / r_s) > costheta) + { + + ind_cell_edge[n_cell_edge] = i + ii + (j + jj + (k + kk) * GridDimension[1]) * GridDimension[0]; + nx_cell_edge[n_cell_edge] = ii / r_s; //directional vector + ny_cell_edge[n_cell_edge] = jj / r_s; + nz_cell_edge[n_cell_edge] = kk / r_s; + m_cell_edge += BaryonField[DensNum][ind_cell_edge[n_cell_edge]] * + pow(CellWidth[0][0], 3); + if (MetallicityField == TRUE) + metal_cell_edge += BaryonField[MetalNum][ind_cell_edge[n_cell_edge]] * + pow(CellWidth[0][0], 3); + if (MBHColourNum > 0) + colour_cell_edge += BaryonField[MBHColourNum][ind_cell_edge[n_cell_edge]] * + pow(CellWidth[0][0], 3); + n_cell_edge++; + } + } + + } // END ii-direction + } // END jj-direction + } // END kk-direction + + // printf("EjectaM in SolarMass = %g, EjectaM = %g, EjectaMetalM = %g, m_cell_edge = %g, n_cell_edge = %d\n", + // cstar->NotEjectedMass, EjectaMass, EjectaMetalMass, m_cell_edge, n_cell_edge); + + /* Calculate the jet density */ + + rho_jet = (m_cell_edge + EjectaMass) / + (n_cell_edge * pow(CellWidth[0][0], 3)); + + if (MetallicityField == TRUE) + { + rho_metal_jet = (metal_cell_edge + EjectaMetalMass) / + (n_cell_edge * pow(CellWidth[0][0], 3)); + metallicity_edge = rho_metal_jet / rho_jet; + } + else + metallicity_edge = 0.0; + + if (MBHColourNum > 0) + { + rho_colour_jet = (colour_cell_edge + EjectaMass) / + (n_cell_edge * pow(CellWidth[0][0], 3)); + colour_edge = rho_colour_jet / rho_jet; + } + else + colour_edge = 0.0; + + // printf("rho_jet_prev = %g\n", m_cell_edge / (n_cell_edge * pow(CellWidth[0][0], 3))); + // printf("rho_jet =%g, rho_metal_jet = %g, rho_colour_jet = %g, metallicity_edge = %g\n", + // rho_jet, rho_metal_jet, rho_colour_jet, metallicity_edge); + + /* Calculate MBHJetsVelocity using energy conservation below: MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency * Mdot * c^2 = 0.5 * MBHFeedbackMassEjectionFraction * Mdot * (MBHJetsVelocity)^2 @@ -653,343 +779,365 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU Note that EjectaThermalEnergy is never used; MBHFeedbackEnergyCoupling should now be calculated considering gravitational redshift (Kim et al. 2010) */ - MBHJetsVelocity = clight * sqrt( 2 * MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency - / MBHFeedbackMassEjectionFraction ) / VelocityUnits; + MBHJetsVelocity = clight * sqrt(2 * MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency / MBHFeedbackMassEjectionFraction) / VelocityUnits; - if (MBHJetsVelocity * VelocityUnits > 0.99*clight) { - ENZO_VFAIL("grid::AddFS: MBHJetsVelocity is ultra-relativistic! (%g/ %g/ %g/ %g c)\n", - MBHFeedbackEnergyCoupling, MBHFeedbackRadiativeEfficiency, - MBHFeedbackMassEjectionFraction, MBHJetsVelocity * VelocityUnits / clight); - } + if (MBHJetsVelocity * VelocityUnits > 0.99 * clight) + { + ENZO_VFAIL("grid::AddFS: MBHJetsVelocity is ultra-relativistic! (%g/ %g/ %g/ %g c)\n", + MBHFeedbackEnergyCoupling, MBHFeedbackRadiativeEfficiency, + MBHFeedbackMassEjectionFraction, MBHJetsVelocity * VelocityUnits / clight); + } - /* Finally, add the jet feedback at the edges (outer part of the supercell) */ + /* Finally, add the jet feedback at the edges (outer part of the supercell) */ - for (ic = 0; ic < n_cell_edge; ic++) { + for (ic = 0; ic < n_cell_edge; ic++) + { - index = ind_cell_edge[ic]; + index = ind_cell_edge[ic]; - /* Update velocities and TE; note that we now have kinetic (jet) energy added, so + /* Update velocities and TE; note that we now have kinetic (jet) energy added, so for DualEnergyFormalism = 0 you don't have to update any energy field */ - sign = sign(nx_cell_edge[ic]*nx_L + ny_cell_edge[ic]*ny_L + nz_cell_edge[ic]*nz_L); + sign = sign(nx_cell_edge[ic] * nx_L + ny_cell_edge[ic] * ny_L + nz_cell_edge[ic] * nz_L); - if (GENum >= 0 && DualEnergyFormalism) - for (dim = 0; dim < GridRank; dim++) - BaryonField[TENum][index] -= - 0.5 * BaryonField[Vel1Num+dim][index] * - BaryonField[Vel1Num+dim][index]; + if (GENum >= 0 && DualEnergyFormalism) + for (dim = 0; dim < GridRank; dim++) + BaryonField[TENum][index] -= + 0.5 * BaryonField[Vel1Num + dim][index] * + BaryonField[Vel1Num + dim][index]; - /* Calculate grid velocity: the actual veloctiy injected in supercell edges. + /* Calculate grid velocity: the actual veloctiy injected in supercell edges. This is different from MBHJetsVelocity because it is the mass-weighted average - between MBHJetsVelocity and the original veloctiy in grid */ - - BaryonField[Vel1Num][index] = (BaryonField[DensNum][index] * BaryonField[Vel1Num][index] + - EjectaMass / (n_cell_edge*pow(CellWidth[0][0], 3)) * - sign * nx_L * MBHJetsVelocity) / - (BaryonField[DensNum][index] + - EjectaMass / (n_cell_edge*pow(CellWidth[0][0], 3))); - BaryonField[Vel2Num][index] = (BaryonField[DensNum][index] * BaryonField[Vel2Num][index] + - EjectaMass / (n_cell_edge*pow(CellWidth[0][0], 3)) * - sign * ny_L * MBHJetsVelocity) / - (BaryonField[DensNum][index] + - EjectaMass / (n_cell_edge*pow(CellWidth[0][0], 3))); - BaryonField[Vel3Num][index] = (BaryonField[DensNum][index] * BaryonField[Vel3Num][index] + - EjectaMass / (n_cell_edge*pow(CellWidth[0][0], 3)) * - sign * nz_L * MBHJetsVelocity) / - (BaryonField[DensNum][index] + - EjectaMass / (n_cell_edge*pow(CellWidth[0][0], 3))); - - if (GENum >= 0 && DualEnergyFormalism) - for (dim = 0; dim < GridRank; dim++) - BaryonField[TENum][index] += - 0.5 * BaryonField[Vel1Num+dim][index] * - BaryonField[Vel1Num+dim][index]; - - /* Update density, species and colour fields */ - - OldDensity = BaryonField[DensNum][index]; - BaryonField[DensNum][index] = rho_jet; - increase = rho_jet / OldDensity; -// printf("grid::AFS: increase = %lf\n", increase); - - if (MultiSpecies) { - BaryonField[DeNum][index] *= increase; - BaryonField[HINum][index] *= increase; - BaryonField[HIINum][index] *= increase; - BaryonField[HeINum][index] *= increase; - BaryonField[HeIINum][index] *= increase; - BaryonField[HeIIINum][index] *= increase; - } - if (MultiSpecies > 1) { - BaryonField[HMNum][index] *= increase; - BaryonField[H2INum][index] *= increase; - BaryonField[H2IINum][index] *= increase; - } - if (MultiSpecies > 2) { - BaryonField[DINum][index] *= increase; - BaryonField[DIINum][index] *= increase; - BaryonField[HIINum][index] *= increase; - BaryonField[HDINum][index] *= increase; - } - - if (MetallicityField == TRUE) - BaryonField[MetalNum][index] = rho_metal_jet; - - if (MBHColourNum > 0) - BaryonField[MBHColourNum][index] = rho_colour_jet; - - CellsModified++; - - } // END ic in n_cell_edge - - /* Remove ejected mass from star; now that we injected the NotEjectedMass, set it to zero */ - - double old_mass = cstar->Mass; - float old_vel1 = cstar->vel[1]; - cstar->Mass -= cstar->NotEjectedMass; - cstar->NotEjectedMass = 0.0; - - cstar->vel[0] *= old_mass / cstar->Mass; - cstar->vel[1] *= old_mass / cstar->Mass; - cstar->vel[2] *= old_mass / cstar->Mass; -// fprintf(stdout, "grid::AFS: Mass = %lf -> %lf, vel[1] = %f -> %f\n", -// old_mass, cstar->Mass, old_vel1, cstar->vel[1]); - - fprintf(stdout, "grid::AddFS: jets injected (EjectaM = %g Ms, JetsVelocity = %g, grid v = %g, rho_jet = %g) along n_L = (%g, %g, %g)\n", - EjectaMass * DensityUnits * pow(LengthUnits,3.0) / SolarMass, - MBHJetsVelocity, BaryonField[Vel3Num][n_cell_edge-1], rho_jet, nx_L, ny_L, nz_L); - - } // END MBH_JETS - - /*********************************************************************** + between MBHJetsVelocity and the original veloctiy in grid */ + + BaryonField[Vel1Num][index] = (BaryonField[DensNum][index] * BaryonField[Vel1Num][index] + + EjectaMass / (n_cell_edge * pow(CellWidth[0][0], 3)) * + sign * nx_L * MBHJetsVelocity) / + (BaryonField[DensNum][index] + + EjectaMass / (n_cell_edge * pow(CellWidth[0][0], 3))); + BaryonField[Vel2Num][index] = (BaryonField[DensNum][index] * BaryonField[Vel2Num][index] + + EjectaMass / (n_cell_edge * pow(CellWidth[0][0], 3)) * + sign * ny_L * MBHJetsVelocity) / + (BaryonField[DensNum][index] + + EjectaMass / (n_cell_edge * pow(CellWidth[0][0], 3))); + BaryonField[Vel3Num][index] = (BaryonField[DensNum][index] * BaryonField[Vel3Num][index] + + EjectaMass / (n_cell_edge * pow(CellWidth[0][0], 3)) * + sign * nz_L * MBHJetsVelocity) / + (BaryonField[DensNum][index] + + EjectaMass / (n_cell_edge * pow(CellWidth[0][0], 3))); + + if (GENum >= 0 && DualEnergyFormalism) + for (dim = 0; dim < GridRank; dim++) + BaryonField[TENum][index] += + 0.5 * BaryonField[Vel1Num + dim][index] * + BaryonField[Vel1Num + dim][index]; + + /* Update density, species and colour fields */ + + OldDensity = BaryonField[DensNum][index]; + BaryonField[DensNum][index] = rho_jet; + increase = rho_jet / OldDensity; + // printf("grid::AFS: increase = %lf\n", increase); + + if (MultiSpecies) + { + BaryonField[DeNum][index] *= increase; + BaryonField[HINum][index] *= increase; + BaryonField[HIINum][index] *= increase; + BaryonField[HeINum][index] *= increase; + BaryonField[HeIINum][index] *= increase; + BaryonField[HeIIINum][index] *= increase; + } + if (MultiSpecies > 1) + { + BaryonField[HMNum][index] *= increase; + BaryonField[H2INum][index] *= increase; + BaryonField[H2IINum][index] *= increase; + } + if (MultiSpecies > 2) + { + BaryonField[DINum][index] *= increase; + BaryonField[DIINum][index] *= increase; + BaryonField[HIINum][index] *= increase; + BaryonField[HDINum][index] *= increase; + } + + if (MetallicityField == TRUE) + BaryonField[MetalNum][index] = rho_metal_jet; + + if (MBHColourNum > 0) + BaryonField[MBHColourNum][index] = rho_colour_jet; + + CellsModified++; + + } // END ic in n_cell_edge + + /* Remove ejected mass from star; now that we injected the NotEjectedMass, set it to zero */ + + double old_mass = cstar->Mass; + float old_vel1 = cstar->vel[1]; + cstar->Mass -= cstar->NotEjectedMass; + cstar->NotEjectedMass = 0.0; + + cstar->vel[0] *= old_mass / cstar->Mass; + cstar->vel[1] *= old_mass / cstar->Mass; + cstar->vel[2] *= old_mass / cstar->Mass; + // fprintf(stdout, "grid::AFS: Mass = %lf -> %lf, vel[1] = %f -> %f\n", + // old_mass, cstar->Mass, old_vel1, cstar->vel[1]); + + fprintf(stdout, "grid::AddFS: jets injected (EjectaM = %g Ms, JetsVelocity = %g, grid v = %g, rho_jet = %g) along n_L = (%g, %g, %g)\n", + EjectaMass * DensityUnits * pow(LengthUnits, 3.0) / SolarMass, + MBHJetsVelocity, BaryonField[Vel3Num][n_cell_edge - 1], rho_jet, nx_L, ny_L, nz_L); + + } // END MBH_JETS + + /*********************************************************************** STROEMGREN SPHERE FROM A POP III STAR (WHALEN ET AL. 2004) ************************************************************************/ - if (cstar->FeedbackFlag == STROEMGREN) { - - maxVelocity = 1e5*WhalenMaxVelocity / VelocityUnits; - coef = maxVelocity / ( 0.8*0.8 + 2*0.8 ); - index = 0; - - for (k = 0; k < GridDimension[2]; k++) { - - delz = CellLeftEdge[2][k] + 0.5*CellWidth[2][k] - cstar->pos[2]; - sz = sign(delz); - delz = fabs(delz); - delz = min(delz, DomainWidth[2]-delz); - - for (j = 0; j < GridDimension[1]; j++) { - - dely = CellLeftEdge[1][j] + 0.5*CellWidth[1][j] - cstar->pos[1]; - sy = sign(dely); - dely = fabs(dely); - dely = min(dely, DomainWidth[1]-dely); - - for (i = 0; i < GridDimension[0]; i++, index++) { - - delx = CellLeftEdge[0][i] + 0.5*CellWidth[0][i] - cstar->pos[0]; - sx = sign(delx); - delx = fabs(delx); - delx = min(delx, DomainWidth[0]-delx); - - radius2 = delx*delx + dely*dely + delz*delz; - if (radius2 <= 1.2*1.2*radius*radius) { - - float r1 = sqrt(radius2) / radius; - float ramp = min(max(1.0 - (r1 - 0.8)/0.4, 0.01), 1.0); - - BaryonField[DensNum][index] = EjectaDensity * ramp; - - // Estimate of velocity profile - speed = coef * (r1*r1 + 2*r1) * ramp; - Radius = sqrt(radius2); - - if (Radius > TOLERANCE) { - BaryonField[Vel1Num][index] = sx*speed*delx/Radius + cstar->vel[0]; - BaryonField[Vel2Num][index] = sy*speed*dely/Radius + cstar->vel[1]; - BaryonField[Vel3Num][index] = sz*speed*delz/Radius + cstar->vel[2]; - } else { - BaryonField[Vel1Num][index] = cstar->vel[0]; - BaryonField[Vel2Num][index] = cstar->vel[1]; - BaryonField[Vel3Num][index] = cstar->vel[2]; - } - - BaryonField[TENum][index] = EjectaThermalEnergy*ramp; - if (GENum >= 0 && DualEnergyFormalism) - BaryonField[GENum][index] = EjectaThermalEnergy*ramp; - - if (HydroMethod != Zeus_Hydro) - for (dim = 0; dim < GridRank; dim++) - BaryonField[TENum][index] += - 0.5 * BaryonField[Vel1Num+dim][index] * - BaryonField[Vel1Num+dim][index]; - - CellsModified++; - - } // END if inside radius - - } // END i-direction - } // END j-direction - } // END k-direction - } // END Pop III sphere - - /*********************************************************************** + if (cstar->FeedbackFlag == STROEMGREN) + { + + maxVelocity = 1e5 * WhalenMaxVelocity / VelocityUnits; + coef = maxVelocity / (0.8 * 0.8 + 2 * 0.8); + index = 0; + + for (k = 0; k < GridDimension[2]; k++) + { + + delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; + sz = sign(delz); + delz = fabs(delz); + delz = min(delz, DomainWidth[2] - delz); + + for (j = 0; j < GridDimension[1]; j++) + { + + dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; + sy = sign(dely); + dely = fabs(dely); + dely = min(dely, DomainWidth[1] - dely); + + for (i = 0; i < GridDimension[0]; i++, index++) + { + + delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; + sx = sign(delx); + delx = fabs(delx); + delx = min(delx, DomainWidth[0] - delx); + + radius2 = delx * delx + dely * dely + delz * delz; + if (radius2 <= 1.2 * 1.2 * radius * radius) + { + + float r1 = sqrt(radius2) / radius; + float ramp = min(max(1.0 - (r1 - 0.8) / 0.4, 0.01), 1.0); + + BaryonField[DensNum][index] = EjectaDensity * ramp; + + // Estimate of velocity profile + speed = coef * (r1 * r1 + 2 * r1) * ramp; + Radius = sqrt(radius2); + + if (Radius > TOLERANCE) + { + BaryonField[Vel1Num][index] = sx * speed * delx / Radius + cstar->vel[0]; + BaryonField[Vel2Num][index] = sy * speed * dely / Radius + cstar->vel[1]; + BaryonField[Vel3Num][index] = sz * speed * delz / Radius + cstar->vel[2]; + } + else + { + BaryonField[Vel1Num][index] = cstar->vel[0]; + BaryonField[Vel2Num][index] = cstar->vel[1]; + BaryonField[Vel3Num][index] = cstar->vel[2]; + } + + BaryonField[TENum][index] = EjectaThermalEnergy * ramp; + if (GENum >= 0 && DualEnergyFormalism) + BaryonField[GENum][index] = EjectaThermalEnergy * ramp; + + if (HydroMethod != Zeus_Hydro) + for (dim = 0; dim < GridRank; dim++) + BaryonField[TENum][index] += + 0.5 * BaryonField[Vel1Num + dim][index] * + BaryonField[Vel1Num + dim][index]; + + CellsModified++; + + } // END if inside radius + + } // END i-direction + } // END j-direction + } // END k-direction + } // END Pop III sphere + + /*********************************************************************** BARYON REMOVAL AFTER ACCRETION OR STAR PARTICLE CREATION -- Enforce a minimum temperature for cold gas accretion -- ************************************************************************/ - float MinimumTemperature = 1e4, AdditionalEnergy, GasEnergy; - ionizedFraction = 0.999; // Assume an initial HII region + float MinimumTemperature = 1e4, AdditionalEnergy, GasEnergy; + ionizedFraction = 0.999; // Assume an initial HII region - if (cstar->FeedbackFlag == FORMATION) { + if (cstar->FeedbackFlag == FORMATION) + { - index = 0; - //if (cstar->type == PopII) - //MinimumTemperature = (MultiSpecies > 1) ? 1e3 : 1e4; + index = 0; + //if (cstar->type == PopII) + //MinimumTemperature = (MultiSpecies > 1) ? 1e3 : 1e4; - /* For the initial Stroemgren sphere, pre-calculate the numerator + /* For the initial Stroemgren sphere, pre-calculate the numerator of the photo-ionization and photo-heating terms and also absorb the unit conversions and (1/4pi) into the cross-section. */ - float kph, kheat; - sigma_HI *= (double) TimeUnits / ((double)LengthUnits * (double)LengthUnits) - / (4.0 * pi); - kph = (float) (Q_HI * sigma_HI); - kheat = kph * deltaE; - - /* Get photo-ionization fields */ - - int kphHINum, kphHeINum, kphHeIINum, kdissH2INum, kphHMNum, kdissH2IINum; - int gammaNum; - IdentifyRadiativeTransferFields(kphHINum, gammaNum, kphHeINum, kphHeIINum, - kdissH2INum, kphHMNum, kdissH2IINum); - - for (k = 0; k < GridDimension[2]; k++) { - - delz = CellLeftEdge[2][k] + 0.5*CellWidth[2][k] - cstar->pos[2]; - sz = sign(delz); - delz = fabs(delz); - delz = min(delz, DomainWidth[2]-delz); - - for (j = 0; j < GridDimension[1]; j++) { - - dely = CellLeftEdge[1][j] + 0.5*CellWidth[1][j] - cstar->pos[1]; - sy = sign(dely); - dely = fabs(dely); - dely = min(dely, DomainWidth[1]-dely); - - for (i = 0; i < GridDimension[0]; i++, index++) { - - delx = CellLeftEdge[0][i] + 0.5*CellWidth[0][i] - cstar->pos[0]; - sx = sign(delx); - delx = fabs(delx); - delx = min(delx, DomainWidth[0]-delx); - - radius2 = delx*delx + dely*dely + delz*delz; - if (radius2 <= radius*radius) { - - radius2 = max(radius2, 0.0625*CellWidth[0][i]*CellWidth[0][i]); // (0.25*dx)^2 - - if (MetallicityField == TRUE) - metallicity = BaryonField[MetalNum][index] / BaryonField[DensNum][index]; - else - metallicity = 0; - - fhz = fh * (1-metallicity); - fhez = (1-fh) * (1-metallicity); - - BaryonField[DensNum][index] = EjectaDensity; - - if (MultiSpecies) { - BaryonField[DeNum][index] = BaryonField[DensNum][index] * ionizedFraction; - BaryonField[HINum][index] = BaryonField[DensNum][index] * (1-ionizedFraction) * fhz; - BaryonField[HIINum][index] = BaryonField[DensNum][index] * ionizedFraction * fhz; - BaryonField[HeINum][index] = BaryonField[DensNum][index] * (1-ionizedFraction) * fhez; - BaryonField[HeIINum][index] = BaryonField[DensNum][index] * (ionizedFraction) * fhez; - BaryonField[HeIIINum][index] = 1e-10 * BaryonField[DensNum][index]; - } - if (MultiSpecies > 1) { - BaryonField[HMNum][index] = tiny_number; - BaryonField[H2INum][index] = tiny_number; - BaryonField[H2IINum][index] = tiny_number; - } - if (MultiSpecies > 2) { - BaryonField[DINum][index] = BaryonField[DensNum][index] * fh * - CoolData.DeuteriumToHydrogenRatio * (1-ionizedFraction); - BaryonField[DIINum][index] = BaryonField[DensNum][index] * fh * - CoolData.DeuteriumToHydrogenRatio * ionizedFraction; - BaryonField[HDINum][index] = tiny_number * BaryonField[DensNum][index]; - } - - if (SNColourNum > 0) - BaryonField[SNColourNum][index] *= factor; - if (Metal2Num > 0) - BaryonField[Metal2Num][index] *= factor; - - CellsModified++; - - } // END if inside radius - - } // END i-direction - } // END j-direction - } // END k-direction - } // END star birth - - /*********************************************************************** + float kph, kheat; + sigma_HI *= (double)TimeUnits / ((double)LengthUnits * (double)LengthUnits) / (4.0 * pi); + kph = (float)(Q_HI * sigma_HI); + kheat = kph * deltaE; + + /* Get photo-ionization fields */ + + int kphHINum, kphHeINum, kphHeIINum, kdissH2INum, kphHMNum, kdissH2IINum; + int gammaNum; + IdentifyRadiativeTransferFields(kphHINum, gammaNum, kphHeINum, kphHeIINum, + kdissH2INum, kphHMNum, kdissH2IINum); + + for (k = 0; k < GridDimension[2]; k++) + { + + delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; + sz = sign(delz); + delz = fabs(delz); + delz = min(delz, DomainWidth[2] - delz); + + for (j = 0; j < GridDimension[1]; j++) + { + + dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; + sy = sign(dely); + dely = fabs(dely); + dely = min(dely, DomainWidth[1] - dely); + + for (i = 0; i < GridDimension[0]; i++, index++) + { + + delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; + sx = sign(delx); + delx = fabs(delx); + delx = min(delx, DomainWidth[0] - delx); + + radius2 = delx * delx + dely * dely + delz * delz; + if (radius2 <= radius * radius) + { + + radius2 = max(radius2, 0.0625 * CellWidth[0][i] * CellWidth[0][i]); // (0.25*dx)^2 + + if (MetallicityField == TRUE) + metallicity = BaryonField[MetalNum][index] / BaryonField[DensNum][index]; + else + metallicity = 0; + + fhz = fh * (1 - metallicity); + fhez = (1 - fh) * (1 - metallicity); + + BaryonField[DensNum][index] = EjectaDensity; + + if (MultiSpecies) + { + BaryonField[DeNum][index] = BaryonField[DensNum][index] * ionizedFraction; + BaryonField[HINum][index] = BaryonField[DensNum][index] * (1 - ionizedFraction) * fhz; + BaryonField[HIINum][index] = BaryonField[DensNum][index] * ionizedFraction * fhz; + BaryonField[HeINum][index] = BaryonField[DensNum][index] * (1 - ionizedFraction) * fhez; + BaryonField[HeIINum][index] = BaryonField[DensNum][index] * (ionizedFraction)*fhez; + BaryonField[HeIIINum][index] = 1e-10 * BaryonField[DensNum][index]; + } + if (MultiSpecies > 1) + { + BaryonField[HMNum][index] = tiny_number; + BaryonField[H2INum][index] = tiny_number; + BaryonField[H2IINum][index] = tiny_number; + } + if (MultiSpecies > 2) + { + BaryonField[DINum][index] = BaryonField[DensNum][index] * fh * + CoolData.DeuteriumToHydrogenRatio * (1 - ionizedFraction); + BaryonField[DIINum][index] = BaryonField[DensNum][index] * fh * + CoolData.DeuteriumToHydrogenRatio * ionizedFraction; + BaryonField[HDINum][index] = tiny_number * BaryonField[DensNum][index]; + } + + if (SNColourNum > 0) + BaryonField[SNColourNum][index] *= factor; + if (Metal2Num > 0) + BaryonField[Metal2Num][index] *= factor; + + CellsModified++; + + } // END if inside radius + + } // END i-direction + } // END j-direction + } // END k-direction + } // END star birth + + /*********************************************************************** POPIII - Color field ************************************************************************/ - if (cstar->FeedbackFlag == COLOR_FIELD) { - int CellsModified2 = 0; - - int ColorField = FindField(ForbiddenRefinement, FieldType, NumberOfBaryonFields); - if (ColorField < 0) ENZO_FAIL("Couldn't Find Color Field!"); - index = 0; - - for (k = 0; k < GridDimension[2]; k++) { + if (cstar->FeedbackFlag == COLOR_FIELD) + { + int CellsModified2 = 0; - delz = CellLeftEdge[2][k] + 0.5*CellWidth[2][k] - cstar->pos[2]; - sz = sign(delz); - delz = fabs(delz); - delz = min(delz, DomainWidth[2]-delz); + int ColorField = FindField(ForbiddenRefinement, FieldType, NumberOfBaryonFields); + if (ColorField < 0) + ENZO_FAIL("Couldn't Find Color Field!"); + index = 0; - for (j = 0; j < GridDimension[1]; j++) { + for (k = 0; k < GridDimension[2]; k++) + { - dely = CellLeftEdge[1][j] + 0.5*CellWidth[1][j] - cstar->pos[1]; - sy = sign(dely); - dely = fabs(dely); - dely = min(dely, DomainWidth[1]-dely); + delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; + sz = sign(delz); + delz = fabs(delz); + delz = min(delz, DomainWidth[2] - delz); - for (i = 0; i < GridDimension[0]; i++, index++) { + for (j = 0; j < GridDimension[1]; j++) + { - delx = CellLeftEdge[0][i] + 0.5*CellWidth[0][i] - cstar->pos[0]; - sx = sign(delx); - delx = fabs(delx); - delx = min(delx, DomainWidth[0]-delx); + dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; + sy = sign(dely); + dely = fabs(dely); + dely = min(dely, DomainWidth[1] - dely); - radius2 = delx*delx + dely*dely + delz*delz; - if (radius2 <= radius*radius) { + for (i = 0; i < GridDimension[0]; i++, index++) + { - BaryonField[ColorField][index] = - BaryonField[DensNum][index]; + delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; + sx = sign(delx); + delx = fabs(delx); + delx = min(delx, DomainWidth[0] - delx); - CellsModified++; - CellsModified2++; + radius2 = delx * delx + dely * dely + delz * delz; + if (radius2 <= radius * radius) + { - } // END if inside radius + BaryonField[ColorField][index] = + BaryonField[DensNum][index]; - } // END i-direction - } // END j-direction - } // END k-direction - fprintf(stderr, "CellsModified: %"ISYM"\n", CellsModified2); - } + CellsModified++; + CellsModified2++; - /* Now it's done, unmark. */ + } // END if inside radius - //cstar->FeedbackFlag = NO_FEEDBACK; + } // END i-direction + } // END j-direction + } // END k-direction + fprintf(stderr, "CellsModified: %" ISYM "\n", CellsModified2); + } + /* Now it's done, unmark. */ - return SUCCESS; + //cstar->FeedbackFlag = NO_FEEDBACK; + return SUCCESS; } - diff --git a/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C b/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C new file mode 100644 index 000000000..1c4b49648 --- /dev/null +++ b/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C @@ -0,0 +1,144 @@ +/*********************************************************************** +/ +/ Set flagging field to refine around pop III particles. +/ +/ written by: Azton Wells +/ date: Dec, 2019 +/ modified1: +/ +/ PURPOSE: +/ +************************************************************************/ + +#ifdef USE_MPI +#include "mpi.h" +#endif +#include +#include +#include +#include "ErrorExceptions.h" +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "Hierarchy.h" +#include "TopGridData.h" +#include "LevelHierarchy.h" +#include "CommunicationUtilities.h" +#include "phys_constants.h" +int GetUnits(float *DensityUnits, float *LengthUnits, + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, FLOAT Time); +/* + New refinement criteria will refine the region around Pop III star particles. + This will ensure that their thermal feedback is effective, given that MaximumRefinementLevel is + sufficient + */ + +int grid::FlagCellsToBeRefinedByPopIII(int level) +{ + /* declarations */ + + float LengthUnits, TimeUnits, TemperatureUnits, VelocityUnits, + DensityUnits; + int i, j, k, index, dim, size = 1, NumberOfFlaggedCells = 0; + int Start[MAX_DIMENSION], End[MAX_DIMENSION]; + + FLOAT CellSize, xpos, ypos, zpos; + /* Return if this grid is not on this processor. */ + + if (MyProcessorNumber != ProcessorNumber) + return SUCCESS; + + /* error check */ + if (FlaggingField == NULL) + { + fprintf(stderr, "Flagging Field is undefined.\n"); + return -1; + } + + /* loop over dimensions - I guess this is unnecessary, + but it's handy to have shorter names */ + for (dim = 0; dim < MAX_DIMENSION; dim++) + { + Start[dim] = GridStartIndex[dim]; + End[dim] = GridEndIndex[dim]; + } + + /* compute size */ + for (int dim = 0; dim < GridRank; dim++) + size *= GridDimension[dim]; + GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, Time); + + //If A: no particles or + // B: the resolution is such that its already as refined as PopIIISupernovaMustRefineResolution + int nCellsPerRadius = 1.1*float(PopIIISupernovaRadius)/(CellWidth[0][0]*LengthUnits/pc_cm)+0.5; + if (NumberOfParticles == 0 || 2*nCellsPerRadius > PopIIISupernovaMustRefineResolution || level >= MaximumRefinementLevel){ + for (i = 0; i < size; i++) + { + if (FlaggingField[i] > 0){ + FlaggingField[i] = 1; + NumberOfFlaggedCells += 1; + } + } + return NumberOfFlaggedCells; + } + float PopIIIMustRefineLifetime = 3; //Myr + int istar = 0; + // printf("[%d] Checking particles %d<->%d::%f<->%f\n", level, 2*nCellsPerRadius, + // PopIIISupernovaMustRefineResolution, + // CellWidth[0][0]*LengthUnits/pc_cm, PopIIISupernovaRadius); + int np = 0; + while (istar < NumberOfParticles) + { + if (ParticleAttribute[0][istar] > 0.0 && ParticleType[istar] == 5) // if its a star + { + /* factor = birthtime + lifetime + refineTime */ + float factor = (ParticleAttribute[0][istar] + ParticleAttribute[1][istar]) * TimeUnits + PopIIIMustRefineLifetime * 3.1557e13; + float m = ParticleMass[istar]*(DensityUnits*pow(LengthUnits*CellWidth[0][0], 3))/SolarMass; + if ((((11 < m && m < 40) || (140 < m && m < 260)) || (m < 1e-10)) && (Time * TimeUnits < factor)) + { + // fprintf(stdout, "Flagging cells for particle m=%"FSYM" fact=%"FSYM" Time=%"FSYM"\n", m, factor/3.1557e13, Time*TimeUnits/3.1557e13); + // refine a radius a*Pop3 SN radius + FLOAT radius = 1.1 * PopIIISupernovaRadius * 3.086e18 / LengthUnits; + CellSize = FLOAT(CellWidth[0][0]); + + for (k = Start[2]; k <= End[2]; k++) + for (j = Start[1]; j <= End[1]; j++) + for (i = Start[0]; i <= End[0]; i++) + { + index = i + j * GridDimension[0] + + k * GridDimension[1] * GridDimension[0]; + + xpos = GridLeftEdge[0] + (FLOAT(i - Start[0]) + 0.5) * CellSize; + ypos = GridLeftEdge[1] + (FLOAT(j - Start[1]) + 0.5) * CellSize; + zpos = GridLeftEdge[2] + (FLOAT(k - Start[2]) + 0.5) * CellSize; + float dist = pow(xpos - ParticlePosition[0][istar], 2) + + pow(ypos - ParticlePosition[1][istar], 2) + + pow(zpos - ParticlePosition[2][istar], 2); + if (dist < radius * radius) + { + FlaggingField[index] += 1; + np += 1; + } + } // end loop over cells + } // end if its a star + } // end if refine star + istar++; + } // end for particles + // // sum cells flagged + for (i = 0; i < size; i++) + { + if (FlaggingField[i] > 0){ + FlaggingField[i] = 1; + NumberOfFlaggedCells += 1; + } + } + // fprintf(stdout, "[ %d ] P3 flagged %d cells\n", level, NumberOfFlaggedCells); + + return NumberOfFlaggedCells; +} \ No newline at end of file diff --git a/src/enzo/Grid_SetFlaggingField.C b/src/enzo/Grid_SetFlaggingField.C index 98df34d62..aa82b90f8 100644 --- a/src/enzo/Grid_SetFlaggingField.C +++ b/src/enzo/Grid_SetFlaggingField.C @@ -279,6 +279,15 @@ int grid::SetFlaggingField(int &NumberOfFlaggedCells, int level) } break; + case 20: + // fprintf(stdout, "Calling FlagCellsToBeRefinedByPopIII\n"); + NumberOfFlaggedCells = this->FlagCellsToBeRefinedByPopIII(level); + if (NumberOfFlaggedCells < 0){ + fprintf(stderr, "Error in FlagCellsToBeRefinedByPopIII: NCells < 0.\n"); + return FAIL; + } + // fprintf(stdout, "Called FlagCellsToBeRefinedByPopIII\n"); + break; /* ==== METHOD 100: UNDO REFINEMENT IN SOME REGIONS ==== */ /* Must be done last ... */ diff --git a/src/enzo/Star.h b/src/enzo/Star.h index 6726ef293..7164f07cb 100644 --- a/src/enzo/Star.h +++ b/src/enzo/Star.h @@ -82,6 +82,7 @@ class Star void IncreaseLevel(void) { level++; }; void SetLevel(int i) { level = i; }; void SetGridID(int i) { GridID = i; }; + int ReturnGridID() {return GridID;}; int ReturnFeedbackFlag(void) { return FeedbackFlag; }; grid *ReturnCurrentGrid(void) { return CurrentGrid; }; void AssignCurrentGrid(grid *a) { this->CurrentGrid = a; }; From 62b67f40bf366491252f1c1ae4de576e2a3c7e53 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sun, 8 Dec 2019 08:59:19 -0800 Subject: [PATCH 041/115] added parameter to control how long refinement persists after PopIII death --- src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C | 3 +-- src/enzo/ReadParameterFile.C | 2 ++ src/enzo/SetDefaultGlobalValues.C | 1 + src/enzo/StarParticleData.h | 1 + src/enzo/WriteParameterFile.C | 3 ++- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C b/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C index 1c4b49648..595a8a2b0 100644 --- a/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C +++ b/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C @@ -87,7 +87,6 @@ int grid::FlagCellsToBeRefinedByPopIII(int level) } return NumberOfFlaggedCells; } - float PopIIIMustRefineLifetime = 3; //Myr int istar = 0; // printf("[%d] Checking particles %d<->%d::%f<->%f\n", level, 2*nCellsPerRadius, // PopIIISupernovaMustRefineResolution, @@ -98,7 +97,7 @@ int grid::FlagCellsToBeRefinedByPopIII(int level) if (ParticleAttribute[0][istar] > 0.0 && ParticleType[istar] == 5) // if its a star { /* factor = birthtime + lifetime + refineTime */ - float factor = (ParticleAttribute[0][istar] + ParticleAttribute[1][istar]) * TimeUnits + PopIIIMustRefineLifetime * 3.1557e13; + float factor = (ParticleAttribute[0][istar] + ParticleAttribute[1][istar]) * TimeUnits + PopIIIMustRefineRegionLifetime * 3.1557e13; float m = ParticleMass[istar]*(DensityUnits*pow(LengthUnits*CellWidth[0][0], 3))/SolarMass; if ((((11 < m && m < 40) || (140 < m && m < 260)) || (m < 1e-10)) && (Time * TimeUnits < factor)) { diff --git a/src/enzo/ReadParameterFile.C b/src/enzo/ReadParameterFile.C index c76cbd1c0..12b5b1cd7 100644 --- a/src/enzo/ReadParameterFile.C +++ b/src/enzo/ReadParameterFile.C @@ -1052,6 +1052,8 @@ int ReadParameterFile(FILE *fptr, TopGridData &MetaData, float *Initialdt) &PopIIISupernovaMustRefine); ret += sscanf(line, "PopIIISupernovaMustRefineResolution = %"ISYM, &PopIIISupernovaMustRefineResolution); + ret += sscanf(line, "PopIIIMustRefineRegionLifetime = %"FSYM, + &PopIIIMustRefineRegionLifetime); ret += sscanf(line, "PopIIIHeliumIonization = %"ISYM, &PopIIIHeliumIonization); diff --git a/src/enzo/SetDefaultGlobalValues.C b/src/enzo/SetDefaultGlobalValues.C index b565fae86..095e4ff90 100644 --- a/src/enzo/SetDefaultGlobalValues.C +++ b/src/enzo/SetDefaultGlobalValues.C @@ -746,6 +746,7 @@ int SetDefaultGlobalValues(TopGridData &MetaData) PopIIIUseHypernova = TRUE; // TRUE for HN yields, FALSE for CCSN PopIIISupernovaExplosions = TRUE; // TRUE for supernova energy injection PopIIIOutputOnFeedback = FALSE; // TRUE to output at creation and supernova + PopIIIMustRefineRegionLifetime = 3.0; // if using refinement criteria 20, set time to refine after supernova IMFData = NULL; MBHAccretion = FALSE; // 1: Bondi rate, 2: fix temperature, 3: fix rate, 4: Bondi with v_rel=0, 5: Bondi with v_rel=0 and vorticity diff --git a/src/enzo/StarParticleData.h b/src/enzo/StarParticleData.h index f561d7c1f..14e83653f 100644 --- a/src/enzo/StarParticleData.h +++ b/src/enzo/StarParticleData.h @@ -90,6 +90,7 @@ SPEXTERN float PopIIIColorMass; SPEXTERN int PopIIIUseHypernova; SPEXTERN int PopIIISupernovaExplosions; SPEXTERN int PopIIIOutputOnFeedback; +SPEXTERN int PopIIIMustRefineRegionLifetime; SPEXTERN int StarClusterUseMetalField; SPEXTERN int StarClusterHeliumIonization; diff --git a/src/enzo/WriteParameterFile.C b/src/enzo/WriteParameterFile.C index 76d745fd1..c4cbf4227 100644 --- a/src/enzo/WriteParameterFile.C +++ b/src/enzo/WriteParameterFile.C @@ -1027,7 +1027,8 @@ int WriteParameterFile(FILE *fptr, TopGridData &MetaData, char *name = NULL) PopIIISupernovaMustRefine); fprintf(fptr, "PopIIISupernovaMustRefineResolution = %"ISYM"\n", PopIIISupernovaMustRefineResolution); - + fprintf(fptr, "PopIIIMustRefineRegionLifetime = %"FSYM"\n", + PopIIIMustRefineRegionLifetime); fprintf(fptr, "PopIIIColorDensityThreshold = %"GSYM"\n", PopIIIColorDensityThreshold); fprintf(fptr, "PopIIIColorMass = %"GSYM"\n", From 8dbb3718406950d0a69c7384bee7e4330d84f6b3 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sun, 8 Dec 2019 09:25:02 -0800 Subject: [PATCH 042/115] forgot to add updated make objects --- src/enzo/Make.config.objects | 1 + 1 file changed, 1 insertion(+) diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index 81760ca15..5a9c7bc8e 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -497,6 +497,7 @@ OBJS_CONFIG_LIB = \ Grid_FlagCellsToBeRefinedByShockwaves.o \ Grid_FlagCellsToBeRefinedBySlope.o \ Grid_FlagCellsToBeRefinedBySecondDerivative.o \ + Grid_FlagCellsToBeRefinedByPopIII.o \ Grid_FlagRefinedCells.o \ Grid_FlagGridArray.o \ Grid_FreeExpansionInitializeGrid.o \ From 828eace59d05e12fc670bf74ce03eb5d60ea166f Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 12 Dec 2019 08:31:28 -0800 Subject: [PATCH 043/115] Corrected type of refineregionlifetime parameter --- src/enzo/StarParticleData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enzo/StarParticleData.h b/src/enzo/StarParticleData.h index 14e83653f..86ece66ea 100644 --- a/src/enzo/StarParticleData.h +++ b/src/enzo/StarParticleData.h @@ -90,7 +90,7 @@ SPEXTERN float PopIIIColorMass; SPEXTERN int PopIIIUseHypernova; SPEXTERN int PopIIISupernovaExplosions; SPEXTERN int PopIIIOutputOnFeedback; -SPEXTERN int PopIIIMustRefineRegionLifetime; +SPEXTERN float PopIIIMustRefineRegionLifetime; SPEXTERN int StarClusterUseMetalField; SPEXTERN int StarClusterHeliumIonization; From 41846119e3e5da96911ff5f34dadc7946846d3f6 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 12 Dec 2019 15:40:28 -0800 Subject: [PATCH 044/115] added prints to verify number of particle issuing feedback --- src/enzo/Grid_AddFeedbackSphere.C | 3 +- src/enzo/StarParticleAddFeedback.C | 232 +++++++++++++++-------------- 2 files changed, 119 insertions(+), 116 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 46b3022b3..321877e8c 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -373,7 +373,8 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END j-direction } // END k-direction // if (debug){ - fprintf(stdout, "[ %d ]Coupling feedback on level %d for star assigned to level %d\n", cstar->ReturnGridID(), level, cstar->ReturnLevel()); + fprintf(stdout, "[ %d ]Coupling feedback on level %d for star [%d] assigned to level %d\n", cstar->ReturnGridID(), level, + cstar->ReturnID(), cstar->ReturnLevel()); fprintf(stdout, "Deposited Vol = %e\n", depositedVolume*pow(LengthUnits,3)); fprintf(stdout, "Deposited Vol/Vold = %f\n", depositedVolume/V_old); fprintf(stdout, "Deposited Vol/Vnew = %f\n", depositedVolume/V_new); diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 3cca1655d..7a19d2288 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -39,18 +39,18 @@ #define MAX_TEMPERATURE 1e8 int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, FLOAT Time); -int RecalibrateMBHFeedbackThermalRadius(FLOAT star_pos[], LevelHierarchyEntry *LevelArray[], - int level, float &Radius, - double &EjectaDensity, double &EjectaMetalDensity, - double &EjectaThermalEnergy); + float *TemperatureUnits, float *TimeUnits, + float *VelocityUnits, FLOAT Time); +int RecalibrateMBHFeedbackThermalRadius(FLOAT star_pos[], LevelHierarchyEntry *LevelArray[], + int level, float &Radius, + double &EjectaDensity, double &EjectaMetalDensity, + double &EjectaThermalEnergy); int RemoveParticles(LevelHierarchyEntry *LevelArray[], int level, int ID); FLOAT FindCrossSection(int type, float energy); -int StarParticleAddFeedback(TopGridData *MetaData, - LevelHierarchyEntry *LevelArray[], int level, - Star* &AllStars, bool* &AddedFeedback) +int StarParticleAddFeedback(TopGridData *MetaData, + LevelHierarchyEntry *LevelArray[], int level, + Star *&AllStars, bool *&AddedFeedback) { Star *cstar; @@ -81,14 +81,15 @@ int StarParticleAddFeedback(TopGridData *MetaData, /* Set the units. */ - float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, - VelocityUnits; + float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, + VelocityUnits; GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, Time); + &TimeUnits, &VelocityUnits, Time); count = 0; - for (cstar = AllStars; cstar; cstar = cstar->NextStar, count++) { + for (cstar = AllStars; cstar; cstar = cstar->NextStar, count++) + { AddedFeedback[count] = false; @@ -96,108 +97,108 @@ int StarParticleAddFeedback(TopGridData *MetaData, loss through supernovae. */ if (cstar->ReturnType() == NormalStar && - cstar->ReturnLevel() == level) { + cstar->ReturnLevel() == level) + { MassLoss = cstar->CalculateMassLoss(SNe_dt); cstar->SetAccretionMass(-MassLoss); } if ((cstar->ReturnFeedbackFlag() != MBH_THERMAL) && - (cstar->ReturnFeedbackFlag() != MBH_JETS) && - !cstar->ApplyFeedbackTrue(SNe_dt)) + (cstar->ReturnFeedbackFlag() != MBH_JETS) && + !cstar->ApplyFeedbackTrue(SNe_dt)) continue; dtForThisStar = LevelArray[level]->GridData->ReturnTimeStep(); - + /* Compute some parameters */ - cstar->CalculateFeedbackParameters - (influenceRadius, RootCellWidth, SNe_dt, EjectaDensity, - EjectaThermalEnergy, EjectaMetalDensity, DensityUnits, LengthUnits, - TemperatureUnits, TimeUnits, VelocityUnits, dtForThisStar, - Time, SphereCheck); + cstar->CalculateFeedbackParameters(influenceRadius, RootCellWidth, SNe_dt, EjectaDensity, + EjectaThermalEnergy, EjectaMetalDensity, DensityUnits, LengthUnits, + TemperatureUnits, TimeUnits, VelocityUnits, dtForThisStar, + Time, SphereCheck); - if (SphereCheck) { + if (SphereCheck) + { - /* Recalibrate MBHFeedbackThermalRadius if requested */ + /* Recalibrate MBHFeedbackThermalRadius if requested */ - if (cstar->ReturnFeedbackFlag() == MBH_THERMAL) - RecalibrateMBHFeedbackThermalRadius(cstar->ReturnPosition(), LevelArray, level, influenceRadius, - EjectaDensity, EjectaMetalDensity, EjectaThermalEnergy); + if (cstar->ReturnFeedbackFlag() == MBH_THERMAL) + RecalibrateMBHFeedbackThermalRadius(cstar->ReturnPosition(), LevelArray, level, influenceRadius, + EjectaDensity, EjectaMetalDensity, EjectaThermalEnergy); - /* Determine if a sphere with enough mass (or equivalently radius + /* Determine if a sphere with enough mass (or equivalently radius for SNe) is enclosed within grids on this level */ - LCAPERF_START("star_FindFeedbackSphere"); - cstar->FindFeedbackSphere - (LevelArray, level, influenceRadius, EjectaDensity, EjectaThermalEnergy, - SphereContained, SkipMassRemoval, DensityUnits, LengthUnits, - TemperatureUnits, TimeUnits, VelocityUnits, Time, MarkedSubgrids); - LCAPERF_STOP("star_FindFeedbackSphere"); + LCAPERF_START("star_FindFeedbackSphere"); + cstar->FindFeedbackSphere(LevelArray, level, influenceRadius, EjectaDensity, EjectaThermalEnergy, + SphereContained, SkipMassRemoval, DensityUnits, LengthUnits, + TemperatureUnits, TimeUnits, VelocityUnits, Time, MarkedSubgrids); + LCAPERF_STOP("star_FindFeedbackSphere"); - /* If the particle already had sufficient mass, we still want to + /* If the particle already had sufficient mass, we still want to mark this particle to activate it. */ - if (SkipMassRemoval == TRUE) - AddedFeedback[count] = true; + if (SkipMassRemoval == TRUE) + AddedFeedback[count] = true; - /* If there's no feedback or something weird happens, don't bother. */ + /* If there's no feedback or something weird happens, don't bother. */ - if ( influenceRadius <= tiny_number || - SphereContained == FALSE || - ((cstar->ReturnFeedbackFlag() == MBH_THERMAL || - cstar->ReturnFeedbackFlag() == MBH_JETS) && - (influenceRadius >= RootCellWidth/2 || - EjectaThermalEnergy <= tiny_number)) ) - continue; + if (influenceRadius <= tiny_number || + SphereContained == FALSE || + ((cstar->ReturnFeedbackFlag() == MBH_THERMAL || + cstar->ReturnFeedbackFlag() == MBH_JETS) && + (influenceRadius >= RootCellWidth / 2 || + EjectaThermalEnergy <= tiny_number))) + continue; - /* Determine if a sphere is enclosed within the grids on next level + /* Determine if a sphere is enclosed within the grids on next level If that is the case, we perform AddFeedbackSphere not here, but in the EvolveLevel of the next level. */ - SphereContainedNextLevel = FALSE; - - LCAPERF_START("star_FindFeedbackSphere2"); - if ((cstar->ReturnFeedbackFlag() == MBH_THERMAL || - cstar->ReturnFeedbackFlag() == MBH_JETS || - cstar->ReturnFeedbackFlag() == CONT_SUPERNOVA) && - LevelArray[level+1] != NULL) - cstar->FindFeedbackSphere - (LevelArray, level+1, influenceRadius, EjectaDensity, EjectaThermalEnergy, - SphereContainedNextLevel, dummy, DensityUnits, LengthUnits, - TemperatureUnits, TimeUnits, VelocityUnits, Time, MarkedSubgrids); - LCAPERF_STOP("star_FindFeedbackSphere2"); - -// if (debug) { -// fprintf(stdout, "EjectaDensity=%g, influenceRadius=%g\n", EjectaDensity, influenceRadius); -// fprintf(stdout, "SkipMassRemoval=%d, SphereContained=%d, SphereContainedNextLevel=%d\n", -// SkipMassRemoval, SphereContained, SphereContainedNextLevel); -// } - - /* Quit this routine when + SphereContainedNextLevel = FALSE; + + LCAPERF_START("star_FindFeedbackSphere2"); + if ((cstar->ReturnFeedbackFlag() == MBH_THERMAL || + cstar->ReturnFeedbackFlag() == MBH_JETS || + cstar->ReturnFeedbackFlag() == CONT_SUPERNOVA) && + LevelArray[level + 1] != NULL) + cstar->FindFeedbackSphere(LevelArray, level + 1, influenceRadius, EjectaDensity, EjectaThermalEnergy, + SphereContainedNextLevel, dummy, DensityUnits, LengthUnits, + TemperatureUnits, TimeUnits, VelocityUnits, Time, MarkedSubgrids); + LCAPERF_STOP("star_FindFeedbackSphere2"); + + // if (debug) { + // fprintf(stdout, "EjectaDensity=%g, influenceRadius=%g\n", EjectaDensity, influenceRadius); + // fprintf(stdout, "SkipMassRemoval=%d, SphereContained=%d, SphereContainedNextLevel=%d\n", + // SkipMassRemoval, SphereContained, SphereContainedNextLevel); + // } + + /* Quit this routine when (1) sphere is not contained, or - (2) sphere is contained, but the next level can contain the sphere, too. */ - if ((SphereContained == FALSE) || - (SphereContained == TRUE && SphereContainedNextLevel == TRUE)) - continue; + (2) sphere is contained, but the next level can contain the sphere, too. */ + if ((SphereContained == FALSE) || + (SphereContained == TRUE && SphereContainedNextLevel == TRUE)) + continue; } // ENDIF SphereCheck - else { - + else + { + /* When the sphere is completely confined in a grid, only apply feedback at the level at which the star exists. */ - if (level != cstar->ReturnLevel()) - continue; - + if (level != cstar->ReturnLevel()) + continue; } - + /* Now set cells within the radius to their values after feedback. While walking through the hierarchy, look for particle to change their properties to post-feedback values. */ int CellsModified = 0; - if (SkipMassRemoval == FALSE) { + if (SkipMassRemoval == FALSE) + { /* Determine the H-ionizing photon luminosity to calculate the photo-ionization and heating rate in the initial Stroemgren @@ -207,31 +208,32 @@ int StarParticleAddFeedback(TopGridData *MetaData, double Q[MAX_ENERGY_BINS], Q_HI, sigma; float energies[MAX_ENERGY_BINS], deltaE; #ifdef TRANSFER - if (RadiativeTransfer) { - cstar->ComputePhotonRates(TimeUnits, Time, nbins, energies, Q, dtForThisStar); - sigma = (double) FindCrossSection(0, energies[0]); // HI (cm^2) - Q_HI = Q[0]; - deltaE = energies[0] - 13.6; // eV - } else + if (RadiativeTransfer) + { + cstar->ComputePhotonRates(TimeUnits, Time, nbins, energies, Q, dtForThisStar); + sigma = (double)FindCrossSection(0, energies[0]); // HI (cm^2) + Q_HI = Q[0]; + deltaE = energies[0] - 13.6; // eV + } + else #endif /* TRANSFER */ - { - Q_HI = 0.0; - sigma = 0.0; - deltaE = 0.0; + { + Q_HI = 0.0; + sigma = 0.0; + deltaE = 0.0; } for (l = level; l < MAX_DEPTH_OF_HIERARCHY; l++) - for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - Temp->GridData->AddFeedbackSphere - (cstar, l, influenceRadius, DensityUnits, LengthUnits, - VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, - EjectaMetalDensity, EjectaThermalEnergy, Q_HI, sigma, deltaE, - CellsModified); + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + Temp->GridData->AddFeedbackSphere(cstar, l, influenceRadius, DensityUnits, LengthUnits, + VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, + EjectaMetalDensity, EjectaThermalEnergy, Q_HI, sigma, deltaE, + CellsModified); } // ENDIF -// fprintf(stdout, "StarParticleAddFeedback[%"ISYM"][%"ISYM"]: " -// "Radius = %e pc_cm, changed %"ISYM" cells.\n", -// cstar->ReturnID(), level, influenceRadius*LengthUnits/pc_cm, CellsModified); + // fprintf(stdout, "StarParticleAddFeedback[%"ISYM"][%"ISYM"]: " + // "Radius = %e pc_cm, changed %"ISYM" cells.\n", + // cstar->ReturnID(), level, influenceRadius*LengthUnits/pc_cm, CellsModified); /* Remove mass from the star that is added to grids. Also, because EjectaDensity is added with zero net momentum, increase the particle's velocity accordingly. @@ -257,31 +259,31 @@ int StarParticleAddFeedback(TopGridData *MetaData, #ifdef UNUSED temp_int = CellsModified; MPI_Reduce(&temp_int, &CellsModified, 1, MPI_INT, MPI_SUM, ROOT_PROCESSOR, - MPI_COMM_WORLD); + MPI_COMM_WORLD); - if (debug) { + if (debug) + { if (cstar->ReturnFeedbackFlag() != FORMATION) - fprintf(stdout, "StarParticleAddFeedback[%"ISYM"][%"ISYM"]: " - "Radius = %"GSYM" pc\n", - cstar->ReturnID(), level, influenceRadius*LengthUnits/pc_cm); - if (cstar->ReturnFeedbackFlag() == DEATH || - - cstar->ReturnFeedbackFlag() == CONT_SUPERNOVA || - cstar->ReturnFeedbackFlag() == MBH_THERMAL || - cstar->ReturnFeedbackFlag() == MBH_JETS ) - fprintf(stdout, "StarParticleAddFeedback[%"ISYM"][%"ISYM"]: " - "Energy = %"GSYM" , skip = %"ISYM"\n", - cstar->ReturnID(), level, EjectaThermalEnergy, SkipMassRemoval); - fprintf(stdout, "StarParticleAddFeedback[%"ISYM"][%"ISYM"]: " - "changed %"ISYM" cells. AddedFeedback[%d] = %d\n", - cstar->ReturnID(), level, CellsModified, - count, AddedFeedback[count]); + fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " + "Radius = %" GSYM " pc\n", + cstar->ReturnID(), level, influenceRadius * LengthUnits / pc_cm); + if (cstar->ReturnFeedbackFlag() == DEATH || + + cstar->ReturnFeedbackFlag() == CONT_SUPERNOVA || + cstar->ReturnFeedbackFlag() == MBH_THERMAL || + cstar->ReturnFeedbackFlag() == MBH_JETS) + fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " + "Energy = %" GSYM " , skip = %" ISYM "\n", + cstar->ReturnID(), level, EjectaThermalEnergy, SkipMassRemoval); + fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " + "changed %" ISYM " cells. AddedFeedback[%d] = %d\n", + cstar->ReturnID(), level, CellsModified, + count, AddedFeedback[count]); } #endif - + } // ENDFOR stars LCAPERF_STOP("StarParticleAddFeedback"); return SUCCESS; - } From a616a6cd3e32fdfc9777f769bbd1a5f877824a05 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 12 Dec 2019 21:14:44 -0800 Subject: [PATCH 045/115] debugging--corrected the deposition for really low resolution cases; left in debugging statements for use on frontera --- src/enzo/Grid_AddFeedbackSphere.C | 27 +++++++++++---------- src/enzo/StarParticleAddFeedback.C | 5 +++- src/enzo/Star_CalculateFeedbackParameters.C | 4 ++- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 321877e8c..a70b4afff 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -173,7 +173,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU rescale the densities to fill that volume with the correct mass. */ //1) First loop to calculate number of cells that will be deposited into - outerRadius2 = radius * radius; + outerRadius2 = radius * radius; int NumAffectedCells = 0; for (k = 0; k < GridDimension[2]; k++) { @@ -211,13 +211,14 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } //2) rescale EjectaMetalDensity and EjectaDensity FLOAT V_new = NumAffectedCells*pow(CellWidth[0][0],3); - FLOAT V_old = BubbleVolume; + FLOAT V_old = 4.0*pi/3.0*radius*radius*radius; float MassUnits = DensityUnits*pow(LengthUnits, 3); // needs factor dx^3 to get to physical mass // if (debug) fprintf(stdout, "Prescaled EjectaDensity=%f EjectaMetalDensity=%f\n", EjectaDensity, EjectaMetalDensity); - bool rescale = V_new > V_old; - // EjectaMetalDensity = (rescale)?(EjectaMetalDensity * pow(V_old/V_new,3)): (EjectaMetalDensity); - // EjectaDensity = (rescale)?(EjectaDensity * pow(V_old/V_new,3)):(EjectaDensity); + fprintf(stdout, "Prescaled mass = %f metal = %f\n", EjectaDensity*V_old*MassUnits/SolarMass, EjectaMetalDensity*V_old*MassUnits/SolarMass); + bool rescale = true;// V_new > V_old; + EjectaMetalDensity = (rescale)?(EjectaMetalDensity * V_old/V_new): (EjectaMetalDensity); + EjectaDensity = (rescale)?(EjectaDensity * V_old/V_new):(EjectaDensity); if (rescale){ fprintf(stdout, "Scaling P3 Feedback: N_aff=%"ISYM" V_new=%"GSYM" V_old=%"GSYM"\n", NumAffectedCells,V_new*pow(LengthUnits,3), 4.0/3.0*pi*pow(radius,3)*pow(LengthUnits,3)); @@ -232,7 +233,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU EjectaMetalDensity *= pow(MetalRadius, -3.0); PrimordialDensity = EjectaDensity - EjectaMetalDensity; MetalRadius2 = radius * radius * MetalRadius * MetalRadius; - outerRadius2 = 1.2 * 1.2 * radius * radius; + outerRadius2 = radius * radius*1.2*1.2; /* Remove mass from the star that will now be added to grids. @@ -299,7 +300,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU OldDensity = BaryonField[DensNum][index]; BaryonField[DensNum][index] += factor * EjectaDensity; - depositedMass += factor*EjectaDensity*pow(CellWidth[0][0], 3); + depositedMass += factor*EjectaDensity*pow(CellWidth[0][0],3); /* Add total energies of spheres together, then divide by density to get specific energy */ @@ -362,10 +363,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU BaryonField[HDINum][index] *= increase; } - if (MetallicityField == TRUE) + if (MetallicityField == TRUE){ BaryonField[MetalNum][index] += factor*EjectaMetalDensity; - depositedMetal += factor*EjectaMetalDensity*pow(CellWidth[0][0], 3); - + depositedMetal += factor*EjectaMetalDensity*pow(CellWidth[0][0],3); + } CellsModified++; } // END if inside radius @@ -375,16 +376,16 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU // if (debug){ fprintf(stdout, "[ %d ]Coupling feedback on level %d for star [%d] assigned to level %d\n", cstar->ReturnGridID(), level, cstar->ReturnID(), cstar->ReturnLevel()); - fprintf(stdout, "Deposited Vol = %e\n", depositedVolume*pow(LengthUnits,3)); + fprintf(stdout, "Deposited Vol = %e\n", depositedVolume*pow(LengthUnits,3))*1.2*1.2; fprintf(stdout, "Deposited Vol/Vold = %f\n", depositedVolume/V_old); fprintf(stdout, "Deposited Vol/Vnew = %f\n", depositedVolume/V_new); fprintf(stdout, "Deposited mass = %f\n", depositedMass*MassUnits/SolarMass); fprintf(stdout, "Mass Error = %f\n", 1.0-depositedMass/(EjectaDensity*V_new)); fprintf(stdout, "Deposited metal = %f\n", depositedMetal*MassUnits/SolarMass); fprintf(stdout, "Metal Error = %f\n", 1.0-depositedMetal/(EjectaMetalDensity*V_new)); - fprintf(stdout, "Energy Deposit = %"GSYM"\n", depositedEnergy*MassUnits*pow(CellWidth[0][0], 3)/TimeUnits/TimeUnits); + fprintf(stdout, "Energy Deposit = %"GSYM"\n", depositedEnergy*MassUnits*MassUnits/pow(CellWidth[0][0],3)/TimeUnits/TimeUnits); + //exit(2); // } - } // END Supernova /*********************************************************************** diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 7a19d2288..96322e271 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -222,7 +222,10 @@ int StarParticleAddFeedback(TopGridData *MetaData, sigma = 0.0; deltaE = 0.0; } - + // LevelArray[level]->GridData->AddFeedbackSphere(cstar, level, influenceRadius, DensityUnits, LengthUnits, + // VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, + // EjectaMetalDensity, EjectaThermalEnergy, Q_HI, sigma, deltaE, + // CellsModified); for (l = level; l < MAX_DEPTH_OF_HIERARCHY; l++) for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) Temp->GridData->AddFeedbackSphere(cstar, l, influenceRadius, DensityUnits, LengthUnits, diff --git a/src/enzo/Star_CalculateFeedbackParameters.C b/src/enzo/Star_CalculateFeedbackParameters.C index a7c6f78fc..81e2345bb 100644 --- a/src/enzo/Star_CalculateFeedbackParameters.C +++ b/src/enzo/Star_CalculateFeedbackParameters.C @@ -85,7 +85,6 @@ void Star::CalculateFeedbackParameters(float &Radius, Radius = max(Radius, 3.5*StarLevelCellWidth); EjectaVolume = 4.0/3.0 * pi * pow(Radius*LengthUnits, 3); EjectaDensity = Mass * SolarMass / EjectaVolume / DensityUnits; - // pair-instability SNe if (this->Mass >= PISNLowerMass && this->Mass <= PISNUpperMass) { HeliumCoreMass = (13./24.) * (Mass - 20); @@ -117,6 +116,9 @@ void Star::CalculateFeedbackParameters(float &Radius, // into some of the surrounding parent grids within the next // timestep if we inject the energy into a small radius. Radius *= 1.0; + fprintf(stdout, "CalculateFeedbackParamaters: V = %g :: rho = %f :: rho_z = %f :: mass = %f :: metal :: %f\n", + EjectaVolume, EjectaDensity, EjectaMetalDensity,EjectaVolume*EjectaDensity*DensityUnits/SolarMass, + EjectaMetalDensity*EjectaVolume/SolarMass*DensityUnits); #define DEBUG #ifdef DEBUG From 8b08cf80c702a32566bc0a25f362b26f1390379f Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 12 Dec 2019 21:51:35 -0800 Subject: [PATCH 046/115] more debug-- < 1% error on home PC now -\(oo)/- --- src/enzo/Grid_AddFeedbackSphere.C | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index a70b4afff..97e855c0a 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -173,7 +173,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU rescale the densities to fill that volume with the correct mass. */ //1) First loop to calculate number of cells that will be deposited into - outerRadius2 = radius * radius; + outerRadius2 = 1.2 * 1.2 * radius * radius; int NumAffectedCells = 0; for (k = 0; k < GridDimension[2]; k++) { @@ -216,7 +216,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU // if (debug) fprintf(stdout, "Prescaled EjectaDensity=%f EjectaMetalDensity=%f\n", EjectaDensity, EjectaMetalDensity); fprintf(stdout, "Prescaled mass = %f metal = %f\n", EjectaDensity*V_old*MassUnits/SolarMass, EjectaMetalDensity*V_old*MassUnits/SolarMass); - bool rescale = true;// V_new > V_old; + bool rescale = true;//V_new > V_old; EjectaMetalDensity = (rescale)?(EjectaMetalDensity * V_old/V_new): (EjectaMetalDensity); EjectaDensity = (rescale)?(EjectaDensity * V_old/V_new):(EjectaDensity); if (rescale){ @@ -296,7 +296,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU without a ramp. The ramp is only applied to the energy*density factor. */ - factor = 0.578704; + factor = 1.0;//0.578704; OldDensity = BaryonField[DensNum][index]; BaryonField[DensNum][index] += factor * EjectaDensity; @@ -364,8 +364,8 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } if (MetallicityField == TRUE){ - BaryonField[MetalNum][index] += factor*EjectaMetalDensity; - depositedMetal += factor*EjectaMetalDensity*pow(CellWidth[0][0],3); + BaryonField[MetalNum][index] += EjectaMetalDensity; + depositedMetal += EjectaMetalDensity*pow(CellWidth[0][0],3); } CellsModified++; @@ -376,14 +376,14 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU // if (debug){ fprintf(stdout, "[ %d ]Coupling feedback on level %d for star [%d] assigned to level %d\n", cstar->ReturnGridID(), level, cstar->ReturnID(), cstar->ReturnLevel()); - fprintf(stdout, "Deposited Vol = %e\n", depositedVolume*pow(LengthUnits,3))*1.2*1.2; + fprintf(stdout, "Deposited Vol = %e\n", depositedVolume*pow(LengthUnits,3)); fprintf(stdout, "Deposited Vol/Vold = %f\n", depositedVolume/V_old); fprintf(stdout, "Deposited Vol/Vnew = %f\n", depositedVolume/V_new); fprintf(stdout, "Deposited mass = %f\n", depositedMass*MassUnits/SolarMass); fprintf(stdout, "Mass Error = %f\n", 1.0-depositedMass/(EjectaDensity*V_new)); fprintf(stdout, "Deposited metal = %f\n", depositedMetal*MassUnits/SolarMass); fprintf(stdout, "Metal Error = %f\n", 1.0-depositedMetal/(EjectaMetalDensity*V_new)); - fprintf(stdout, "Energy Deposit = %"GSYM"\n", depositedEnergy*MassUnits*MassUnits/pow(CellWidth[0][0],3)/TimeUnits/TimeUnits); + fprintf(stdout, "Energy Deposit = %"GSYM"\n", depositedEnergy*DensityUnits*pow(CellWidth[0][0]*LengthUnits,3)*pow(LengthUnits,2)/TimeUnits/TimeUnits); //exit(2); // } } // END Supernova From 20ed6f215ba545f35abd783ec2d582c6458cb463 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 13 Dec 2019 08:49:22 -0800 Subject: [PATCH 047/115] Runs wells on home--further testing on frontera --- src/enzo/Grid_AddFeedbackSphere.C | 2 +- src/enzo/Star_CalculateFeedbackParameters.C | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 97e855c0a..0744a372b 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -440,7 +440,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU depositing a uniform ejecta in a sphere of 1.2*radius without a ramp. The ramp is only applied to the energy*density factor. */ - factor = 0.578704; + factor = 1.0;//0.578704; OldDensity = BaryonField[DensNum][index]; BaryonField[DensNum][index] += factor * EjectaDensity; diff --git a/src/enzo/Star_CalculateFeedbackParameters.C b/src/enzo/Star_CalculateFeedbackParameters.C index 81e2345bb..9813243b8 100644 --- a/src/enzo/Star_CalculateFeedbackParameters.C +++ b/src/enzo/Star_CalculateFeedbackParameters.C @@ -116,9 +116,9 @@ void Star::CalculateFeedbackParameters(float &Radius, // into some of the surrounding parent grids within the next // timestep if we inject the energy into a small radius. Radius *= 1.0; - fprintf(stdout, "CalculateFeedbackParamaters: V = %g :: rho = %f :: rho_z = %f :: mass = %f :: metal :: %f\n", - EjectaVolume, EjectaDensity, EjectaMetalDensity,EjectaVolume*EjectaDensity*DensityUnits/SolarMass, - EjectaMetalDensity*EjectaVolume/SolarMass*DensityUnits); + // fprintf(stdout, "CalculateFeedbackParamaters: V = %g :: rho = %f :: rho_z = %f :: mass = %f :: metal :: %f\n", + // EjectaVolume, EjectaDensity, EjectaMetalDensity,EjectaVolume*EjectaDensity*DensityUnits/SolarMass, + // EjectaMetalDensity*EjectaVolume/SolarMass*DensityUnits); #define DEBUG #ifdef DEBUG From 0a2f9f7ffa9cc1e5ccb0c9e5594970cb26c04d90 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 16 Dec 2019 14:02:14 -0800 Subject: [PATCH 048/115] Moved conservation check into StarParticleAddFeedback so that it is conservative across grids --- src/enzo/Grid.h | 2 + src/enzo/Grid_AddFeedbackSphere.C | 86 ++----- src/enzo/StarParticleAddFeedback.C | 389 ++++++++++++++++------------- 3 files changed, 235 insertions(+), 242 deletions(-) diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index 842752c9f..b5cdc84ca 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -404,6 +404,8 @@ class grid FLOAT ReturnTime() {return Time;}; FLOAT ReturnOldTime() {return OldTime;}; float ReturnTimeStep() {return dtFixed;}; + // Get the volume of one cell on this grid + float GetVCell() {return CellWidth[0][0]*CellWidth[1][0]*CellWidth[2][0];}; /* Return, set grid ID */ diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 0744a372b..838a6d380 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -165,67 +165,15 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU // EjectaMetalDensity *= 0.1; // EjectaThermalEnergy *= 0.1; // } -/* - - In principle, the feedback metal and mass density are depending on - a sphere with radius = radius. Since the grid is NOT spherical, - we need to find the actual volume that will be deposited into, and - rescale the densities to fill that volume with the correct mass. - */ - //1) First loop to calculate number of cells that will be deposited into - outerRadius2 = 1.2 * 1.2 * radius * radius; - int NumAffectedCells = 0; - for (k = 0; k < GridDimension[2]; k++) - { - - delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; - sz = sign(delz); - delz = fabs(delz); - delz = min(delz, DomainWidth[2] - delz); - - for (j = 0; j < GridDimension[1]; j++) - { - - dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; - sy = sign(dely); - dely = fabs(dely); - dely = min(dely, DomainWidth[1] - dely); - - index = (k * GridDimension[1] + j) * GridDimension[0]; - for (i = 0; i < GridDimension[0]; i++, index++) - { - - delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; - sx = sign(delx); - delx = fabs(delx); - delx = min(delx, DomainWidth[0] - delx); - - radius2 = delx * delx + dely * dely + delz * delz; - if (radius2 <= outerRadius2) - { - - NumAffectedCells++; - } - } - } - } - //2) rescale EjectaMetalDensity and EjectaDensity - FLOAT V_new = NumAffectedCells*pow(CellWidth[0][0],3); - FLOAT V_old = 4.0*pi/3.0*radius*radius*radius; - float MassUnits = DensityUnits*pow(LengthUnits, 3); // needs factor dx^3 to get to physical mass - // if (debug) - fprintf(stdout, "Prescaled EjectaDensity=%f EjectaMetalDensity=%f\n", EjectaDensity, EjectaMetalDensity); - fprintf(stdout, "Prescaled mass = %f metal = %f\n", EjectaDensity*V_old*MassUnits/SolarMass, EjectaMetalDensity*V_old*MassUnits/SolarMass); - bool rescale = true;//V_new > V_old; - EjectaMetalDensity = (rescale)?(EjectaMetalDensity * V_old/V_new): (EjectaMetalDensity); - EjectaDensity = (rescale)?(EjectaDensity * V_old/V_new):(EjectaDensity); - if (rescale){ - fprintf(stdout, "Scaling P3 Feedback: N_aff=%"ISYM" V_new=%"GSYM" V_old=%"GSYM"\n", NumAffectedCells,V_new*pow(LengthUnits,3), - 4.0/3.0*pi*pow(radius,3)*pow(LengthUnits,3)); + FLOAT V_old = radius*radius*radius*4.0*pi/3.0; + float MassUnits = DensityUnits*pow(LengthUnits, 3); + if (EjectaDensity > 0){ + // fprintf(stdout, "Scaling P3 Feedback: N_aff=%"ISYM" V_new=%"GSYM" V_old=%"GSYM"\n", NumAffectedCells,V_new*pow(LengthUnits,3), + // 4.0/3.0*pi*pow(radius,3)*pow(LengthUnits,3)); fprintf(stdout, "New EjectaMetalDensity = %"GSYM"\n", EjectaMetalDensity); fprintf(stdout, "New EjectaDensity = %"GSYM"\n",EjectaDensity); - fprintf(stdout, "Mass to deposit = %f\n", EjectaDensity*V_new*MassUnits/SolarMass); - fprintf(stdout, "Metal to deposit = %f\n", EjectaMetalDensity*V_new*MassUnits/SolarMass); + fprintf(stdout, "Mass to deposit = %f\n", EjectaDensity*V_old*MassUnits/SolarMass); + fprintf(stdout, "Metal to deposit = %f\n", EjectaMetalDensity*V_old*MassUnits/SolarMass); } //3) Continue on and profit with mass conserving feedback! @@ -374,17 +322,19 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END j-direction } // END k-direction // if (debug){ - fprintf(stdout, "[ %d ]Coupling feedback on level %d for star [%d] assigned to level %d\n", cstar->ReturnGridID(), level, + if (EjectaDensity > 0){ + fprintf(stdout, "$$$$$\n[ %d ]Coupled feedback on level %d for star [%d] assigned to level %d ::: ", cstar->ReturnGridID(), level, cstar->ReturnID(), cstar->ReturnLevel()); - fprintf(stdout, "Deposited Vol = %e\n", depositedVolume*pow(LengthUnits,3)); - fprintf(stdout, "Deposited Vol/Vold = %f\n", depositedVolume/V_old); - fprintf(stdout, "Deposited Vol/Vnew = %f\n", depositedVolume/V_new); - fprintf(stdout, "Deposited mass = %f\n", depositedMass*MassUnits/SolarMass); - fprintf(stdout, "Mass Error = %f\n", 1.0-depositedMass/(EjectaDensity*V_new)); - fprintf(stdout, "Deposited metal = %f\n", depositedMetal*MassUnits/SolarMass); - fprintf(stdout, "Metal Error = %f\n", 1.0-depositedMetal/(EjectaMetalDensity*V_new)); - fprintf(stdout, "Energy Deposit = %"GSYM"\n", depositedEnergy*DensityUnits*pow(CellWidth[0][0]*LengthUnits,3)*pow(LengthUnits,2)/TimeUnits/TimeUnits); + fprintf(stdout, "Deposited Vol = %e ::", depositedVolume*pow(LengthUnits,3)); + // fprintf(stdout, "Deposited Vol/Vold = %f ::", depositedVolume/V_old); + // fprintf(stdout, "Deposited Vol/Vnew = %f ::", depositedVolume/V_new); + fprintf(stdout, "Deposited mass = %f ::", depositedMass*MassUnits/SolarMass); + fprintf(stdout, "Mass Error = %f ::", 1.0-depositedMass/(EjectaDensity*depositedVolume)); + fprintf(stdout, "Deposited metal = %f ::", depositedMetal*MassUnits/SolarMass); + fprintf(stdout, "Metal Error = %f ::", 1.0-depositedMetal/(EjectaMetalDensity*depositedVolume)); + fprintf(stdout, "Energy Deposit = %"GSYM"\n$$$$$\n", depositedEnergy*DensityUnits*pow(CellWidth[0][0]*LengthUnits,3)*pow(LengthUnits,2)/TimeUnits/TimeUnits); //exit(2); + } // } } // END Supernova diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 96322e271..e457fc844 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -53,196 +53,237 @@ int StarParticleAddFeedback(TopGridData *MetaData, Star *&AllStars, bool *&AddedFeedback) { - Star *cstar; - bool MarkedSubgrids = false; - bool SphereCheck; - int i, l, dim, temp_int, SkipMassRemoval, SphereContained, - SphereContainedNextLevel, dummy, count; - float influenceRadius, RootCellWidth, SNe_dt, dtForThisStar, MassLoss; - double EjectaThermalEnergy, EjectaDensity, EjectaMetalDensity; - FLOAT Time; - LevelHierarchyEntry *Temp; - - if (AllStars == NULL) - return SUCCESS; - - LCAPERF_START("StarParticleAddFeedback"); - - /* Get time and SNe timestep */ - - Temp = LevelArray[level]; - Time = Temp->GridData->ReturnTime(); - if (LastSupernovaTime < 0) - SNe_dt = 0.0; - else - SNe_dt = Time - LastSupernovaTime; - LastSupernovaTime = Time; - RootCellWidth = 1.0 / MetaData->TopGridDims[0]; + Star *cstar; + bool MarkedSubgrids = false; + bool SphereCheck; + int i, l, dim, temp_int, SkipMassRemoval, SphereContained, + SphereContainedNextLevel, dummy, count; + float influenceRadius, RootCellWidth, SNe_dt, dtForThisStar, MassLoss; + double EjectaThermalEnergy, EjectaDensity, EjectaMetalDensity; + FLOAT Time; + LevelHierarchyEntry *Temp; + + if (AllStars == NULL) + return SUCCESS; + + LCAPERF_START("StarParticleAddFeedback"); + + /* Get time and SNe timestep */ + + Temp = LevelArray[level]; + Time = Temp->GridData->ReturnTime(); + if (LastSupernovaTime < 0) + SNe_dt = 0.0; + else + SNe_dt = Time - LastSupernovaTime; + LastSupernovaTime = Time; + RootCellWidth = 1.0 / MetaData->TopGridDims[0]; - /* Set the units. */ + /* Set the units. */ - float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, - VelocityUnits; - GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, Time); + float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, + VelocityUnits; + GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, Time); - count = 0; + count = 0; - for (cstar = AllStars; cstar; cstar = cstar->NextStar, count++) - { + for (cstar = AllStars; cstar; cstar = cstar->NextStar, count++) + { - AddedFeedback[count] = false; + AddedFeedback[count] = false; - /* Special case for "normal" star particles to account for mass + /* Special case for "normal" star particles to account for mass loss through supernovae. */ - if (cstar->ReturnType() == NormalStar && - cstar->ReturnLevel() == level) - { - MassLoss = cstar->CalculateMassLoss(SNe_dt); - cstar->SetAccretionMass(-MassLoss); - } + if (cstar->ReturnType() == NormalStar && + cstar->ReturnLevel() == level) + { + MassLoss = cstar->CalculateMassLoss(SNe_dt); + cstar->SetAccretionMass(-MassLoss); + } - if ((cstar->ReturnFeedbackFlag() != MBH_THERMAL) && - (cstar->ReturnFeedbackFlag() != MBH_JETS) && - !cstar->ApplyFeedbackTrue(SNe_dt)) - continue; + if ((cstar->ReturnFeedbackFlag() != MBH_THERMAL) && + (cstar->ReturnFeedbackFlag() != MBH_JETS) && + !cstar->ApplyFeedbackTrue(SNe_dt)) + continue; - dtForThisStar = LevelArray[level]->GridData->ReturnTimeStep(); + dtForThisStar = LevelArray[level]->GridData->ReturnTimeStep(); - /* Compute some parameters */ + /* Compute some parameters */ - cstar->CalculateFeedbackParameters(influenceRadius, RootCellWidth, SNe_dt, EjectaDensity, - EjectaThermalEnergy, EjectaMetalDensity, DensityUnits, LengthUnits, - TemperatureUnits, TimeUnits, VelocityUnits, dtForThisStar, - Time, SphereCheck); + cstar->CalculateFeedbackParameters(influenceRadius, RootCellWidth, SNe_dt, EjectaDensity, + EjectaThermalEnergy, EjectaMetalDensity, DensityUnits, LengthUnits, + TemperatureUnits, TimeUnits, VelocityUnits, dtForThisStar, + Time, SphereCheck); - if (SphereCheck) - { + if (SphereCheck) + { - /* Recalibrate MBHFeedbackThermalRadius if requested */ + /* Recalibrate MBHFeedbackThermalRadius if requested */ - if (cstar->ReturnFeedbackFlag() == MBH_THERMAL) - RecalibrateMBHFeedbackThermalRadius(cstar->ReturnPosition(), LevelArray, level, influenceRadius, - EjectaDensity, EjectaMetalDensity, EjectaThermalEnergy); + if (cstar->ReturnFeedbackFlag() == MBH_THERMAL) + RecalibrateMBHFeedbackThermalRadius(cstar->ReturnPosition(), LevelArray, level, influenceRadius, + EjectaDensity, EjectaMetalDensity, EjectaThermalEnergy); - /* Determine if a sphere with enough mass (or equivalently radius + /* Determine if a sphere with enough mass (or equivalently radius for SNe) is enclosed within grids on this level */ - LCAPERF_START("star_FindFeedbackSphere"); - cstar->FindFeedbackSphere(LevelArray, level, influenceRadius, EjectaDensity, EjectaThermalEnergy, - SphereContained, SkipMassRemoval, DensityUnits, LengthUnits, - TemperatureUnits, TimeUnits, VelocityUnits, Time, MarkedSubgrids); - LCAPERF_STOP("star_FindFeedbackSphere"); + LCAPERF_START("star_FindFeedbackSphere"); + cstar->FindFeedbackSphere(LevelArray, level, influenceRadius, EjectaDensity, EjectaThermalEnergy, + SphereContained, SkipMassRemoval, DensityUnits, LengthUnits, + TemperatureUnits, TimeUnits, VelocityUnits, Time, MarkedSubgrids); + LCAPERF_STOP("star_FindFeedbackSphere"); - /* If the particle already had sufficient mass, we still want to + /* If the particle already had sufficient mass, we still want to mark this particle to activate it. */ - if (SkipMassRemoval == TRUE) - AddedFeedback[count] = true; + if (SkipMassRemoval == TRUE) + AddedFeedback[count] = true; - /* If there's no feedback or something weird happens, don't bother. */ + /* If there's no feedback or something weird happens, don't bother. */ - if (influenceRadius <= tiny_number || - SphereContained == FALSE || - ((cstar->ReturnFeedbackFlag() == MBH_THERMAL || - cstar->ReturnFeedbackFlag() == MBH_JETS) && - (influenceRadius >= RootCellWidth / 2 || - EjectaThermalEnergy <= tiny_number))) - continue; + if (influenceRadius <= tiny_number || + SphereContained == FALSE || + ((cstar->ReturnFeedbackFlag() == MBH_THERMAL || + cstar->ReturnFeedbackFlag() == MBH_JETS) && + (influenceRadius >= RootCellWidth / 2 || + EjectaThermalEnergy <= tiny_number))) + continue; - /* Determine if a sphere is enclosed within the grids on next level + /* Determine if a sphere is enclosed within the grids on next level If that is the case, we perform AddFeedbackSphere not here, but in the EvolveLevel of the next level. */ - SphereContainedNextLevel = FALSE; - - LCAPERF_START("star_FindFeedbackSphere2"); - if ((cstar->ReturnFeedbackFlag() == MBH_THERMAL || - cstar->ReturnFeedbackFlag() == MBH_JETS || - cstar->ReturnFeedbackFlag() == CONT_SUPERNOVA) && - LevelArray[level + 1] != NULL) - cstar->FindFeedbackSphere(LevelArray, level + 1, influenceRadius, EjectaDensity, EjectaThermalEnergy, - SphereContainedNextLevel, dummy, DensityUnits, LengthUnits, - TemperatureUnits, TimeUnits, VelocityUnits, Time, MarkedSubgrids); - LCAPERF_STOP("star_FindFeedbackSphere2"); - - // if (debug) { - // fprintf(stdout, "EjectaDensity=%g, influenceRadius=%g\n", EjectaDensity, influenceRadius); - // fprintf(stdout, "SkipMassRemoval=%d, SphereContained=%d, SphereContainedNextLevel=%d\n", - // SkipMassRemoval, SphereContained, SphereContainedNextLevel); - // } - - /* Quit this routine when + SphereContainedNextLevel = FALSE; + + LCAPERF_START("star_FindFeedbackSphere2"); + if ((cstar->ReturnFeedbackFlag() == MBH_THERMAL || + cstar->ReturnFeedbackFlag() == MBH_JETS || + cstar->ReturnFeedbackFlag() == CONT_SUPERNOVA) && + LevelArray[level + 1] != NULL) + cstar->FindFeedbackSphere(LevelArray, level + 1, influenceRadius, EjectaDensity, EjectaThermalEnergy, + SphereContainedNextLevel, dummy, DensityUnits, LengthUnits, + TemperatureUnits, TimeUnits, VelocityUnits, Time, MarkedSubgrids); + LCAPERF_STOP("star_FindFeedbackSphere2"); + + // if (debug) { + // fprintf(stdout, "EjectaDensity=%g, influenceRadius=%g\n", EjectaDensity, influenceRadius); + // fprintf(stdout, "SkipMassRemoval=%d, SphereContained=%d, SphereContainedNextLevel=%d\n", + // SkipMassRemoval, SphereContained, SphereContainedNextLevel); + // } + + /* Quit this routine when (1) sphere is not contained, or (2) sphere is contained, but the next level can contain the sphere, too. */ - if ((SphereContained == FALSE) || - (SphereContained == TRUE && SphereContainedNextLevel == TRUE)) - continue; + if ((SphereContained == FALSE) || + (SphereContained == TRUE && SphereContainedNextLevel == TRUE)) + continue; - } // ENDIF SphereCheck - else - { + } // ENDIF SphereCheck + else + { - /* When the sphere is completely confined in a grid, only apply + /* When the sphere is completely confined in a grid, only apply feedback at the level at which the star exists. */ - if (level != cstar->ReturnLevel()) - continue; - } + if (level != cstar->ReturnLevel()) + continue; + } - /* Now set cells within the radius to their values after feedback. + /* Now set cells within the radius to their values after feedback. While walking through the hierarchy, look for particle to change their properties to post-feedback values. */ - int CellsModified = 0; + int CellsModified = 0; - if (SkipMassRemoval == FALSE) - { + if (SkipMassRemoval == FALSE) + { - /* Determine the H-ionizing photon luminosity to calculate the + /* Determine the H-ionizing photon luminosity to calculate the photo-ionization and heating rate in the initial Stroemgren sphere. */ - int nbins; - double Q[MAX_ENERGY_BINS], Q_HI, sigma; - float energies[MAX_ENERGY_BINS], deltaE; + int nbins; + double Q[MAX_ENERGY_BINS], Q_HI, sigma; + float energies[MAX_ENERGY_BINS], deltaE; #ifdef TRANSFER - if (RadiativeTransfer) - { - cstar->ComputePhotonRates(TimeUnits, Time, nbins, energies, Q, dtForThisStar); - sigma = (double)FindCrossSection(0, energies[0]); // HI (cm^2) - Q_HI = Q[0]; - deltaE = energies[0] - 13.6; // eV - } - else + if (RadiativeTransfer) + { + cstar->ComputePhotonRates(TimeUnits, Time, nbins, energies, Q, dtForThisStar); + sigma = (double)FindCrossSection(0, energies[0]); // HI (cm^2) + Q_HI = Q[0]; + deltaE = energies[0] - 13.6; // eV + } + else #endif /* TRANSFER */ - { - Q_HI = 0.0; - sigma = 0.0; - deltaE = 0.0; - } - // LevelArray[level]->GridData->AddFeedbackSphere(cstar, level, influenceRadius, DensityUnits, LengthUnits, - // VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, - // EjectaMetalDensity, EjectaThermalEnergy, Q_HI, sigma, deltaE, - // CellsModified); - for (l = level; l < MAX_DEPTH_OF_HIERARCHY; l++) - for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - Temp->GridData->AddFeedbackSphere(cstar, l, influenceRadius, DensityUnits, LengthUnits, - VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, - EjectaMetalDensity, EjectaThermalEnergy, Q_HI, sigma, deltaE, - CellsModified); - } // ENDIF - - // fprintf(stdout, "StarParticleAddFeedback[%"ISYM"][%"ISYM"]: " - // "Radius = %e pc_cm, changed %"ISYM" cells.\n", - // cstar->ReturnID(), level, influenceRadius*LengthUnits/pc_cm, CellsModified); - - /* Remove mass from the star that is added to grids. Also, because EjectaDensity + { + Q_HI = 0.0; + sigma = 0.0; + deltaE = 0.0; + } + float rho = EjectaDensity; + float z_rho = EjectaMetalDensity; + for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ + if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ + if (!LevelArray[l]) continue; + /* + Spheres interacting with grids isnt consistent; Do a first pass with no deposition + to validate the volume we will deposit into, then rescale the deposition accordingly. + */ + int nCells = 0; + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + Temp->GridData->AddFeedbackSphere(cstar, l, influenceRadius, DensityUnits, + LengthUnits, + VelocityUnits, TemperatureUnits, TimeUnits, 0, 0, 0, + Q_HI, sigma, deltaE, + nCells); + /* Rescale */ + FLOAT vol_modified = nCells * LevelArray[l]->GridData->GetVCell(); + FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius + * 4.0 * pi / 3.0; +// NB: Levels > level may not deposit the whole sphere volume. leave those alone + bool rescale = (vol_modified > old_vol); + rho = (rescale) ? (EjectaDensity * old_vol / vol_modified) : EjectaDensity; + z_rho = (rescale) ? EjectaMetalDensity * old_vol / vol_modified : EjectaMetalDensity; + if (rescale) + fprintf(stdout, "\n\nRescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g\n\n\n", + l, vol_modified*pow(LengthUnits,3), + old_vol*pow(LengthUnits,3), rho * DensityUnits, EjectaDensity*DensityUnits, + z_rho * DensityUnits, EjectaMetalDensity*DensityUnits); + /* do the real deposition */ + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + Temp->GridData->AddFeedbackSphere(cstar, l, + influenceRadius, + DensityUnits, LengthUnits, + VelocityUnits, TemperatureUnits, TimeUnits, rho, z_rho, + EjectaThermalEnergy, Q_HI, sigma, deltaE, + CellsModified); + } + else{ + + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + Temp->GridData->AddFeedbackSphere(cstar, l, + influenceRadius, + DensityUnits, LengthUnits, + VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, EjectaMetalDensity, + EjectaThermalEnergy, Q_HI, sigma, deltaE, + CellsModified); + } + + } + + } // ENDIF + + // fprintf(stdout, "StarParticleAddFeedback[%"ISYM"][%"ISYM"]: " + // "Radius = %e pc_cm, changed %"ISYM" cells.\n", + // cstar->ReturnID(), level, influenceRadius*LengthUnits/pc_cm, CellsModified); + + /* Remove mass from the star that is added to grids. Also, because EjectaDensity is added with zero net momentum, increase the particle's velocity accordingly. Only for MBH_JETS; currently this is done in Grid_AddFeedbackSphere.C */ - /* + /* if (EjectaDensity != 0 && CellsModified > 0) if (cstar->ReturnFeedbackFlag() == MBH_THERMAL || cstar->ReturnFeedbackFlag() == MBH_JETS) @@ -250,43 +291,43 @@ int StarParticleAddFeedback(TopGridData *MetaData, DensityUnits, LengthUnits, CellsModified); */ - /* Only kill a Pop III star after it has gone SN */ + /* Only kill a Pop III star after it has gone SN */ - if (cstar->ReturnFeedbackFlag() == SUPERNOVA) - cstar->SetFeedbackFlag(DEATH); + if (cstar->ReturnFeedbackFlag() == SUPERNOVA) + cstar->SetFeedbackFlag(DEATH); - /* We only color the fields once */ + /* We only color the fields once */ - AddedFeedback[count] = true; + AddedFeedback[count] = true; #ifdef UNUSED - temp_int = CellsModified; - MPI_Reduce(&temp_int, &CellsModified, 1, MPI_INT, MPI_SUM, ROOT_PROCESSOR, - MPI_COMM_WORLD); - - if (debug) - { - if (cstar->ReturnFeedbackFlag() != FORMATION) - fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " - "Radius = %" GSYM " pc\n", - cstar->ReturnID(), level, influenceRadius * LengthUnits / pc_cm); - if (cstar->ReturnFeedbackFlag() == DEATH || - - cstar->ReturnFeedbackFlag() == CONT_SUPERNOVA || - cstar->ReturnFeedbackFlag() == MBH_THERMAL || - cstar->ReturnFeedbackFlag() == MBH_JETS) - fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " - "Energy = %" GSYM " , skip = %" ISYM "\n", - cstar->ReturnID(), level, EjectaThermalEnergy, SkipMassRemoval); - fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " - "changed %" ISYM " cells. AddedFeedback[%d] = %d\n", - cstar->ReturnID(), level, CellsModified, - count, AddedFeedback[count]); - } + temp_int = CellsModified; + MPI_Reduce(&temp_int, &CellsModified, 1, MPI_INT, MPI_SUM, ROOT_PROCESSOR, + MPI_COMM_WORLD); + + if (debug) + { + if (cstar->ReturnFeedbackFlag() != FORMATION) + fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " + "Radius = %" GSYM " pc\n", + cstar->ReturnID(), level, influenceRadius * LengthUnits / pc_cm); + if (cstar->ReturnFeedbackFlag() == DEATH || + + cstar->ReturnFeedbackFlag() == CONT_SUPERNOVA || + cstar->ReturnFeedbackFlag() == MBH_THERMAL || + cstar->ReturnFeedbackFlag() == MBH_JETS) + fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " + "Energy = %" GSYM " , skip = %" ISYM "\n", + cstar->ReturnID(), level, EjectaThermalEnergy, SkipMassRemoval); + fprintf(stdout, "StarParticleAddFeedback[%" ISYM "][%" ISYM "]: " + "changed %" ISYM " cells. AddedFeedback[%d] = %d\n", + cstar->ReturnID(), level, CellsModified, + count, AddedFeedback[count]); + } #endif - } // ENDFOR stars + } // ENDFOR stars - LCAPERF_STOP("StarParticleAddFeedback"); - return SUCCESS; + LCAPERF_STOP("StarParticleAddFeedback"); + return SUCCESS; } From e23cc9574cdcbba784aa223cea3e3c9389b64ee9 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 21 Dec 2019 10:51:33 -0800 Subject: [PATCH 049/115] debugged colour evolution--seems to work on laptop; next testing on frontera --- src/enzo/Grid.h | 4 + src/enzo/Grid_AddFeedbackSphere.C | 11 ++- ...Grid_StarParticleCalculateFeedbackVolume.C | 98 +++++++++++++++++++ src/enzo/Make.config.objects | 1 + src/enzo/StarParticleAddFeedback.C | 57 ++++++----- src/enzo/macros_and_parameters.h | 2 +- 6 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 src/enzo/Grid_StarParticleCalculateFeedbackVolume.C diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index b5cdc84ca..b72aa276e 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2815,6 +2815,10 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int RemoveParticle(int ID, bool disable=false); int RemoveActiveParticle(PINT ID, int NewProcessorNumber); + + int StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radius, float DensityUnits, + float LengthUnits, float VelocityUnits, + float TemperatureUnits, float TimeUnits); int AddFeedbackSphere(Star *cstar, int level, float radius, float DensityUnits, float LengthUnits, float VelocityUnits, diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 838a6d380..7f9e06a7d 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -389,7 +389,8 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU /* 1/1.2^3 factor to dilute the density since we're depositing a uniform ejecta in a sphere of 1.2*radius without a ramp. The ramp is only applied to the - energy*density factor. */ + energy*density factor. + Dont need to rescale here, since that is done in the calling routine !AIW */ factor = 1.0;//0.578704; OldDensity = BaryonField[DensNum][index]; @@ -985,13 +986,15 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU radius2 = max(radius2, 0.0625 * CellWidth[0][i] * CellWidth[0][i]); // (0.25*dx)^2 if (MetallicityField == TRUE) - metallicity = BaryonField[MetalNum][index] / BaryonField[DensNum][index]; + /* Use total metallicity from PopIII SN as well if available -AIW */ + metallicity = (SNColourNum > 0)?(BaryonField[SNColourNum][index]+BaryonField[MetalNum][index])/BaryonField[DensNum][index] + :BaryonField[MetalNum][index] / BaryonField[DensNum][index]; else metallicity = 0; fhz = fh * (1 - metallicity); fhez = (1 - fh) * (1 - metallicity); - + float d0 = BaryonField[DensNum][index]; BaryonField[DensNum][index] = EjectaDensity; if (MultiSpecies) @@ -1018,6 +1021,8 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU BaryonField[HDINum][index] = tiny_number * BaryonField[DensNum][index]; } + /* factor is initialized to zero and never set--should we be setting the metals to zero? + Why is standard metal_density field never touched?*/ if (SNColourNum > 0) BaryonField[SNColourNum][index] *= factor; if (Metal2Num > 0) diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C new file mode 100644 index 000000000..696c657e9 --- /dev/null +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -0,0 +1,98 @@ + #include +#include +#include +#include +#include "ErrorExceptions.h" +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "list.h" +#include "Fluxes.h" +#include "GridList.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "Hierarchy.h" +#include "CosmologyParameters.h" +#include "phys_constants.h" + + + +int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radius, float DensityUnits, + float LengthUnits, float VelocityUnits, + float TemperatureUnits, float TimeUnits) +{ + + const float WhalenMaxVelocity = 35; // km/s + + int dim, i, j, k, index; + int sx, sy, sz; + FLOAT delx, dely, delz, radius2, Radius, DomainWidth[MAX_DIMENSION]; + + if (MyProcessorNumber != ProcessorNumber) + return 0.0; + + /* If the radius is less than the cell width, return */ + + if (radius < CellWidth[0][0]) + return 0.0; + + /* Check if sphere overlaps with this grid */ + + for (dim = 0; dim < GridRank; dim++) + if (cstar->pos[dim] - radius > GridRightEdge[dim] || + cstar->pos[dim] + radius < GridLeftEdge[dim]) + return 0.0; + + for (dim = 0; dim < GridRank; dim++) + DomainWidth[dim] = DomainRightEdge[dim] - DomainLeftEdge[dim]; + + + + + + + + /*********************************************************************** + Checking volume--The real volume the supernova + will be put into. + ************************************************************************/ + + float outerRadius2=1.2*1.2*radius*radius; + FLOAT depositedVolume = 0.0; + int CellsModified = 0; + for (k = 0; k < GridDimension[2]; k++) + { + + delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->ReturnPosition()[2]; + sz = sign(delz); + delz = fabs(delz); + delz = min(delz, DomainWidth[2] - delz); + + for (j = 0; j < GridDimension[1]; j++) + { + + dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->ReturnPosition()[1]; + sy = sign(dely); + dely = fabs(dely); + dely = min(dely, DomainWidth[1] - dely); + + index = (k * GridDimension[1] + j) * GridDimension[0]; + for (i = 0; i < GridDimension[0]; i++, index++) + { + + delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->ReturnPosition()[0]; + sx = sign(delx); + delx = fabs(delx); + delx = min(delx, DomainWidth[0] - delx); + + radius2 = delx * delx + dely * dely + delz * delz; + if (radius2 <= outerRadius2) + { + depositedVolume += CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + CellsModified ++; + } // END if inside radius + } // END i-direction + } // END j-direction + } // END k-direction + return CellsModified; +} \ No newline at end of file diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index 5a9c7bc8e..0e6e82e4b 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -343,6 +343,7 @@ OBJS_CONFIG_LIB = \ Grid_AddExternalAcceleration.o \ Grid_AddExternalPotentialField.o \ Grid_AddFeedbackSphere.o \ + Grid_StarParticleCalculateFeedbackVolume.o \ Grid_AddFieldMassToMassFlaggingField.o \ Grid_AddFields.o \ Grid_AddMagneticSupernovaeToList.o \ diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index e457fc844..320856636 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -51,6 +51,7 @@ FLOAT FindCrossSection(int type, float energy); int StarParticleAddFeedback(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], int level, Star *&AllStars, bool *&AddedFeedback) + { Star *cstar; @@ -224,31 +225,36 @@ int StarParticleAddFeedback(TopGridData *MetaData, } float rho = EjectaDensity; float z_rho = EjectaMetalDensity; - for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ - if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ + for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ // initially l=level; lNextGridThisLevel) - Temp->GridData->AddFeedbackSphere(cstar, l, influenceRadius, DensityUnits, + nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( + cstar, l, influenceRadius, DensityUnits, LengthUnits, - VelocityUnits, TemperatureUnits, TimeUnits, 0, 0, 0, - Q_HI, sigma, deltaE, - nCells); - /* Rescale */ - FLOAT vol_modified = nCells * LevelArray[l]->GridData->GetVCell(); + VelocityUnits, TemperatureUnits, TimeUnits); FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius * 4.0 * pi / 3.0; -// NB: Levels > level may not deposit the whole sphere volume. leave those alone - bool rescale = (vol_modified > old_vol); - rho = (rescale) ? (EjectaDensity * old_vol / vol_modified) : EjectaDensity; - z_rho = (rescale) ? EjectaMetalDensity * old_vol / vol_modified : EjectaMetalDensity; - if (rescale) - fprintf(stdout, "\n\nRescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g\n\n\n", - l, vol_modified*pow(LengthUnits,3), + vol_modified = nCells * LevelArray[l]->GridData->GetVCell(); +// NB: Levels > level may not deposit the whole sphere volume. leave those alone; Leave MBH deposition alone +// because I dont know it. -AIW + float rescale = 1.0; + if (vol_modified > old_vol + && (cstar->ReturnFeedbackFlag() == SUPERNOVA)) + rescale = (old_vol/vol_modified); + rho = EjectaDensity * rescale; + z_rho = EjectaMetalDensity * rescale; + if (rescale < 1.0) + fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g\n\n\n", + cstar->ReturnFeedbackFlag(), l, vol_modified*pow(LengthUnits,3), old_vol*pow(LengthUnits,3), rho * DensityUnits, EjectaDensity*DensityUnits, z_rho * DensityUnits, EjectaMetalDensity*DensityUnits); /* do the real deposition */ @@ -259,17 +265,16 @@ int StarParticleAddFeedback(TopGridData *MetaData, VelocityUnits, TemperatureUnits, TimeUnits, rho, z_rho, EjectaThermalEnergy, Q_HI, sigma, deltaE, CellsModified); - } - else{ - - for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - Temp->GridData->AddFeedbackSphere(cstar, l, - influenceRadius, - DensityUnits, LengthUnits, - VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, EjectaMetalDensity, - EjectaThermalEnergy, Q_HI, sigma, deltaE, - CellsModified); - } + // } + // else{ + // for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + // Temp->GridData->AddFeedbackSphere(cstar, l, + // influenceRadius, + // DensityUnits, LengthUnits, + // VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, EjectaMetalDensity, + // EjectaThermalEnergy, Q_HI, sigma, deltaE, + // CellsModified); + // } } diff --git a/src/enzo/macros_and_parameters.h b/src/enzo/macros_and_parameters.h index 9448e7af2..b9fcee0e5 100644 --- a/src/enzo/macros_and_parameters.h +++ b/src/enzo/macros_and_parameters.h @@ -74,7 +74,7 @@ #define GRAVITY_BUFFER_SIZE 3 -#define MAX_FLAGGING_METHODS 9 +#define MAX_FLAGGING_METHODS 21 #define MAX_STATIC_REGIONS 1000 From a1b5ae64104b2adfda0ead12b2ecadc1029a20be Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 30 Dec 2019 17:20:30 -0600 Subject: [PATCH 050/115] attempted debugging on frontera; still have accumulating errors beyond first deposition :( --- src/enzo/Grid_AddFeedbackSphere.C | 8 +-- src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C | 4 +- ...Grid_StarParticleCalculateFeedbackVolume.C | 3 +- src/enzo/StarParticleAddFeedback.C | 59 ++++++++++++------- 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 7f9e06a7d..6a08c5e08 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -244,7 +244,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU without a ramp. The ramp is only applied to the energy*density factor. */ - factor = 1.0;//0.578704; + factor = 0.578704; OldDensity = BaryonField[DensNum][index]; BaryonField[DensNum][index] += factor * EjectaDensity; @@ -312,8 +312,8 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } if (MetallicityField == TRUE){ - BaryonField[MetalNum][index] += EjectaMetalDensity; - depositedMetal += EjectaMetalDensity*pow(CellWidth[0][0],3); + BaryonField[MetalNum][index] += factor*EjectaMetalDensity; + depositedMetal += factor*EjectaMetalDensity*pow(CellWidth[0][0],3); } CellsModified++; @@ -322,7 +322,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END j-direction } // END k-direction // if (debug){ - if (EjectaDensity > 0){ + if (EjectaDensity > 0 && depositedVolume > 0){ fprintf(stdout, "$$$$$\n[ %d ]Coupled feedback on level %d for star [%d] assigned to level %d ::: ", cstar->ReturnGridID(), level, cstar->ReturnID(), cstar->ReturnLevel()); fprintf(stdout, "Deposited Vol = %e ::", depositedVolume*pow(LengthUnits,3)); diff --git a/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C b/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C index 595a8a2b0..288286795 100644 --- a/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C +++ b/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C @@ -76,7 +76,7 @@ int grid::FlagCellsToBeRefinedByPopIII(int level) //If A: no particles or // B: the resolution is such that its already as refined as PopIIISupernovaMustRefineResolution - int nCellsPerRadius = 1.1*float(PopIIISupernovaRadius)/(CellWidth[0][0]*LengthUnits/pc_cm)+0.5; + int nCellsPerRadius = 1.4*float(PopIIISupernovaRadius)/(CellWidth[0][0]*LengthUnits/pc_cm)+0.5; if (NumberOfParticles == 0 || 2*nCellsPerRadius > PopIIISupernovaMustRefineResolution || level >= MaximumRefinementLevel){ for (i = 0; i < size; i++) { @@ -103,7 +103,7 @@ int grid::FlagCellsToBeRefinedByPopIII(int level) { // fprintf(stdout, "Flagging cells for particle m=%"FSYM" fact=%"FSYM" Time=%"FSYM"\n", m, factor/3.1557e13, Time*TimeUnits/3.1557e13); // refine a radius a*Pop3 SN radius - FLOAT radius = 1.1 * PopIIISupernovaRadius * 3.086e18 / LengthUnits; + FLOAT radius = 1.4 * PopIIISupernovaRadius * 3.086e18 / LengthUnits; CellSize = FLOAT(CellWidth[0][0]); for (k = Start[2]; k <= End[2]; k++) diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index 696c657e9..8145abd02 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -22,7 +22,6 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi float TemperatureUnits, float TimeUnits) { - const float WhalenMaxVelocity = 35; // km/s int dim, i, j, k, index; int sx, sy, sz; @@ -57,7 +56,7 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi will be put into. ************************************************************************/ - float outerRadius2=1.2*1.2*radius*radius; + float outerRadius2=radius*radius; FLOAT depositedVolume = 0.0; int CellsModified = 0; for (k = 0; k < GridDimension[2]; k++) diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 320856636..0d67d9845 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -235,47 +235,62 @@ int StarParticleAddFeedback(TopGridData *MetaData, int nCells = 0; /* Get the volume that the sphere interacts with */ + FLOAT vol_modified = 0.0; - for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( + if (cstar->ReturnFeedbackFlag() == SUPERNOVA) + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( cstar, l, influenceRadius, DensityUnits, LengthUnits, VelocityUnits, TemperatureUnits, TimeUnits); FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius * 4.0 * pi / 3.0; vol_modified = nCells * LevelArray[l]->GridData->GetVCell(); + FLOAT AllVol = 0; + + // sum volume across all processes for this level + // (sphere can be across procs as well!) -AIW + + if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ + MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // NB: Levels > level may not deposit the whole sphere volume. leave those alone; Leave MBH deposition alone // because I dont know it. -AIW + + if (vol_modified > 0.0) + printf("level %d Prior Deposition Masses M = %g Z = %g AllVol = %g rankVol = %g\n ",level, + AllVol*EjectaDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, + AllVol*EjectaMetalDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, + AllVol*pow(LengthUnits,3), vol_modified*pow(LengthUnits,3)); + + } float rescale = 1.0; - if (vol_modified > old_vol - && (cstar->ReturnFeedbackFlag() == SUPERNOVA)) - rescale = (old_vol/vol_modified); - rho = EjectaDensity * rescale; - z_rho = EjectaMetalDensity * rescale; - if (rescale < 1.0) - fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g\n\n\n", + if (AllVol > old_vol + && (cstar->ReturnFeedbackFlag() == SUPERNOVA)){ + rescale = (old_vol/AllVol); + rho = EjectaDensity * rescale; + z_rho = EjectaMetalDensity * rescale; + } + else{ + rho = EjectaDensity; + z_rho = EjectaMetalDensity; + } + if (rescale < 1.0 && level == l) + fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", cstar->ReturnFeedbackFlag(), l, vol_modified*pow(LengthUnits,3), old_vol*pow(LengthUnits,3), rho * DensityUnits, EjectaDensity*DensityUnits, - z_rho * DensityUnits, EjectaMetalDensity*DensityUnits); + z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, + z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); + /* do the real deposition */ - for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) Temp->GridData->AddFeedbackSphere(cstar, l, influenceRadius, DensityUnits, LengthUnits, VelocityUnits, TemperatureUnits, TimeUnits, rho, z_rho, EjectaThermalEnergy, Q_HI, sigma, deltaE, CellsModified); - // } - // else{ - // for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - // Temp->GridData->AddFeedbackSphere(cstar, l, - // influenceRadius, - // DensityUnits, LengthUnits, - // VelocityUnits, TemperatureUnits, TimeUnits, EjectaDensity, EjectaMetalDensity, - // EjectaThermalEnergy, Q_HI, sigma, deltaE, - // CellsModified); - // } - } } // ENDIF From 0c8c54b25976ef65259ce6615eae0a348516d8b4 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 30 Dec 2019 21:30:04 -0800 Subject: [PATCH 051/115] debugged on laptop; further testing on frontera --- src/enzo/Grid_AddFeedbackSphere.C | 17 +-- ...Grid_StarParticleCalculateFeedbackVolume.C | 7 +- src/enzo/StarParticleAddFeedback.C | 135 ++++++++++-------- 3 files changed, 86 insertions(+), 73 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 6a08c5e08..f479b6f86 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -132,7 +132,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU // 1988 or Tenorio-Tagle 1996). //const float MetalRadius = 0.75; - const float MetalRadius = 1.0; + const float MetalRadius = 1.0/1.2; float ionizedFraction = 0.999; // Assume supernova is ionized float maxGE, MetalRadius2, PrimordialDensity, metallicity, fhz, fhez; float outerRadius2, delta_fz; @@ -181,7 +181,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU EjectaMetalDensity *= pow(MetalRadius, -3.0); PrimordialDensity = EjectaDensity - EjectaMetalDensity; MetalRadius2 = radius * radius * MetalRadius * MetalRadius; - outerRadius2 = radius * radius*1.2*1.2; + outerRadius2 = radius * radius; /* Remove mass from the star that will now be added to grids. @@ -204,8 +204,8 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // ENDIF !Supernova maxGE = MAX_TEMPERATURE / (TemperatureUnits * (Gamma - 1.0) * 0.6); - - for (k = 0; k < GridDimension[2]; k++) + int GZ = 0;//NumberOfGhostZones; + for (k = GZ; k < GridDimension[2]; k++) { delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; @@ -213,7 +213,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU delz = fabs(delz); delz = min(delz, DomainWidth[2] - delz); - for (j = 0; j < GridDimension[1]; j++) + for (j = GZ; j < GridDimension[1]; j++) { dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; @@ -222,7 +222,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU dely = min(dely, DomainWidth[1] - dely); index = (k * GridDimension[1] + j) * GridDimension[0]; - for (i = 0; i < GridDimension[0]; i++, index++) + for (i = GZ; i < GridDimension[0]; i++, index++) { delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; @@ -244,7 +244,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU without a ramp. The ramp is only applied to the energy*density factor. */ - factor = 0.578704; + factor =1.0;// 0.578704; OldDensity = BaryonField[DensNum][index]; BaryonField[DensNum][index] += factor * EjectaDensity; @@ -323,7 +323,8 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END k-direction // if (debug){ if (EjectaDensity > 0 && depositedVolume > 0){ - fprintf(stdout, "$$$$$\n[ %d ]Coupled feedback on level %d for star [%d] assigned to level %d ::: ", cstar->ReturnGridID(), level, + fprintf(stdout, "$$$$$\n[ %d::%d ]Coupled feedback on level %d for star [%d] assigned to level %d ::: ", + ProcessorNumber, cstar->ReturnGridID(), level, cstar->ReturnID(), cstar->ReturnLevel()); fprintf(stdout, "Deposited Vol = %e ::", depositedVolume*pow(LengthUnits,3)); // fprintf(stdout, "Deposited Vol/Vold = %f ::", depositedVolume/V_old); diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index 8145abd02..1845466a1 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -59,7 +59,8 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi float outerRadius2=radius*radius; FLOAT depositedVolume = 0.0; int CellsModified = 0; - for (k = 0; k < GridDimension[2]; k++) + int GZ = NumberOfGhostZones; + for (k = GZ; k < GridDimension[2]; k++) { delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->ReturnPosition()[2]; @@ -67,7 +68,7 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi delz = fabs(delz); delz = min(delz, DomainWidth[2] - delz); - for (j = 0; j < GridDimension[1]; j++) + for (j = GZ; j < GridDimension[1]; j++) { dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->ReturnPosition()[1]; @@ -76,7 +77,7 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi dely = min(dely, DomainWidth[1] - dely); index = (k * GridDimension[1] + j) * GridDimension[0]; - for (i = 0; i < GridDimension[0]; i++, index++) + for (i = GZ; i < GridDimension[0]; i++, index++) { delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->ReturnPosition()[0]; diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 0d67d9845..ee509cb8d 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -225,73 +225,84 @@ int StarParticleAddFeedback(TopGridData *MetaData, } float rho = EjectaDensity; float z_rho = EjectaMetalDensity; + FLOAT AVL0 = 0.0; for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ // initially l=level; lReturnFeedbackFlag() == SUPERNOVA) - for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( - cstar, l, influenceRadius, DensityUnits, - LengthUnits, - VelocityUnits, TemperatureUnits, TimeUnits); - FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius - * 4.0 * pi / 3.0; - vol_modified = nCells * LevelArray[l]->GridData->GetVCell(); - FLOAT AllVol = 0; - - // sum volume across all processes for this level - // (sphere can be across procs as well!) -AIW - - if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ - MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - -// NB: Levels > level may not deposit the whole sphere volume. leave those alone; Leave MBH deposition alone -// because I dont know it. -AIW - - if (vol_modified > 0.0) - printf("level %d Prior Deposition Masses M = %g Z = %g AllVol = %g rankVol = %g\n ",level, - AllVol*EjectaDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, - AllVol*EjectaMetalDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, - AllVol*pow(LengthUnits,3), vol_modified*pow(LengthUnits,3)); + if (!LevelArray[l]) continue; + + if (cstar->ReturnFeedbackFlag() == SUPERNOVA) + { + /* + Spheres interacting with grids isnt consistent; Do a first pass with no deposition + to validate the volume we will deposit into, then rescale the deposition accordingly. + --AIW + */ + int nCells = 0; + + /* Get the volume that the sphere interacts with */ + + FLOAT vol_modified = 0.0; + if (cstar->ReturnFeedbackFlag() == SUPERNOVA) + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( + cstar, l, influenceRadius, DensityUnits, + LengthUnits, + VelocityUnits, TemperatureUnits, TimeUnits); + FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius + * 4.0 * pi / 3.0; + vol_modified = nCells * LevelArray[l]->GridData->GetVCell(); + FLOAT AllVol = 0; + + // sum volume across all processes for this level + // (sphere can be across procs as well!) -AIW + + if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ + MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + if (l == level) + AVL0 = AllVol; + // NB: Levels > level may not deposit the whole sphere volume. leave those alone; Leave MBH deposition alone + // because I dont know it. -AIW + + if (vol_modified > 0.0) + printf("level %d Prior Deposition Masses M = %g Z = %g AllVol = %g rankVol = %g ratio = %f r_mass = %g r_z = %g\n ", + l, AllVol*EjectaDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, + AllVol*EjectaMetalDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, + AllVol*pow(LengthUnits,3), vol_modified*pow(LengthUnits,3), + old_vol/AllVol, + vol_modified*EjectaDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, + vol_modified*EjectaMetalDensity*pow(LengthUnits,3)*DensityUnits/SolarMass + ); + + } + float rescale = 1.0; + if (l == level){ + rescale = (old_vol/AllVol); + rho = EjectaDensity * rescale; + z_rho = EjectaMetalDensity * rescale; } - float rescale = 1.0; - if (AllVol > old_vol - && (cstar->ReturnFeedbackFlag() == SUPERNOVA)){ - rescale = (old_vol/AllVol); - rho = EjectaDensity * rescale; - z_rho = EjectaMetalDensity * rescale; - } - else{ - rho = EjectaDensity; - z_rho = EjectaMetalDensity; - } - if (rescale < 1.0 && level == l) - fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", - cstar->ReturnFeedbackFlag(), l, vol_modified*pow(LengthUnits,3), - old_vol*pow(LengthUnits,3), rho * DensityUnits, EjectaDensity*DensityUnits, - z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, - z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); - + if (l > level) + { + rho = EjectaDensity*pow(0.578703704,l-level);//*AllVol/AVL0 ; + z_rho = EjectaMetalDensity*pow(0.578703704,l-level);//*AllVol/AVL0; + } + if (rescale < 1.0) + fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", + cstar->ReturnFeedbackFlag(), l, AllVol*pow(LengthUnits,3), + old_vol*pow(LengthUnits,3), rho * DensityUnits, EjectaDensity*DensityUnits, + z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, + rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, + z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); + } /* do the real deposition */ - for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - Temp->GridData->AddFeedbackSphere(cstar, l, - influenceRadius, - DensityUnits, LengthUnits, - VelocityUnits, TemperatureUnits, TimeUnits, rho, z_rho, - EjectaThermalEnergy, Q_HI, sigma, deltaE, - CellsModified); - } + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + Temp->GridData->AddFeedbackSphere(cstar, l, + influenceRadius, + DensityUnits, LengthUnits, + VelocityUnits, TemperatureUnits, TimeUnits, rho, z_rho, + EjectaThermalEnergy, Q_HI, sigma, deltaE, + CellsModified); + } } // ENDIF From 9164421c34986aa43b09ba36b009a1e8b75923e1 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Tue, 31 Dec 2019 16:10:09 -0600 Subject: [PATCH 052/115] altered factor for deposting on higher grids --- src/enzo/StarParticleAddFeedback.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index ee509cb8d..d19707ab5 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -282,8 +282,8 @@ int StarParticleAddFeedback(TopGridData *MetaData, } if (l > level) { - rho = EjectaDensity*pow(0.578703704,l-level);//*AllVol/AVL0 ; - z_rho = EjectaMetalDensity*pow(0.578703704,l-level);//*AllVol/AVL0; + rho = EjectaDensity*pow(0.578703704,1);//*AllVol/AVL0 ; + z_rho = EjectaMetalDensity*pow(0.578703704,1);//*AllVol/AVL0; } if (rescale < 1.0) fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", From 1eb852239d358c5788ac8c496ef5ee826b83e0d4 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 2 Jan 2020 19:00:17 -0800 Subject: [PATCH 053/115] Added finest-level check to creation criteria! --- src/enzo/Grid_MechStarsCreation.C | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index eb3e992b5..cb4bf4262 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -42,7 +42,6 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, { /* If limiting timesteps for SNe, return if not the right level */ if (level < StarMakeLevel) return 0; - /* these flags are used to determine if we should set off a seed SNe if (gridShouldFormStars && !notEnoughMetals) at the end, we'll seed @@ -113,7 +112,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, for (int i = GZ; i < GridDimension[0]-GZ; i++){ /* Particle creation has several criteria: - + 0. is this the finest level for this cell 1. Density > overdensity 2. is flow converging by finite differences 3. is cooling time < dynamical time @@ -122,6 +121,8 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, 6. is virial parameter < 1 */ + int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; + if (BaryonField[NumberOfBaryonFields][index] != 0.0) continue; float shieldedFraction = 0; float freeFallTime = 0; float dynamicalTime = 0; @@ -140,7 +141,6 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, if (createStar){ - int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; /* Determine Mass of new particle */ From f3704211fcd840f8e08ddbfc6f50a6a801235fed Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 2 Jan 2020 19:44:55 -0800 Subject: [PATCH 054/115] Attemped to make PopII star formation conserve metal and mass --- src/enzo/Grid.h | 3 +- src/enzo/Grid_AddFeedbackSphere.C | 31 +++++-- ...Grid_StarParticleCalculateFeedbackVolume.C | 45 ++++++++-- src/enzo/Star.h | 1 + src/enzo/StarParticleAddFeedback.C | 82 ++++++++++++------- 5 files changed, 122 insertions(+), 40 deletions(-) diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index b72aa276e..9bf3582bf 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2818,7 +2818,8 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radius, float DensityUnits, float LengthUnits, float VelocityUnits, - float TemperatureUnits, float TimeUnits); + float TemperatureUnits, float TimeUnits, int &nCells, float &depositedMass, + float &depositedMetal, FLOAT &depositedVolume); int AddFeedbackSphere(Star *cstar, int level, float radius, float DensityUnits, float LengthUnits, float VelocityUnits, diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index f479b6f86..7a0c2e2cb 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -19,6 +19,7 @@ #include #include #include +#include #include "ErrorExceptions.h" #include "macros_and_parameters.h" #include "typedefs.h" @@ -322,7 +323,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END j-direction } // END k-direction // if (debug){ - if (EjectaDensity > 0 && depositedVolume > 0){ + if (EjectaDensity > 0 && depositedVolume > 0 && cstar->ReturnFeedbackFlag() == SUPERNOVA){ fprintf(stdout, "$$$$$\n[ %d::%d ]Coupled feedback on level %d for star [%d] assigned to level %d ::: ", ProcessorNumber, cstar->ReturnGridID(), level, cstar->ReturnID(), cstar->ReturnLevel()); @@ -955,7 +956,16 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU int gammaNum; IdentifyRadiativeTransferFields(kphHINum, gammaNum, kphHeINum, kphHeIINum, kdissH2INum, kphHMNum, kdissH2IINum); - + /* + Track density and metallicity prior to subtracting to make sure + its conservative. The Metal fraction in ie., cluster_maker.F is only + set according to the host cell, but the metals are coming from many cells + with varying metallicity levels -AIW + */ + // hold values of initial mass and metal in grid and new mass + float m0 = 0; + float z0 = 0; + float mNew = 0; for (k = 0; k < GridDimension[2]; k++) { @@ -995,9 +1005,9 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU fhz = fh * (1 - metallicity); fhez = (1 - fh) * (1 - metallicity); - float d0 = BaryonField[DensNum][index]; + m0 += BaryonField[DensNum][index]*CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; BaryonField[DensNum][index] = EjectaDensity; - + mNew += BaryonField[DensNum][index]*CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; if (MultiSpecies) { BaryonField[DeNum][index] = BaryonField[DensNum][index] * ionizedFraction; @@ -1024,8 +1034,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU /* factor is initialized to zero and never set--should we be setting the metals to zero? Why is standard metal_density field never touched?*/ + z0 += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) + *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; if (SNColourNum > 0) - BaryonField[SNColourNum][index] *= factor; + BaryonField[SNColourNum][index] = EjectaMetalDensity;//factor; if (Metal2Num > 0) BaryonField[Metal2Num][index] *= factor; @@ -1036,6 +1048,15 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END i-direction } // END j-direction } // END k-direction + // now have total metal erased from grid and density prior to formation; reset metallicity of star to conserve metals + + for (i = 0; i < NumberOfParticles; i++){ + if (ParticleNumber[i] == cstar->ReturnID()){ + printf("Resetting %d metallicity to %g from %g with mass change %g\n", + cstar->ReturnID(), EjectaMetalDensity/EjectaDensity, cstar->ReturnMetallicity(), (m0-mNew)*DensityUnits*pow(LengthUnits,3)/SolarMass); + ParticleAttribute[2][i] = EjectaMetalDensity/EjectaDensity; // all the metal must've gone into the star; but only m0-mNew mass went in + } + } } // END star birth /*********************************************************************** diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index 1845466a1..16030f9d5 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -19,7 +19,8 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radius, float DensityUnits, float LengthUnits, float VelocityUnits, - float TemperatureUnits, float TimeUnits) + float TemperatureUnits, float TimeUnits, int &nCells, float &depositedMass, + float &depositedMetal, FLOAT &depositedVolume) { @@ -45,7 +46,41 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi for (dim = 0; dim < GridRank; dim++) DomainWidth[dim] = DomainRightEdge[dim] - DomainLeftEdge[dim]; + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) + { + ENZO_FAIL("Error in IdentifyPhysicalQuantities."); + } + + /* Find Multi-species fields. */ + + int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, + DINum, DIINum, HDINum; + if (MultiSpecies) + if (this->IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, + HeIIINum, HMNum, H2INum, H2IINum, DINum, + DIINum, HDINum) == FAIL) + { + ENZO_FAIL("Error in grid->IdentifySpeciesFields."); + } + + + /* Find Metallicity or SNColour field and set flag. */ + + int SNColourNum, MetalNum, Metal2Num, MBHColourNum, Galaxy1ColourNum, + Galaxy2ColourNum, MetalIaNum, MetalIINum; + int MetallicityField = FALSE; + + if (this->IdentifyColourFields(SNColourNum, Metal2Num, MetalIaNum, + MetalIINum, MBHColourNum, Galaxy1ColourNum, + Galaxy2ColourNum) == FAIL) + ENZO_FAIL("Error in grid->IdentifyColourFields.\n"); + MetalNum = max(Metal2Num, SNColourNum); + MetallicityField = (MetalNum > 0) ? TRUE : FALSE; + if (MetalNum > 0 && SNColourNum > 0 && cstar->type == PopIII) + MetalNum = SNColourNum; @@ -57,8 +92,6 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi ************************************************************************/ float outerRadius2=radius*radius; - FLOAT depositedVolume = 0.0; - int CellsModified = 0; int GZ = NumberOfGhostZones; for (k = GZ; k < GridDimension[2]; k++) { @@ -89,10 +122,12 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi if (radius2 <= outerRadius2) { depositedVolume += CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; - CellsModified ++; + nCells ++; + depositedMass += BaryonField[DensNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + depositedMetal += BaryonField[SNColourNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; } // END if inside radius } // END i-direction } // END j-direction } // END k-direction - return CellsModified; + return SUCCESS; } \ No newline at end of file diff --git a/src/enzo/Star.h b/src/enzo/Star.h index 7164f07cb..985d28d93 100644 --- a/src/enzo/Star.h +++ b/src/enzo/Star.h @@ -70,6 +70,7 @@ class Star // Routines star_type ReturnType(void) { return type; }; + float ReturnMetallicity(void) {return Metallicity;}; int ReturnID(void) { return Identifier; }; double ReturnMass(void) { return Mass; }; float ReturnBirthTime(void) { return BirthTime; }; diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index d19707ab5..4b5501b8e 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -229,7 +229,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ // initially l=level; lReturnFeedbackFlag() == SUPERNOVA) + if (cstar->ReturnFeedbackFlag() == SUPERNOVA || cstar->ReturnFeedbackFlag() == FORMATION) { /* @@ -237,29 +237,51 @@ int StarParticleAddFeedback(TopGridData *MetaData, to validate the volume we will deposit into, then rescale the deposition accordingly. --AIW */ - int nCells = 0; - - /* Get the volume that the sphere interacts with */ + /* Get the volume that the sphere interacts with. for formation also get mass and metal mass of sphere */ + int nCells = 0; FLOAT vol_modified = 0.0; - if (cstar->ReturnFeedbackFlag() == SUPERNOVA) + float mass_dep = 0.0; + float metal_dep = 0.0; + if (cstar->ReturnFeedbackFlag() == SUPERNOVA || cstar->ReturnFeedbackFlag() == FORMATION) for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( + Temp->GridData->StarParticleCalculateFeedbackVolume( cstar, l, influenceRadius, DensityUnits, LengthUnits, - VelocityUnits, TemperatureUnits, TimeUnits); + VelocityUnits, TemperatureUnits, TimeUnits, nCells, + mass_dep, metal_dep, vol_modified); + FLOAT AllVol = 0; FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius * 4.0 * pi / 3.0; - vol_modified = nCells * LevelArray[l]->GridData->GetVCell(); - FLOAT AllVol = 0; + if (cstar->ReturnFeedbackFlag() == SUPERNOVA || cstar->ReturnFeedbackFlag() == FORMATION){ + MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + if (AVL0 == 0) + AVL0 = AllVol; + float allMass = 0; + float allMetal = 0; + FLOAT vCell = LevelArray[l]->GridData->GetVCell(); + FLOAT MassUnits = DensityUnits*pow(LengthUnits,3)/SolarMass; //code -> Msun + // if forming mass, need to check that mass accreting from grid is consistent + if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity){ + MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // Set the densities to constant value for the interior of Stromgren sphere + allMass *= MassUnits; + allMetal *= MassUnits; + printf("[%d] AllMass = %g AllZ = %g New FZ = %f volume = %g", + l, allMass, allMetal, allMetal/allMass, AVL0*pow(LengthUnits,3)); + if (allMass > 0 && AVL0 > 0){ + rho = (allMass - cstar->ReturnFinalMass())/MassUnits/AVL0*vCell; + z_rho = max(0.0,(allMetal-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity())/MassUnits)*vCell/AVL0); + printf("New densities rho=%g z_rho=%g\n",rho,z_rho); + } + + } // sum volume across all processes for this level // (sphere can be across procs as well!) -AIW - if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ - MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - if (l == level) - AVL0 = AllVol; // NB: Levels > level may not deposit the whole sphere volume. leave those alone; Leave MBH deposition alone // because I dont know it. -AIW @@ -274,24 +296,26 @@ int StarParticleAddFeedback(TopGridData *MetaData, ); } - float rescale = 1.0; - if (l == level){ - rescale = (old_vol/AllVol); - rho = EjectaDensity * rescale; - z_rho = EjectaMetalDensity * rescale; + if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ + float rescale = 1.0; + if (l == level){ + rescale = (old_vol/AllVol); + rho = EjectaDensity * rescale; + z_rho = EjectaMetalDensity * rescale; + } + if (l > level) + { + rho = EjectaDensity*pow(0.578703704,1);//*AllVol/AVL0 ; + z_rho = EjectaMetalDensity*pow(0.578703704,1);//*AllVol/AVL0; } - if (l > level) - { - rho = EjectaDensity*pow(0.578703704,1);//*AllVol/AVL0 ; - z_rho = EjectaMetalDensity*pow(0.578703704,1);//*AllVol/AVL0; + if (rescale < 1.0) + fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", + cstar->ReturnFeedbackFlag(), l, AllVol*pow(LengthUnits,3), + old_vol*pow(LengthUnits,3), rho * DensityUnits, EjectaDensity*DensityUnits, + z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, + rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, + z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); } - if (rescale < 1.0) - fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", - cstar->ReturnFeedbackFlag(), l, AllVol*pow(LengthUnits,3), - old_vol*pow(LengthUnits,3), rho * DensityUnits, EjectaDensity*DensityUnits, - z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, - rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, - z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); } /* do the real deposition */ From 8b1337a1d782a5d125c09956200a71bef7dee6c6 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 2 Jan 2020 21:43:32 -0800 Subject: [PATCH 055/115] fixed metal deposition factors; removed some prints n such. --- src/enzo/Grid_AddFeedbackSphere.C | 42 +++++++++--------------------- src/enzo/StarParticleAddFeedback.C | 10 +++---- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 7a0c2e2cb..4466dfe33 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -168,14 +168,6 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU // } FLOAT V_old = radius*radius*radius*4.0*pi/3.0; float MassUnits = DensityUnits*pow(LengthUnits, 3); - if (EjectaDensity > 0){ - // fprintf(stdout, "Scaling P3 Feedback: N_aff=%"ISYM" V_new=%"GSYM" V_old=%"GSYM"\n", NumAffectedCells,V_new*pow(LengthUnits,3), - // 4.0/3.0*pi*pow(radius,3)*pow(LengthUnits,3)); - fprintf(stdout, "New EjectaMetalDensity = %"GSYM"\n", EjectaMetalDensity); - fprintf(stdout, "New EjectaDensity = %"GSYM"\n",EjectaDensity); - fprintf(stdout, "Mass to deposit = %f\n", EjectaDensity*V_old*MassUnits/SolarMass); - fprintf(stdout, "Metal to deposit = %f\n", EjectaMetalDensity*V_old*MassUnits/SolarMass); - } //3) Continue on and profit with mass conserving feedback! // Correct for smaller enrichment radius @@ -322,21 +314,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END i-direction } // END j-direction } // END k-direction - // if (debug){ - if (EjectaDensity > 0 && depositedVolume > 0 && cstar->ReturnFeedbackFlag() == SUPERNOVA){ - fprintf(stdout, "$$$$$\n[ %d::%d ]Coupled feedback on level %d for star [%d] assigned to level %d ::: ", - ProcessorNumber, cstar->ReturnGridID(), level, - cstar->ReturnID(), cstar->ReturnLevel()); - fprintf(stdout, "Deposited Vol = %e ::", depositedVolume*pow(LengthUnits,3)); - // fprintf(stdout, "Deposited Vol/Vold = %f ::", depositedVolume/V_old); - // fprintf(stdout, "Deposited Vol/Vnew = %f ::", depositedVolume/V_new); - fprintf(stdout, "Deposited mass = %f ::", depositedMass*MassUnits/SolarMass); - fprintf(stdout, "Mass Error = %f ::", 1.0-depositedMass/(EjectaDensity*depositedVolume)); - fprintf(stdout, "Deposited metal = %f ::", depositedMetal*MassUnits/SolarMass); - fprintf(stdout, "Metal Error = %f ::", 1.0-depositedMetal/(EjectaMetalDensity*depositedVolume)); - fprintf(stdout, "Energy Deposit = %"GSYM"\n$$$$$\n", depositedEnergy*DensityUnits*pow(CellWidth[0][0]*LengthUnits,3)*pow(LengthUnits,2)/TimeUnits/TimeUnits); - //exit(2); - } + // } } // END Supernova @@ -965,6 +943,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU // hold values of initial mass and metal in grid and new mass float m0 = 0; float z0 = 0; + float zNew = 0; float mNew = 0; for (k = 0; k < GridDimension[2]; k++) { @@ -1038,6 +1017,8 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; if (SNColourNum > 0) BaryonField[SNColourNum][index] = EjectaMetalDensity;//factor; + zNew += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) + *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; if (Metal2Num > 0) BaryonField[Metal2Num][index] *= factor; @@ -1049,14 +1030,15 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END j-direction } // END k-direction // now have total metal erased from grid and density prior to formation; reset metallicity of star to conserve metals - - for (i = 0; i < NumberOfParticles; i++){ - if (ParticleNumber[i] == cstar->ReturnID()){ - printf("Resetting %d metallicity to %g from %g with mass change %g\n", - cstar->ReturnID(), EjectaMetalDensity/EjectaDensity, cstar->ReturnMetallicity(), (m0-mNew)*DensityUnits*pow(LengthUnits,3)/SolarMass); - ParticleAttribute[2][i] = EjectaMetalDensity/EjectaDensity; // all the metal must've gone into the star; but only m0-mNew mass went in + if (EjectaMetalDensity > 0 && cstar->ReturnType() == 7) + for (i = 0; i < NumberOfParticles; i++){ + if (ParticleNumber[i] == cstar->ReturnID()){ + printf("Removed %g Msun metal and put %g to star\n", z0-zNew, EjectaMetalDensity/EjectaDensity*cstar->ReturnFinalMass()); + printf("Resetting %d metallicity to %g from %g with mass change %g\n", + cstar->ReturnID(), EjectaMetalDensity/EjectaDensity, cstar->ReturnMetallicity(), (m0-mNew)*DensityUnits*pow(LengthUnits,3)/SolarMass); + ParticleAttribute[2][i] = EjectaMetalDensity/EjectaDensity; // all the metal must've gone into the star; but only m0-mNew mass went in + } } - } } // END star birth /*********************************************************************** diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 4b5501b8e..e2d7bf37e 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -262,18 +262,18 @@ int StarParticleAddFeedback(TopGridData *MetaData, FLOAT vCell = LevelArray[l]->GridData->GetVCell(); FLOAT MassUnits = DensityUnits*pow(LengthUnits,3)/SolarMass; //code -> Msun // if forming mass, need to check that mass accreting from grid is consistent - if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity){ + if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity && AVL0 > 0){ // set all this on the first valid pass MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); // Set the densities to constant value for the interior of Stromgren sphere allMass *= MassUnits; allMetal *= MassUnits; - printf("[%d] AllMass = %g AllZ = %g New FZ = %f volume = %g", - l, allMass, allMetal, allMetal/allMass, AVL0*pow(LengthUnits,3)); - if (allMass > 0 && AVL0 > 0){ + printf("[%d--%d] AllMass = %g AllZ = %g z_rho = %g New FZ = %g volume = %g Zstar = %g\n", + l, cstar->ReturnType(), allMass, allMetal, allMetal/MassUnits*vCell, allMetal/allMass, AVL0*pow(LengthUnits,3), cstar->ReturnMetallicity()); + if (allMass > cstar->ReturnFinalMass() && AVL0 > 0){ rho = (allMass - cstar->ReturnFinalMass())/MassUnits/AVL0*vCell; - z_rho = max(0.0,(allMetal-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity())/MassUnits)*vCell/AVL0); + z_rho = (allMetal-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/MassUnits*vCell/AVL0; printf("New densities rho=%g z_rho=%g\n",rho,z_rho); } From 580fdfdc1ef53561e51dd2632da3ab7f1ee228b9 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 3 Jan 2020 22:37:26 -0800 Subject: [PATCH 056/115] edited volume change criteria --- src/enzo/StarParticleAddFeedback.C | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index e2d7bf37e..1909b176e 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -298,15 +298,15 @@ int StarParticleAddFeedback(TopGridData *MetaData, } if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ float rescale = 1.0; - if (l == level){ - rescale = (old_vol/AllVol); + if (AVL0 > 0 && rescale == 1.0){ + rescale = (old_vol/AVL0); rho = EjectaDensity * rescale; z_rho = EjectaMetalDensity * rescale; } if (l > level) { - rho = EjectaDensity*pow(0.578703704,1);//*AllVol/AVL0 ; - z_rho = EjectaMetalDensity*pow(0.578703704,1);//*AllVol/AVL0; + rho = EjectaDensity*rescale*0.578703704;//*AllVol/AVL0 ; + z_rho = EjectaMetalDensity*rescale*0.578703704;//*AllVol/AVL0; } if (rescale < 1.0) fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", From 77c09231f11789b844d4af3f84bed46f54796064 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sun, 5 Jan 2020 08:51:51 -0800 Subject: [PATCH 057/115] changes to make star formation conservative --- src/enzo/Grid.h | 4 +- src/enzo/Grid_AddFeedbackSphere.C | 52 ++++++++------ ...Grid_StarParticleCalculateFeedbackVolume.C | 7 +- src/enzo/Star.h | 1 + src/enzo/StarParticleAddFeedback.C | 72 ++++++++++++------- 5 files changed, 85 insertions(+), 51 deletions(-) diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index 9bf3582bf..2177000fe 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2819,13 +2819,13 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radius, float DensityUnits, float LengthUnits, float VelocityUnits, float TemperatureUnits, float TimeUnits, int &nCells, float &depositedMass, - float &depositedMetal, FLOAT &depositedVolume); + float &depositedMetal, float &depositedMetal2, FLOAT &depositedVolume); int AddFeedbackSphere(Star *cstar, int level, float radius, float DensityUnits, float LengthUnits, float VelocityUnits, float TemperatureUnits, float TimeUnits, double EjectaDensity, double EjectaMetalDensity, double EjectaThermalEnergy, - double Q_HI, double sigma_HI, float deltaE, int &CellsModified); + double Q_HI, double sigma_HI, float deltaE, int &CellsModified, float MetalFraction); int SubtractAccretedMassFromSphere(Star *cstar, int level, float radius, float DensityUnits, float LengthUnits, float VelocityUnits, diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 4466dfe33..5fa75ef19 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -51,7 +51,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU float LengthUnits, float VelocityUnits, float TemperatureUnits, float TimeUnits, double EjectaDensity, double EjectaMetalDensity, double EjectaThermalEnergy, - double Q_HI, double sigma_HI, float deltaE, int &CellsModified) + double Q_HI, double sigma_HI, float deltaE, int &CellsModified, float MetalFraction) { const float WhalenMaxVelocity = 35; // km/s @@ -1013,32 +1013,44 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU /* factor is initialized to zero and never set--should we be setting the metals to zero? Why is standard metal_density field never touched?*/ - z0 += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) - *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; - if (SNColourNum > 0) - BaryonField[SNColourNum][index] = EjectaMetalDensity;//factor; - zNew += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) - *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; - if (Metal2Num > 0) - BaryonField[Metal2Num][index] *= factor; - - CellsModified++; + // only do this for P2 star formation; p3 may artificially remove metals from neighboring regions + if (cstar->ReturnType() == PopII){ + z0 += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) + *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; + if (SNColourNum > 0){ + BaryonField[SNColourNum][index] = EjectaMetalDensity*MetalFraction;//factor; + } + if (MetalNum > 0) + BaryonField[MetalNum][index] = EjectaMetalDensity*(1-MetalFraction); + zNew += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) + *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; + if (Metal2Num > 0) + BaryonField[Metal2Num][index] *= factor; + + CellsModified++; + } } // END if inside radius } // END i-direction } // END j-direction } // END k-direction - // now have total metal erased from grid and density prior to formation; reset metallicity of star to conserve metals - if (EjectaMetalDensity > 0 && cstar->ReturnType() == 7) - for (i = 0; i < NumberOfParticles; i++){ - if (ParticleNumber[i] == cstar->ReturnID()){ - printf("Removed %g Msun metal and put %g to star\n", z0-zNew, EjectaMetalDensity/EjectaDensity*cstar->ReturnFinalMass()); - printf("Resetting %d metallicity to %g from %g with mass change %g\n", - cstar->ReturnID(), EjectaMetalDensity/EjectaDensity, cstar->ReturnMetallicity(), (m0-mNew)*DensityUnits*pow(LengthUnits,3)/SolarMass); - ParticleAttribute[2][i] = EjectaMetalDensity/EjectaDensity; // all the metal must've gone into the star; but only m0-mNew mass went in - } + /* if the metal removed from the grid doesn't jive with the star metal, reset it */ + if (EjectaMetalDensity > 0 && cstar->ReturnType() == PopII) + { + printf("[ %d -- %d ] Removed %g(%g) Msun metal with mass change %g Msunn\n", + level, cstar->ReturnType(), (z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass, + (m0-mNew)*DensityUnits*pow(LengthUnits,3)/SolarMass); + if (cstar->ReturnMetallicity() < (z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass/cstar->ReturnFinalMass()) + { + printf("Removed metal mismatch with star; setting star metallicity to %g from %g with mass %g--expected %g Msun\n", + (z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass/cstar->ReturnFinalMass(), + cstar->ReturnMetallicity(), + cstar->ReturnFinalMass()*cstar->ReturnMetallicity(), + cstar->ReturnFinalMass()); + cstar->SetMetallicity((z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass/cstar->ReturnFinalMass()); } + } } // END star birth /*********************************************************************** diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index 16030f9d5..ea7ee8447 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -20,7 +20,7 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radius, float DensityUnits, float LengthUnits, float VelocityUnits, float TemperatureUnits, float TimeUnits, int &nCells, float &depositedMass, - float &depositedMetal, FLOAT &depositedVolume) + float &depositedMetal, float &depositedMetal2, FLOAT &depositedVolume) { @@ -124,7 +124,10 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi depositedVolume += CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; nCells ++; depositedMass += BaryonField[DensNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; - depositedMetal += BaryonField[SNColourNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + if (SNColourNum > 0) + depositedMetal += BaryonField[SNColourNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + if (cstar->ReturnType() != PopIII && MetalNum >0) + depositedMetal2 += BaryonField[MetalNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; } // END if inside radius } // END i-direction } // END j-direction diff --git a/src/enzo/Star.h b/src/enzo/Star.h index 985d28d93..86ea61617 100644 --- a/src/enzo/Star.h +++ b/src/enzo/Star.h @@ -70,6 +70,7 @@ class Star // Routines star_type ReturnType(void) { return type; }; + void SetMetallicity(float metals) {Metallicity = metals;}; float ReturnMetallicity(void) {return Metallicity;}; int ReturnID(void) { return Identifier; }; double ReturnMass(void) { return Mass; }; diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 1909b176e..85ce9f5f5 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -226,6 +226,9 @@ int StarParticleAddFeedback(TopGridData *MetaData, float rho = EjectaDensity; float z_rho = EjectaMetalDensity; FLOAT AVL0 = 0.0; + float metalAccreted = 0.0; + float metalFrac; + float rescale = 1.0; for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ // initially l=level; lReturnFeedbackFlag()==SUPERNOVA && (cstar->ReturnType() == PopIII); int nCells = 0; FLOAT vol_modified = 0.0; float mass_dep = 0.0; - float metal_dep = 0.0; - if (cstar->ReturnFeedbackFlag() == SUPERNOVA || cstar->ReturnFeedbackFlag() == FORMATION) + float metal_dep = 0.0; // track P3 metal + float metal2_dep = 0.0; // track p2 metal + if (rescaleSN || cstar->ReturnFeedbackFlag() == FORMATION) for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) Temp->GridData->StarParticleCalculateFeedbackVolume( cstar, l, influenceRadius, DensityUnits, LengthUnits, VelocityUnits, TemperatureUnits, TimeUnits, nCells, - mass_dep, metal_dep, vol_modified); + mass_dep, metal_dep, metal2_dep, vol_modified); FLOAT AllVol = 0; FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius * 4.0 * pi / 3.0; - if (cstar->ReturnFeedbackFlag() == SUPERNOVA || cstar->ReturnFeedbackFlag() == FORMATION){ + + // sum volume across all processes for this level + // (sphere can be across procs as well!) -AIW + + if (rescaleSN || cstar->ReturnFeedbackFlag() == FORMATION){ MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); if (AVL0 == 0) AVL0 = AllVol; float allMass = 0; - float allMetal = 0; + float allMetal = 0; // track p3 metal + float allMetal2 = 0; // track p2 metal FLOAT vCell = LevelArray[l]->GridData->GetVCell(); FLOAT MassUnits = DensityUnits*pow(LengthUnits,3)/SolarMass; //code -> Msun // if forming mass, need to check that mass accreting from grid is consistent if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity && AVL0 > 0){ // set all this on the first valid pass + /* sum quantities across tasks */ MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); // Set the densities to constant value for the interior of Stromgren sphere allMass *= MassUnits; allMetal *= MassUnits; - printf("[%d--%d] AllMass = %g AllZ = %g z_rho = %g New FZ = %g volume = %g Zstar = %g\n", - l, cstar->ReturnType(), allMass, allMetal, allMetal/MassUnits*vCell, allMetal/allMass, AVL0*pow(LengthUnits,3), cstar->ReturnMetallicity()); + allMetal2 *= MassUnits; + metalFrac = allMetal/(allMetal+allMetal2); //fraction of p3/all metals + printf("[L = %d : type = %d] AllMass = %g AllZ = %g z_rho = %g New FZ = %g volume = %g Zstar = %g\n", + l, cstar->ReturnType(), allMass, allMetal, allMetal/MassUnits*vCell, + (allMetal+allMetal2)/allMass, AVL0*pow(LengthUnits,3), cstar->ReturnMetallicity()); if (allMass > cstar->ReturnFinalMass() && AVL0 > 0){ rho = (allMass - cstar->ReturnFinalMass())/MassUnits/AVL0*vCell; - z_rho = (allMetal-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/MassUnits*vCell/AVL0; - printf("New densities rho=%g z_rho=%g\n",rho,z_rho); - } + z_rho = (allMetal+allMetal2-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/MassUnits*vCell/AVL0; + printf("New densities rho=%g z_rho=%g M = %g Mz = %g\n",rho,z_rho, + rho*MassUnits/SolarMass*pow(LengthUnits,3)*vCell, + z_rho*MassUnits/SolarMass*pow(LengthUnits,3)*vCell); + cstar->SetMetallicity((allMetal+allMetal2)/allMass); + } + // if (allMass > cstar->ReturnFinalMass() && level < l){ + // rho *= 0.578703704; + // z_rho *= 0.578703704; + // } } - // sum volume across all processes for this level - // (sphere can be across procs as well!) -AIW - // NB: Levels > level may not deposit the whole sphere volume. leave those alone; Leave MBH deposition alone - // because I dont know it. -AIW - if (vol_modified > 0.0) + if (vol_modified > 0.0 && rescaleSN && debug) printf("level %d Prior Deposition Masses M = %g Z = %g AllVol = %g rankVol = %g ratio = %f r_mass = %g r_z = %g\n ", l, AllVol*EjectaDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, AllVol*EjectaMetalDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, @@ -296,22 +314,22 @@ int StarParticleAddFeedback(TopGridData *MetaData, ); } - if (cstar->ReturnFeedbackFlag() == SUPERNOVA){ - float rescale = 1.0; - if (AVL0 > 0 && rescale == 1.0){ + if (rescaleSN){ + if (l==level || AVL0 > 0){ rescale = (old_vol/AVL0); rho = EjectaDensity * rescale; z_rho = EjectaMetalDensity * rescale; } + // its a damn dirty hack, but it works. if (l > level) { - rho = EjectaDensity*rescale*0.578703704;//*AllVol/AVL0 ; - z_rho = EjectaMetalDensity*rescale*0.578703704;//*AllVol/AVL0; + rho = EjectaDensity*0.578703704;//*AllVol/AVL0 ; + z_rho = EjectaMetalDensity*0.578703704;//*AllVol/AVL0; } - if (rescale < 1.0) - fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", - cstar->ReturnFeedbackFlag(), l, AllVol*pow(LengthUnits,3), - old_vol*pow(LengthUnits,3), rho * DensityUnits, EjectaDensity*DensityUnits, + if (rescale < 1.0 && AllVol > 0) + fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", + cstar->ReturnFeedbackFlag(), l, AVL0*pow(LengthUnits,3), + old_vol*pow(LengthUnits,3), AllVol/AVL0, rho * DensityUnits, EjectaDensity*DensityUnits, z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); @@ -325,7 +343,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, DensityUnits, LengthUnits, VelocityUnits, TemperatureUnits, TimeUnits, rho, z_rho, EjectaThermalEnergy, Q_HI, sigma, deltaE, - CellsModified); + CellsModified, metalFrac); } } // ENDIF From d4e2c1a6871346686f7035e9197c1727e2624706 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 6 Jan 2020 14:27:54 -0800 Subject: [PATCH 058/115] edited upper limit of HN mass to be consistent with SN bins; over limit causes failures in search_lower_bound. --- src/enzo/Star_CalculateFeedbackParameters.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enzo/Star_CalculateFeedbackParameters.C b/src/enzo/Star_CalculateFeedbackParameters.C index 9813243b8..7e4a679d3 100644 --- a/src/enzo/Star_CalculateFeedbackParameters.C +++ b/src/enzo/Star_CalculateFeedbackParameters.C @@ -46,7 +46,7 @@ void Star::CalculateFeedbackParameters(float &Radius, const double h=0.70; - const float TypeIILowerMass = 11, TypeIIUpperMass = 40.1; + const float TypeIILowerMass = 11, TypeIIUpperMass = 40.01; // 40.1->40.01 to be consistent with SNExplosionMass bins -AIW const float PISNLowerMass = 140, PISNUpperMass = 260; // From Nomoto et al. (2006) From a39b3544ec452876399fcad14bace80afabf0740 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Tue, 7 Jan 2020 16:16:19 -0800 Subject: [PATCH 059/115] added a projection after adding feedback --- src/enzo/Grid_AddFeedbackSphere.C | 2 +- .../Grid_StarParticleCalculateFeedbackVolume.C | 2 +- src/enzo/StarParticleAddFeedback.C | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 5fa75ef19..afb4379e5 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -304,7 +304,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU BaryonField[HDINum][index] *= increase; } - if (MetallicityField == TRUE){ + if (MetallicityField == TRUE && radius2 <= MetalRadius2){ BaryonField[MetalNum][index] += factor*EjectaMetalDensity; depositedMetal += factor*EjectaMetalDensity*pow(CellWidth[0][0],3); } diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index ea7ee8447..f6427112a 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -92,7 +92,7 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi ************************************************************************/ float outerRadius2=radius*radius; - int GZ = NumberOfGhostZones; + int GZ =0;//NumberOfGhostZones; for (k = GZ; k < GridDimension[2]; k++) { diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 85ce9f5f5..706d28c43 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -323,8 +323,8 @@ int StarParticleAddFeedback(TopGridData *MetaData, // its a damn dirty hack, but it works. if (l > level) { - rho = EjectaDensity*0.578703704;//*AllVol/AVL0 ; - z_rho = EjectaMetalDensity*0.578703704;//*AllVol/AVL0; + rho = EjectaDensity*rescale;//*AllVol/AVL0 ; + z_rho = EjectaMetalDensity*rescale;//*AllVol/AVL0; } if (rescale < 1.0 && AllVol > 0) fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", @@ -401,6 +401,16 @@ int StarParticleAddFeedback(TopGridData *MetaData, } // ENDFOR stars + for (level = MaximumRefinementLevel; level > 0; level--){ + Temp = LevelArray[level]; + while (Temp != NULL) { + if (Temp->GridData->ProjectSolutionToParentGrid(*Temp->GridHierarchyEntry->ParentGrid->GridData) == FAIL){ + fprintf(stderr, "Error in grid->ProjectSolutionToParentGrid\n"); + return FAIL; + } + Temp = Temp->NextGridThisLevel; + } + } LCAPERF_STOP("StarParticleAddFeedback"); return SUCCESS; } From 61bec1c0cb7f50a9e3d6bb9910e9eb80c7230c89 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Wed, 8 Jan 2020 08:31:04 -0800 Subject: [PATCH 060/115] updates and debugs --- src/enzo/Grid_AddFeedbackSphere.C | 4 +++- src/enzo/StarParticleAddFeedback.C | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index afb4379e5..5e6f36943 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -314,7 +314,9 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END i-direction } // END j-direction } // END k-direction - + fprintf(stdout, "[%d] <%d> deposited M=%g M_z=%g v=%g dx = %f pc\n", level, + cstar->ReturnID(), depositedMass*MassUnits/SolarMass, depositedMetal*MassUnits/SolarMass, + depositedVolume*pow(LengthUnits,3), CellWidth[0][0]*LengthUnits/pc_cm); // } } // END Supernova diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 706d28c43..c1c1d858c 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -288,7 +288,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, (allMetal+allMetal2)/allMass, AVL0*pow(LengthUnits,3), cstar->ReturnMetallicity()); if (allMass > cstar->ReturnFinalMass() && AVL0 > 0){ rho = (allMass - cstar->ReturnFinalMass())/MassUnits/AVL0*vCell; - z_rho = (allMetal+allMetal2-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/MassUnits*vCell/AVL0; + z_rho = max((allMetal+allMetal2-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/MassUnits*vCell/AVL0, 1e-20*rho); printf("New densities rho=%g z_rho=%g M = %g Mz = %g\n",rho,z_rho, rho*MassUnits/SolarMass*pow(LengthUnits,3)*vCell, z_rho*MassUnits/SolarMass*pow(LengthUnits,3)*vCell); @@ -313,7 +313,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, vol_modified*EjectaMetalDensity*pow(LengthUnits,3)*DensityUnits/SolarMass ); - } + }// endif rescale or formation if (rescaleSN){ if (l==level || AVL0 > 0){ rescale = (old_vol/AVL0); From 8d3fa5f00bc0e0873b561863cce16963661ad504 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Wed, 8 Jan 2020 15:03:42 -0800 Subject: [PATCH 061/115] Debugging, set finding sphere to 1.4x radius since many feedback use > 1.0*radius --- src/enzo/Grid_AddFeedbackSphere.C | 20 +++++++------ ...Grid_StarParticleCalculateFeedbackVolume.C | 4 +-- src/enzo/StarParticleAddFeedback.C | 29 ++++++++++++------- src/enzo/Star_SphereContained.C | 2 +- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 5e6f36943..d3ff592e5 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -133,7 +133,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU // 1988 or Tenorio-Tagle 1996). //const float MetalRadius = 0.75; - const float MetalRadius = 1.0/1.2; + const float MetalRadius = 1.0; float ionizedFraction = 0.999; // Assume supernova is ionized float maxGE, MetalRadius2, PrimordialDensity, metallicity, fhz, fhez; float outerRadius2, delta_fz; @@ -174,10 +174,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU EjectaMetalDensity *= pow(MetalRadius, -3.0); PrimordialDensity = EjectaDensity - EjectaMetalDensity; MetalRadius2 = radius * radius * MetalRadius * MetalRadius; - outerRadius2 = radius * radius; + outerRadius2 = radius * radius*1.2*1.2; - /* Remove mass from the star that will now be added to grids. + /* Remove mass from the star that will now be added to gridMetalRadiuss. Also, because EjectaDensity will be added with zero net momentum, increase the particle's velocity accordingly. - Ji-hoon Kim, Sep.2009 */ @@ -304,9 +304,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU BaryonField[HDINum][index] *= increase; } - if (MetallicityField == TRUE && radius2 <= MetalRadius2){ - BaryonField[MetalNum][index] += factor*EjectaMetalDensity; - depositedMetal += factor*EjectaMetalDensity*pow(CellWidth[0][0],3); + if (MetallicityField == TRUE){ + //factor = 0.578703704; + BaryonField[MetalNum][index] += EjectaMetalDensity; + depositedMetal += EjectaMetalDensity*pow(CellWidth[0][0],3); } CellsModified++; @@ -314,9 +315,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END i-direction } // END j-direction } // END k-direction - fprintf(stdout, "[%d] <%d> deposited M=%g M_z=%g v=%g dx = %f pc\n", level, - cstar->ReturnID(), depositedMass*MassUnits/SolarMass, depositedMetal*MassUnits/SolarMass, - depositedVolume*pow(LengthUnits,3), CellWidth[0][0]*LengthUnits/pc_cm); + if (cstar->ReturnType() == PopIII) + fprintf(stdout, "[%d] <%d> deposited M=%g M_z=%g v=%g dx = %f pc\n", level, + cstar->ReturnID(), depositedMass*MassUnits/SolarMass, depositedMetal*MassUnits/SolarMass, + depositedVolume*pow(LengthUnits,3), CellWidth[0][0]*LengthUnits/pc_cm); // } } // END Supernova diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index f6427112a..a8542cc46 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -91,8 +91,8 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi will be put into. ************************************************************************/ - float outerRadius2=radius*radius; - int GZ =0;//NumberOfGhostZones; + float outerRadius2=radius*radius*1.2*1.2; + int GZ =NumberOfGhostZones; for (k = GZ; k < GridDimension[2]; k++) { diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index c1c1d858c..abd66c434 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -229,6 +229,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, float metalAccreted = 0.0; float metalFrac; float rescale = 1.0; + FLOAT MassUnits = DensityUnits*pow(LengthUnits,3)/SolarMass; //code -> Msun if mult. by cell volume for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ // initially l=level; lReturnFeedbackFlag()==SUPERNOVA && (cstar->ReturnType() == PopIII); + // Things we'll sum across grids int nCells = 0; FLOAT vol_modified = 0.0; float mass_dep = 0.0; float metal_dep = 0.0; // track P3 metal float metal2_dep = 0.0; // track p2 metal + + // sum volume across grids in relevant cases + if (rescaleSN || cstar->ReturnFeedbackFlag() == FORMATION) for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) - Temp->GridData->StarParticleCalculateFeedbackVolume( + nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( cstar, l, influenceRadius, DensityUnits, LengthUnits, VelocityUnits, TemperatureUnits, TimeUnits, nCells, @@ -264,15 +270,20 @@ int StarParticleAddFeedback(TopGridData *MetaData, if (rescaleSN || cstar->ReturnFeedbackFlag() == FORMATION){ MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + // set the volume of the lowest level to deposit into + // WHY IS THIS NOT THE HIGHEST VOLUME?? if (AVL0 == 0) AVL0 = AllVol; float allMass = 0; float allMetal = 0; // track p3 metal float allMetal2 = 0; // track p2 metal FLOAT vCell = LevelArray[l]->GridData->GetVCell(); - FLOAT MassUnits = DensityUnits*pow(LengthUnits,3)/SolarMass; //code -> Msun // if forming mass, need to check that mass accreting from grid is consistent - if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity && AVL0 > 0){ // set all this on the first valid pass + if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity && AVL0 > 0) + { + // set all this on the first valid pass + /* sum quantities across tasks */ MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); @@ -315,17 +326,13 @@ int StarParticleAddFeedback(TopGridData *MetaData, }// endif rescale or formation if (rescaleSN){ - if (l==level || AVL0 > 0){ - rescale = (old_vol/AVL0); + if (AVL0 > 0){ + // AVL0 set to the volume with 1.2*radius + rescale = old_vol/AVL0; rho = EjectaDensity * rescale; z_rho = EjectaMetalDensity * rescale; } - // its a damn dirty hack, but it works. - if (l > level) - { - rho = EjectaDensity*rescale;//*AllVol/AVL0 ; - z_rho = EjectaMetalDensity*rescale;//*AllVol/AVL0; - } + if (rescale < 1.0 && AllVol > 0) fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", cstar->ReturnFeedbackFlag(), l, AVL0*pow(LengthUnits,3), diff --git a/src/enzo/Star_SphereContained.C b/src/enzo/Star_SphereContained.C index 8318890c3..79b13f1eb 100644 --- a/src/enzo/Star_SphereContained.C +++ b/src/enzo/Star_SphereContained.C @@ -56,7 +56,7 @@ int Star::SphereContained(LevelHierarchyEntry *LevelArray[], int level, // If the bit is true, forward. If not, reverse. direction = (i >> dim & 1) ? 1 : -1; - corners[dim][i] = pos[dim] + direction * Radius; + corners[dim][i] = pos[dim] + direction * 1.42* Radius; } cornerDone[i] = 0; } From 0b9806f8ac0820a4ac730023ddffa0ae35e5890f Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Wed, 8 Jan 2020 15:03:55 -0800 Subject: [PATCH 062/115] missed one --- src/enzo/StarParticleAddFeedback.C | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index abd66c434..e684846c2 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -306,10 +306,6 @@ int StarParticleAddFeedback(TopGridData *MetaData, cstar->SetMetallicity((allMetal+allMetal2)/allMass); } - // if (allMass > cstar->ReturnFinalMass() && level < l){ - // rho *= 0.578703704; - // z_rho *= 0.578703704; - // } } From 635434e5b56e211f86cf213e15e2e11f48678211 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 9 Jan 2020 07:49:56 -0800 Subject: [PATCH 063/115] debugging deposition; error is <= 5.2% on laptop in nested simulation after 13 SNe and their evolution --- src/enzo/Grid_AddFeedbackSphere.C | 4 ++-- src/enzo/Grid_StarParticleCalculateFeedbackVolume.C | 6 +++++- src/enzo/StarParticleAddFeedback.C | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index d3ff592e5..006177798 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -974,7 +974,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU delx = min(delx, DomainWidth[0] - delx); radius2 = delx * delx + dely * dely + delz * delz; - if (radius2 <= radius * radius) + if (radius2 <= radius * radius * 1.2 * 1.2) // use 1.2 radius like feedback routine { radius2 = max(radius2, 0.0625 * CellWidth[0][i] * CellWidth[0][i]); // (0.25*dx)^2 @@ -1052,7 +1052,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU cstar->ReturnMetallicity(), cstar->ReturnFinalMass()*cstar->ReturnMetallicity(), cstar->ReturnFinalMass()); - cstar->SetMetallicity((z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass/cstar->ReturnFinalMass()); + // cstar->SetMetallicity((z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass/cstar->ReturnFinalMass()); } } } // END star birth diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index a8542cc46..2864144e0 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -91,7 +91,11 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi will be put into. ************************************************************************/ - float outerRadius2=radius*radius*1.2*1.2; + float outerRadius2 = 0.0; + if (cstar->ReturnFeedbackFlag() == FORMATION) + outerRadius2 = radius*radius; + else if (cstar->ReturnFeedbackFlag() == SUPERNOVA) + outerRadius2 =radius*radius*1.2*1.2; int GZ =NumberOfGhostZones; for (k = GZ; k < GridDimension[2]; k++) { diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index e684846c2..5fc5be0aa 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -298,12 +298,13 @@ int StarParticleAddFeedback(TopGridData *MetaData, l, cstar->ReturnType(), allMass, allMetal, allMetal/MassUnits*vCell, (allMetal+allMetal2)/allMass, AVL0*pow(LengthUnits,3), cstar->ReturnMetallicity()); if (allMass > cstar->ReturnFinalMass() && AVL0 > 0){ + // adjust by 1.2**3 since volume was taken from radius * 1.2 rho = (allMass - cstar->ReturnFinalMass())/MassUnits/AVL0*vCell; z_rho = max((allMetal+allMetal2-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/MassUnits*vCell/AVL0, 1e-20*rho); printf("New densities rho=%g z_rho=%g M = %g Mz = %g\n",rho,z_rho, rho*MassUnits/SolarMass*pow(LengthUnits,3)*vCell, z_rho*MassUnits/SolarMass*pow(LengthUnits,3)*vCell); - cstar->SetMetallicity((allMetal+allMetal2)/allMass); + cstar->SetMetallicity((allMetal+allMetal2)/allMass); } } From 7c1bdafd773db645dea64aa3bd66ebe1d64712eb Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 9 Jan 2020 08:22:15 -0800 Subject: [PATCH 064/115] added less accurate but faster rescaling for PopII continuous supernova feedback --- src/enzo/StarParticleAddFeedback.C | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 5fc5be0aa..0c62f9f7d 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -282,7 +282,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, // if forming mass, need to check that mass accreting from grid is consistent if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity && AVL0 > 0) { - // set all this on the first valid pass + // set all this on the first pass that makes sense. /* sum quantities across tasks */ MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); @@ -309,17 +309,16 @@ int StarParticleAddFeedback(TopGridData *MetaData, } } - - - if (vol_modified > 0.0 && rescaleSN && debug) - printf("level %d Prior Deposition Masses M = %g Z = %g AllVol = %g rankVol = %g ratio = %f r_mass = %g r_z = %g\n ", - l, AllVol*EjectaDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, - AllVol*EjectaMetalDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, - AllVol*pow(LengthUnits,3), vol_modified*pow(LengthUnits,3), - old_vol/AllVol, - vol_modified*EjectaDensity*pow(LengthUnits,3)*DensityUnits/SolarMass, - vol_modified*EjectaMetalDensity*pow(LengthUnits,3)*DensityUnits/SolarMass - ); + /* + Cant afford to do a blocking all-reduce for PopII feedback that happens on every time step + Its less accurate, but rescale the density according to the volume on the least-resolved level + */ + bool PopIIRescale = cstar->ReturnFeedbackFlag() == SUPERNOVA && cstar->ReturnType() == PopII; + if (PopIIRescale && AllVol > 0 && rho == EjectaDensity) // rescale on first valid pass + { + rho = EjectaDensity*old_vol/AllVol; + z_rho = EjectaMetalDensity*old_vol/AllVol; + } }// endif rescale or formation if (rescaleSN){ @@ -329,15 +328,14 @@ int StarParticleAddFeedback(TopGridData *MetaData, rho = EjectaDensity * rescale; z_rho = EjectaMetalDensity * rescale; } - - if (rescale < 1.0 && AllVol > 0) + } + if (rescale < 1.0 && AllVol > 0) fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", cstar->ReturnFeedbackFlag(), l, AVL0*pow(LengthUnits,3), old_vol*pow(LengthUnits,3), AllVol/AVL0, rho * DensityUnits, EjectaDensity*DensityUnits, z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); - } } /* do the real deposition */ From b2b546fb31c6e66830604c782b4778304a91ef68 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 9 Jan 2020 13:33:26 -0800 Subject: [PATCH 065/115] Hopefully, thats all she wrote --- src/enzo/Grid_AddFeedbackSphere.C | 18 ++----- ...Grid_StarParticleCalculateFeedbackVolume.C | 2 + src/enzo/StarParticleAddFeedback.C | 48 ++++++++++--------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 006177798..8794e5d95 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -1040,20 +1040,12 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END j-direction } // END k-direction /* if the metal removed from the grid doesn't jive with the star metal, reset it */ - if (EjectaMetalDensity > 0 && cstar->ReturnType() == PopII) + if (EjectaMetalDensity > 0) { - printf("[ %d -- %d ] Removed %g(%g) Msun metal with mass change %g Msunn\n", - level, cstar->ReturnType(), (z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass, - (m0-mNew)*DensityUnits*pow(LengthUnits,3)/SolarMass); - if (cstar->ReturnMetallicity() < (z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass/cstar->ReturnFinalMass()) - { - printf("Removed metal mismatch with star; setting star metallicity to %g from %g with mass %g--expected %g Msun\n", - (z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass/cstar->ReturnFinalMass(), - cstar->ReturnMetallicity(), - cstar->ReturnFinalMass()*cstar->ReturnMetallicity(), - cstar->ReturnFinalMass()); - // cstar->SetMetallicity((z0-zNew)*DensityUnits*pow(LengthUnits,3)/SolarMass/cstar->ReturnFinalMass()); - } + printf("[ %d -- %d ] Removed %g Msun metal with mass change %g Msunn\n", + level, cstar->ReturnType(), + (z0*DensityUnits*pow(LengthUnits,3)*CellsModified*GetVCell()/SolarMass-zNew*DensityUnits*pow(LengthUnits,3)*CellsModified*GetVCell()/SolarMass), + (m0-mNew)*DensityUnits*pow(LengthUnits,3)*GetVCell()/SolarMass); } } // END star birth diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index 2864144e0..7b2e1ec96 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -92,8 +92,10 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi ************************************************************************/ float outerRadius2 = 0.0; + /* Formation section in Grid_AddFeedbackSphere.C uses volume with r=1.0*radius */ if (cstar->ReturnFeedbackFlag() == FORMATION) outerRadius2 = radius*radius; + /* Feedback uses volume with r=1.2*radius */ else if (cstar->ReturnFeedbackFlag() == SUPERNOVA) outerRadius2 =radius*radius*1.2*1.2; int GZ =NumberOfGhostZones; diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 0c62f9f7d..e075ad80b 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -245,6 +245,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, // only rescale SN if theyre PopIII single supernova--rescaling PopII is too expensive since // it happens at every timestep. bool rescaleSN = cstar->ReturnFeedbackFlag()==SUPERNOVA && (cstar->ReturnType() == PopIII); + bool PopIIRescale = cstar->ReturnFeedbackFlag() == SUPERNOVA && cstar->ReturnType() == PopII; // Things we'll sum across grids int nCells = 0; FLOAT vol_modified = 0.0; @@ -254,13 +255,14 @@ int StarParticleAddFeedback(TopGridData *MetaData, // sum volume across grids in relevant cases - if (rescaleSN || cstar->ReturnFeedbackFlag() == FORMATION) + if (rescaleSN || PopIIRescale || cstar->ReturnFeedbackFlag() == FORMATION){ for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( cstar, l, influenceRadius, DensityUnits, LengthUnits, VelocityUnits, TemperatureUnits, TimeUnits, nCells, mass_dep, metal_dep, metal2_dep, vol_modified); + } FLOAT AllVol = 0; FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius * 4.0 * pi / 3.0; @@ -270,7 +272,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, if (rescaleSN || cstar->ReturnFeedbackFlag() == FORMATION){ MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - + } // set the volume of the lowest level to deposit into // WHY IS THIS NOT THE HIGHEST VOLUME?? if (AVL0 == 0) @@ -279,55 +281,55 @@ int StarParticleAddFeedback(TopGridData *MetaData, float allMetal = 0; // track p3 metal float allMetal2 = 0; // track p2 metal FLOAT vCell = LevelArray[l]->GridData->GetVCell(); + // if forming mass, need to check that mass accreting from grid is consistent + if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity && AVL0 > 0) { // set all this on the first pass that makes sense. - - /* sum quantities across tasks */ + + /* sum quantities across tasks */ + MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - // Set the densities to constant value for the interior of Stromgren sphere allMass *= MassUnits; allMetal *= MassUnits; allMetal2 *= MassUnits; metalFrac = allMetal/(allMetal+allMetal2); //fraction of p3/all metals - printf("[L = %d : type = %d] AllMass = %g AllZ = %g z_rho = %g New FZ = %g volume = %g Zstar = %g\n", - l, cstar->ReturnType(), allMass, allMetal, allMetal/MassUnits*vCell, - (allMetal+allMetal2)/allMass, AVL0*pow(LengthUnits,3), cstar->ReturnMetallicity()); + if (allMass > cstar->ReturnFinalMass() && AVL0 > 0){ - // adjust by 1.2**3 since volume was taken from radius * 1.2 - rho = (allMass - cstar->ReturnFinalMass())/MassUnits/AVL0*vCell; - z_rho = max((allMetal+allMetal2-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/MassUnits*vCell/AVL0, 1e-20*rho); + // Set the densities to constant value for the interior of Stromgren sphere + rho = (allMass - cstar->ReturnFinalMass())/MassUnits/AVL0; + z_rho = max((allMetal+allMetal2-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/AVL0/MassUnits, 1e-30*rho); printf("New densities rho=%g z_rho=%g M = %g Mz = %g\n",rho,z_rho, - rho*MassUnits/SolarMass*pow(LengthUnits,3)*vCell, - z_rho*MassUnits/SolarMass*pow(LengthUnits,3)*vCell); - cstar->SetMetallicity((allMetal+allMetal2)/allMass); + (allMass-rho*AVL0*MassUnits), + allMetal+allMetal2-z_rho*MassUnits*AVL0); + //cstar->SetMetallicity((allMetal+allMetal2)/allMass); } - } + } // end if formation /* Cant afford to do a blocking all-reduce for PopII feedback that happens on every time step Its less accurate, but rescale the density according to the volume on the least-resolved level */ - bool PopIIRescale = cstar->ReturnFeedbackFlag() == SUPERNOVA && cstar->ReturnType() == PopII; - if (PopIIRescale && AllVol > 0 && rho == EjectaDensity) // rescale on first valid pass + if (PopIIRescale && vol_modified > old_vol) // rescale on first valid pass { - rho = EjectaDensity*old_vol/AllVol; - z_rho = EjectaMetalDensity*old_vol/AllVol; + rho = min( rho, EjectaDensity*old_vol/vol_modified); + z_rho = min(z_rho, EjectaMetalDensity*old_vol/vol_modified); } - }// endif rescale or formation + //}// endif rescale or formation if (rescaleSN){ if (AVL0 > 0){ // AVL0 set to the volume with 1.2*radius rescale = old_vol/AVL0; rho = EjectaDensity * rescale; z_rho = EjectaMetalDensity * rescale; - } + } // set the volume of the lowest level to deposit into + // WHY IS THIS NOT THE HIGHEST VOLUME?? } if (rescale < 1.0 && AllVol > 0) fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", @@ -336,7 +338,9 @@ int StarParticleAddFeedback(TopGridData *MetaData, z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); - } + + } // endif supernova or formation + /* do the real deposition */ for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) From 5c0df62a40eb5527941326a2f5aaa2923aefa4dd Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 9 Jan 2020 15:16:09 -0800 Subject: [PATCH 066/115] limited prints to be less spammy --- src/enzo/Grid_AddFeedbackSphere.C | 2 +- src/enzo/StarParticleAddFeedback.C | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 8794e5d95..f9a43885b 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -1040,7 +1040,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // END j-direction } // END k-direction /* if the metal removed from the grid doesn't jive with the star metal, reset it */ - if (EjectaMetalDensity > 0) + if (EjectaMetalDensity > 0 && CellsModified > 0) { printf("[ %d -- %d ] Removed %g Msun metal with mass change %g Msunn\n", level, cstar->ReturnType(), diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index e075ad80b..10cf7e95a 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -299,7 +299,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, allMetal2 *= MassUnits; metalFrac = allMetal/(allMetal+allMetal2); //fraction of p3/all metals - if (allMass > cstar->ReturnFinalMass() && AVL0 > 0){ + if (allMass > cstar->ReturnFinalMass() && vol_modified > 0){ // Set the densities to constant value for the interior of Stromgren sphere rho = (allMass - cstar->ReturnFinalMass())/MassUnits/AVL0; z_rho = max((allMetal+allMetal2-(cstar->ReturnFinalMass()*cstar->ReturnMetallicity()))/AVL0/MassUnits, 1e-30*rho); From 188656174daf48896c3cc375bee87b26ff33391a Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 9 Jan 2020 22:05:15 -0800 Subject: [PATCH 067/115] Reorganized MPI_Allreduce; was causing comm miss, now does reduce for all SN feedback :( --- src/enzo/StarParticleAddFeedback.C | 39 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 10cf7e95a..75a51218b 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -231,7 +231,7 @@ int StarParticleAddFeedback(TopGridData *MetaData, float rescale = 1.0; FLOAT MassUnits = DensityUnits*pow(LengthUnits,3)/SolarMass; //code -> Msun if mult. by cell volume for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ // initially l=level; lReturnFeedbackFlag() == SUPERNOVA || cstar->ReturnFeedbackFlag() == FORMATION) { @@ -253,16 +253,15 @@ int StarParticleAddFeedback(TopGridData *MetaData, float metal_dep = 0.0; // track P3 metal float metal2_dep = 0.0; // track p2 metal - // sum volume across grids in relevant cases - - if (rescaleSN || PopIIRescale || cstar->ReturnFeedbackFlag() == FORMATION){ - for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) + // sum volume across + + for (Temp = LevelArray[l]; Temp; Temp = Temp->NextGridThisLevel) nCells += Temp->GridData->StarParticleCalculateFeedbackVolume( cstar, l, influenceRadius, DensityUnits, LengthUnits, VelocityUnits, TemperatureUnits, TimeUnits, nCells, mass_dep, metal_dep, metal2_dep, vol_modified); - } + FLOAT AllVol = 0; FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius * 4.0 * pi / 3.0; @@ -270,9 +269,8 @@ int StarParticleAddFeedback(TopGridData *MetaData, // sum volume across all processes for this level // (sphere can be across procs as well!) -AIW - if (rescaleSN || cstar->ReturnFeedbackFlag() == FORMATION){ - MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - } + MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // set the volume of the lowest level to deposit into // WHY IS THIS NOT THE HIGHEST VOLUME?? if (AVL0 == 0) @@ -283,17 +281,17 @@ int StarParticleAddFeedback(TopGridData *MetaData, FLOAT vCell = LevelArray[l]->GridData->GetVCell(); // if forming mass, need to check that mass accreting from grid is consistent - + // MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity && AVL0 > 0) { // set all this on the first pass that makes sense. /* sum quantities across tasks */ - MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + allMass *= MassUnits; allMetal *= MassUnits; allMetal2 *= MassUnits; @@ -315,10 +313,10 @@ int StarParticleAddFeedback(TopGridData *MetaData, Cant afford to do a blocking all-reduce for PopII feedback that happens on every time step Its less accurate, but rescale the density according to the volume on the least-resolved level */ - if (PopIIRescale && vol_modified > old_vol) // rescale on first valid pass + if (PopIIRescale && AVL0 > 0) // rescale on first valid pass { - rho = min( rho, EjectaDensity*old_vol/vol_modified); - z_rho = min(z_rho, EjectaMetalDensity*old_vol/vol_modified); + rho = min( rho, EjectaDensity*old_vol/AVL0); + z_rho = min(z_rho, EjectaMetalDensity*old_vol/AVL0); } //}// endif rescale or formation @@ -328,8 +326,11 @@ int StarParticleAddFeedback(TopGridData *MetaData, rescale = old_vol/AVL0; rho = EjectaDensity * rescale; z_rho = EjectaMetalDensity * rescale; - } // set the volume of the lowest level to deposit into - // WHY IS THIS NOT THE HIGHEST VOLUME?? + } + else{ + rho = 0.0; + z_rho = 0.0; + } } if (rescale < 1.0 && AllVol > 0) fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", From 2bd3ca2b3172a07ad60e1789caea5b4ae9f193dc Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 11 Jan 2020 10:56:22 -0800 Subject: [PATCH 068/115] Combined PopII/popIII behavior --- src/enzo/Grid_AddFeedbackSphere.C | 4 ++-- src/enzo/StarParticleAddFeedback.C | 16 ++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index f9a43885b..2352af8da 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -1023,10 +1023,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU z0 += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; if (SNColourNum > 0){ - BaryonField[SNColourNum][index] = EjectaMetalDensity*MetalFraction;//factor; + BaryonField[SNColourNum][index] = 1.0;EjectaMetalDensity*MetalFraction;//factor; } if (MetalNum > 0) - BaryonField[MetalNum][index] = EjectaMetalDensity*(1-MetalFraction); + BaryonField[MetalNum][index] = EjectaMetalDensity;//*(1-MetalFraction); zNew += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; if (Metal2Num > 0) diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 75a51218b..9da002d35 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -313,24 +313,16 @@ int StarParticleAddFeedback(TopGridData *MetaData, Cant afford to do a blocking all-reduce for PopII feedback that happens on every time step Its less accurate, but rescale the density according to the volume on the least-resolved level */ - if (PopIIRescale && AVL0 > 0) // rescale on first valid pass - { - rho = min( rho, EjectaDensity*old_vol/AVL0); - z_rho = min(z_rho, EjectaMetalDensity*old_vol/AVL0); - } //}// endif rescale or formation - if (rescaleSN){ + if (rescaleSN || PopIIRescale){ if (AVL0 > 0){ // AVL0 set to the volume with 1.2*radius rescale = old_vol/AVL0; - rho = EjectaDensity * rescale; - z_rho = EjectaMetalDensity * rescale; + rho = min(EjectaDensity * rescale, rho); + z_rho = min(EjectaMetalDensity * rescale, rho); } - else{ - rho = 0.0; - z_rho = 0.0; - } + } if (rescale < 1.0 && AllVol > 0) fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", From 2113d4bdf1857b40e27d5cb89be774bab1caabb3 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Sat, 11 Jan 2020 17:19:19 -0600 Subject: [PATCH 069/115] excluded ghost zones from volume calculation and make addfeedback consistent with that. --- ...Grid_StarParticleCalculateFeedbackVolume.C | 24 +++++++---- src/enzo/StarParticleAddFeedback.C | 43 +++++++++++-------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index 7b2e1ec96..bd7bd27d2 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -98,8 +98,12 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi /* Feedback uses volume with r=1.2*radius */ else if (cstar->ReturnFeedbackFlag() == SUPERNOVA) outerRadius2 =radius*radius*1.2*1.2; - int GZ =NumberOfGhostZones; - for (k = GZ; k < GridDimension[2]; k++) + + // only the volume to actually deposit--counting ghost zones would double-count + // the volume overlap between grids + int GZ = NumberOfGhostZones; + + for (k = GZ; k < GridDimension[2]-GZ; k++) { delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->ReturnPosition()[2]; @@ -107,7 +111,7 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi delz = fabs(delz); delz = min(delz, DomainWidth[2] - delz); - for (j = GZ; j < GridDimension[1]; j++) + for (j = GZ; j < GridDimension[1]-GZ; j++) { dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->ReturnPosition()[1]; @@ -116,7 +120,7 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi dely = min(dely, DomainWidth[1] - dely); index = (k * GridDimension[1] + j) * GridDimension[0]; - for (i = GZ; i < GridDimension[0]; i++, index++) + for (i = GZ; i < GridDimension[0]-GZ; i++, index++) { delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->ReturnPosition()[0]; @@ -129,11 +133,13 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi { depositedVolume += CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; nCells ++; - depositedMass += BaryonField[DensNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; - if (SNColourNum > 0) - depositedMetal += BaryonField[SNColourNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; - if (cstar->ReturnType() != PopIII && MetalNum >0) - depositedMetal2 += BaryonField[MetalNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + if (cstar->ReturnFeedbackFlag == FORMATION){ + depositedMass += BaryonField[DensNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + if (SNColourNum > 0) + depositedMetal += BaryonField[SNColourNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + if (cstar->ReturnType() != PopIII && MetalNum >0) + depositedMetal2 += BaryonField[MetalNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; + } } // END if inside radius } // END i-direction } // END j-direction diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 9da002d35..8eecc6a3f 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -242,11 +242,11 @@ int StarParticleAddFeedback(TopGridData *MetaData, --AIW */ - // only rescale SN if theyre PopIII single supernova--rescaling PopII is too expensive since - // it happens at every timestep. bool rescaleSN = cstar->ReturnFeedbackFlag()==SUPERNOVA && (cstar->ReturnType() == PopIII); bool PopIIRescale = cstar->ReturnFeedbackFlag() == SUPERNOVA && cstar->ReturnType() == PopII; + // Things we'll sum across grids + int nCells = 0; FLOAT vol_modified = 0.0; float mass_dep = 0.0; @@ -265,26 +265,29 @@ int StarParticleAddFeedback(TopGridData *MetaData, FLOAT AllVol = 0; FLOAT old_vol = influenceRadius * influenceRadius * influenceRadius * 4.0 * pi / 3.0; + float allMass = 0; // track full mass + float allMetal = 0; // track p3 metal + float allMetal2 = 0; // track p2 metal - // sum volume across all processes for this level + // sum volume and quantities across all processes for this level // (sphere can be across procs as well!) -AIW + // IMPROVEMENT: Use the chaining mesh with MPI_GatherV to only + // sum across adjacent grids MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - + MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // set the volume of the lowest level to deposit into // WHY IS THIS NOT THE HIGHEST VOLUME?? if (AVL0 == 0) AVL0 = AllVol; - float allMass = 0; - float allMetal = 0; // track p3 metal - float allMetal2 = 0; // track p2 metal FLOAT vCell = LevelArray[l]->GridData->GetVCell(); // if forming mass, need to check that mass accreting from grid is consistent // MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + if (cstar->ReturnFeedbackFlag() == FORMATION && rho == EjectaDensity && AVL0 > 0) { // set all this on the first pass that makes sense. @@ -310,17 +313,19 @@ int StarParticleAddFeedback(TopGridData *MetaData, } // end if formation /* - Cant afford to do a blocking all-reduce for PopII feedback that happens on every time step - Its less accurate, but rescale the density according to the volume on the least-resolved level - */ - - //}// endif rescale or formation + if dealing with supernova, rescale the densities according to the + actual deposition volume on the coarsest level. + */ if (rescaleSN || PopIIRescale){ if (AVL0 > 0){ // AVL0 set to the volume with 1.2*radius rescale = old_vol/AVL0; - rho = min(EjectaDensity * rescale, rho); - z_rho = min(EjectaMetalDensity * rescale, rho); + rho = EjectaDensity*rescale; + z_rho = EjectaMetalDensity * rescale; + if (AllVol > AVL0){ + rho *= AVL0/AllVol; + z_rho *= AVL0/AllVol; + } } } @@ -329,8 +334,8 @@ int StarParticleAddFeedback(TopGridData *MetaData, cstar->ReturnFeedbackFlag(), l, AVL0*pow(LengthUnits,3), old_vol*pow(LengthUnits,3), AllVol/AVL0, rho * DensityUnits, EjectaDensity*DensityUnits, z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, - rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass, - z_rho*AllVol*DensityUnits*pow(LengthUnits,3)/SolarMass); + rho*AVL0*DensityUnits*pow(LengthUnits,3)/SolarMass, + z_rho*AVL0*DensityUnits*pow(LengthUnits,3)/SolarMass); } // endif supernova or formation From eff2d11cb5dd397e859a0e459f953036fdc3b8b4 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Wed, 4 Mar 2020 21:13:33 -0600 Subject: [PATCH 070/115] adding uncommitted files --- src/enzo/EvolveLevel.C | 15 +++++++---- src/enzo/Grid_AddFeedbackSphere.C | 26 +++++++++++++------ ...Grid_StarParticleCalculateFeedbackVolume.C | 2 +- src/enzo/StarParticleAddFeedback.C | 22 ++++++++++------ src/enzo/Star_SphereContained.C | 4 ++- src/enzo/macros_and_parameters.h | 2 +- 6 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/enzo/EvolveLevel.C b/src/enzo/EvolveLevel.C index c918fcbdd..ce785d0b5 100644 --- a/src/enzo/EvolveLevel.C +++ b/src/enzo/EvolveLevel.C @@ -284,7 +284,8 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], /* Declarations */ int dbx = 0; - + float startEL = MPI_Wtime(); + float preCallEL; FLOAT When, GridTime; //float dtThisLevelSoFar = 0.0, dtThisLevel, dtGrid, dtActual, dtLimit; //float dtThisLevelSoFar = 0.0, dtThisLevel; @@ -347,7 +348,6 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], ENZO_FAIL("Error in SetBoundaryConditions (SlowSib)"); #endif } - Grids[0]->GridData->SetNumberOfColours(); /* Clear the boundary fluxes for all Grids (this will be accumulated over the subcycles below (i.e. during one current grid step) and used to by the @@ -800,7 +800,7 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], for (grid1 = 0; grid1 < NumberOfGrids; grid1++) Grids[grid1]->GridData->SetTimeStep(dtThisLevel[level]); } - + preCallEL = MPI_Wtime()-startEL; if (LevelArray[level+1] != NULL) { if (EvolveLevel(MetaData, LevelArray, level+1, dtThisLevel[level], Exterior #ifdef TRANSFER @@ -811,7 +811,7 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], ENZO_VFAIL("Error in EvolveLevel (%"ISYM").\n", level) } } - + startEL = MPI_Wtime(); #ifdef USE_LCAPERF // Update lcaperf "level" attribute @@ -961,6 +961,7 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], } } // end of loop over subcycles + EXTRA_OUTPUT_MACRO(6, "After Subcycle Loop") if (debug) @@ -1002,7 +1003,11 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], delete [] SiblingList; SiblingGridListStorage[level] = NULL; } - + int32_t mpi_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + if (mpi_rank == 0) + fprintf(stdout, "[ %d ] TIMING %"ISYM" grids %"GSYM" s post EL\n", + level, NumberOfGrids, MPI_Wtime()-startEL + preCallEL); return SUCCESS; } diff --git a/src/enzo/Grid_AddFeedbackSphere.C b/src/enzo/Grid_AddFeedbackSphere.C index 2352af8da..459792e9c 100644 --- a/src/enzo/Grid_AddFeedbackSphere.C +++ b/src/enzo/Grid_AddFeedbackSphere.C @@ -197,8 +197,12 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU } // ENDIF !Supernova maxGE = MAX_TEMPERATURE / (TemperatureUnits * (Gamma - 1.0) * 0.6); - int GZ = 0;//NumberOfGhostZones; - for (k = GZ; k < GridDimension[2]; k++) + int GZ = NumberOfGhostZones; + int maxI = GridDimension[0]-GZ; + int maxJ = GridDimension[1]-GZ; + int maxK = GridDimension[2]-GZ; + + for (k = 0; k < GridDimension[2]; k++) { delz = CellLeftEdge[2][k] + 0.5 * CellWidth[2][k] - cstar->pos[2]; @@ -206,7 +210,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU delz = fabs(delz); delz = min(delz, DomainWidth[2] - delz); - for (j = GZ; j < GridDimension[1]; j++) + for (j = 0; j < GridDimension[1]; j++) { dely = CellLeftEdge[1][j] + 0.5 * CellWidth[1][j] - cstar->pos[1]; @@ -215,7 +219,7 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU dely = min(dely, DomainWidth[1] - dely); index = (k * GridDimension[1] + j) * GridDimension[0]; - for (i = GZ; i < GridDimension[0]; i++, index++) + for (i = 0; i < GridDimension[0]; i++, index++) { delx = CellLeftEdge[0][i] + 0.5 * CellWidth[0][i] - cstar->pos[0]; @@ -241,7 +245,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU OldDensity = BaryonField[DensNum][index]; BaryonField[DensNum][index] += factor * EjectaDensity; - depositedMass += factor*EjectaDensity*pow(CellWidth[0][0],3); + if (i< maxI && i >=GZ + && j < maxJ && j > GZ + && k < maxK && k > GZ) + depositedMass += factor*EjectaDensity*pow(CellWidth[0][0],3); /* Add total energies of spheres together, then divide by density to get specific energy */ @@ -307,7 +314,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU if (MetallicityField == TRUE){ //factor = 0.578703704; BaryonField[MetalNum][index] += EjectaMetalDensity; - depositedMetal += EjectaMetalDensity*pow(CellWidth[0][0],3); + if (i< maxI && i >=GZ + && j < maxJ && j > GZ + && k < maxK && k > GZ) + depositedMetal += EjectaMetalDensity*pow(CellWidth[0][0],3); } CellsModified++; @@ -1023,10 +1033,10 @@ int grid::AddFeedbackSphere(Star *cstar, int level, float radius, float DensityU z0 += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; if (SNColourNum > 0){ - BaryonField[SNColourNum][index] = 1.0;EjectaMetalDensity*MetalFraction;//factor; + BaryonField[SNColourNum][index] = EjectaMetalDensity*MetalFraction;//factor; } if (MetalNum > 0) - BaryonField[MetalNum][index] = EjectaMetalDensity;//*(1-MetalFraction); + BaryonField[MetalNum][index] = EjectaMetalDensity*(1-MetalFraction); zNew += (BaryonField[SNColourNum][index]+BaryonField[MetalNum][index]) *CellWidth[0][0]*CellWidth[0][0]*CellWidth[0][0]; if (Metal2Num > 0) diff --git a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C index bd7bd27d2..219b36535 100644 --- a/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C +++ b/src/enzo/Grid_StarParticleCalculateFeedbackVolume.C @@ -133,7 +133,7 @@ int grid::StarParticleCalculateFeedbackVolume(Star *cstar, int level, float radi { depositedVolume += CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; nCells ++; - if (cstar->ReturnFeedbackFlag == FORMATION){ + if (cstar->ReturnFeedbackFlag() == FORMATION){ depositedMass += BaryonField[DensNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; if (SNColourNum > 0) depositedMetal += BaryonField[SNColourNum][index]*CellWidth[0][i]*CellWidth[1][j]*CellWidth[2][k]; diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 8eecc6a3f..232281d91 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -322,20 +322,23 @@ int StarParticleAddFeedback(TopGridData *MetaData, rescale = old_vol/AVL0; rho = EjectaDensity*rescale; z_rho = EjectaMetalDensity * rescale; + // Just in case the deeper level is somehow larger (unexpected) if (AllVol > AVL0){ - rho *= AVL0/AllVol; - z_rho *= AVL0/AllVol; + rho = EjectaDensity*old_vol/AllVol; + z_rho = EjectaMetalDensity*old_vol/AllVol; } } } - if (rescale < 1.0 && AllVol > 0) - fprintf(stdout, "\n\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g m_z = %g\n\n\n", - cstar->ReturnFeedbackFlag(), l, AVL0*pow(LengthUnits,3), + if (rescale < 1.0 && vol_modified > 0) + fprintf(stdout, "\n[ %d ]Rescaling volume on level %d v = %g/%g lratio = %f rho = %g/%g z_rho=%g/%g m_d = %g/%g m_z = %g/%g\n", + cstar->ReturnLevel(), l, AVL0*pow(LengthUnits,3), old_vol*pow(LengthUnits,3), AllVol/AVL0, rho * DensityUnits, EjectaDensity*DensityUnits, z_rho * DensityUnits, EjectaMetalDensity*DensityUnits, rho*AVL0*DensityUnits*pow(LengthUnits,3)/SolarMass, - z_rho*AVL0*DensityUnits*pow(LengthUnits,3)/SolarMass); + EjectaDensity*old_vol*DensityUnits*pow(LengthUnits, 3)/SolarMass, + z_rho*AVL0*DensityUnits*pow(LengthUnits,3)/SolarMass, + EjectaMetalDensity*old_vol*DensityUnits*pow(LengthUnits, 3)/SolarMass); } // endif supernova or formation @@ -405,8 +408,11 @@ int StarParticleAddFeedback(TopGridData *MetaData, } // ENDFOR stars - for (level = MaximumRefinementLevel; level > 0; level--){ - Temp = LevelArray[level]; + // For formation and feedback, project to parents from the bottom to make sure the information gets there as + // intended, ie., dont want hydro to evolve before solutions are made consistent across levels. + + for (l = MaximumRefinementLevel; l > 0; l--){ + Temp = LevelArray[l]; while (Temp != NULL) { if (Temp->GridData->ProjectSolutionToParentGrid(*Temp->GridHierarchyEntry->ParentGrid->GridData) == FAIL){ fprintf(stderr, "Error in grid->ProjectSolutionToParentGrid\n"); diff --git a/src/enzo/Star_SphereContained.C b/src/enzo/Star_SphereContained.C index 79b13f1eb..7e80e61f2 100644 --- a/src/enzo/Star_SphereContained.C +++ b/src/enzo/Star_SphereContained.C @@ -56,7 +56,9 @@ int Star::SphereContained(LevelHierarchyEntry *LevelArray[], int level, // If the bit is true, forward. If not, reverse. direction = (i >> dim & 1) ? 1 : -1; - corners[dim][i] = pos[dim] + direction * 1.42* Radius; + // feedback uses radius = 1.2*Radius; need to contain a sphere at least + // that size --AIW + corners[dim][i] = pos[dim] + direction * 1.21* Radius; } cornerDone[i] = 0; } diff --git a/src/enzo/macros_and_parameters.h b/src/enzo/macros_and_parameters.h index b9fcee0e5..b6a7f404c 100644 --- a/src/enzo/macros_and_parameters.h +++ b/src/enzo/macros_and_parameters.h @@ -70,7 +70,7 @@ #define MEMORY_POOL_SIZE __memory_pool_size -#define MAX_NUMBER_OF_OUTPUT_REDSHIFTS 500 +#define MAX_NUMBER_OF_OUTPUT_REDSHIFTS 2500 #define GRAVITY_BUFFER_SIZE 3 From b24b78c89521a4b1740f96980c0b2f7291f1f5f9 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Mon, 20 Apr 2020 15:14:01 -0500 Subject: [PATCH 071/115] updated default values of NumberOfTestStars and ClusterRadius --- src/enzo/TestStarParticleInitialize.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enzo/TestStarParticleInitialize.C b/src/enzo/TestStarParticleInitialize.C index 363372ceb..95289bd10 100644 --- a/src/enzo/TestStarParticleInitialize.C +++ b/src/enzo/TestStarParticleInitialize.C @@ -67,8 +67,8 @@ int TestStarParticleInitialize(FILE *fptr, FILE *Outfptr, HierarchyEntry &TopGri float TestStarParticleStarMass = 1000.0; int TestProblemUseMetallicityField = 1; float TestProblemInitialMetallicityFraction = 2e-3; // 0.1 Zsun - int NumberOfTestStars = 10; - float clusterRadius = 0.125; + int NumberOfTestStars = 1; + float clusterRadius = 0.0; From fb8b194687e33cf375fea83f3de35d493662b99f Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 23 Apr 2020 21:53:57 -0500 Subject: [PATCH 072/115] turned off various debugging flags for less printing --- src/enzo/Grid_MechStarsCreation.C | 2 +- src/enzo/Grid_MechStarsDepositFeedback.C | 2 +- src/enzo/Grid_MechStarsSeedSupernova.C | 2 +- src/enzo/MechStars_checkCreationCriteria.C | 2 +- src/enzo/MechStars_depositEmissivity.C | 2 ++ src/enzo/MechStars_determineWinds.C | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index cb4bf4262..42f764d43 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -49,7 +49,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, */ bool gridShouldFormStars=false, notEnoughMetals = true; - bool debug = true; + bool debug = false; //get field numbers diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index fa3c89d84..06ea8555b 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -49,7 +49,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, */ //printf("In Feedback deposition\n"); bool debug = false; - bool criticalDebug = true; + bool criticalDebug = false; float min_winds = 1.0; bool printout = debug && !winds; int index = ip + jp * GridDimension[0] + kp * GridDimension[0] * GridDimension[1]; diff --git a/src/enzo/Grid_MechStarsSeedSupernova.C b/src/enzo/Grid_MechStarsSeedSupernova.C index 6f1f74bf9..2e038e8af 100644 --- a/src/enzo/Grid_MechStarsSeedSupernova.C +++ b/src/enzo/Grid_MechStarsSeedSupernova.C @@ -37,7 +37,7 @@ unsigned_long_int mt_random(void); int StarParticlePopIII_IMFInitialize(void); int grid::MechStars_SeedSupernova(float* totalMetal, float* temperature, int* seedIndex){ - debug = true; + debug = false; /* Initialize the IMF lookup table if requested and not defined */ if (debug) fprintf(stdout, "setting IMF\n"); if (PopIIIInitialMassFunction) diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index 703b097e8..f793691bf 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -34,7 +34,7 @@ int checkCreationCriteria(float* Density, float* Metals, int continuingFormation, int* seedIndex) { float maxZ = 0.0; - bool debug = true; + bool debug = false; bool status = PASS; float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; diff --git a/src/enzo/MechStars_depositEmissivity.C b/src/enzo/MechStars_depositEmissivity.C index 7a6395d34..6ef71e7cc 100644 --- a/src/enzo/MechStars_depositEmissivity.C +++ b/src/enzo/MechStars_depositEmissivity.C @@ -1,4 +1,6 @@ /* + + *** CURRENTLY UNTESTED AND UNUSED *** Couples the mechanical stars to the radiation machinery in ENZO by filling in the emissivity0 field. Code must be compiled with "make emissivity-yes" and "make photon-yes". diff --git a/src/enzo/MechStars_determineWinds.C b/src/enzo/MechStars_determineWinds.C index 5f30a0693..ca68a520c 100644 --- a/src/enzo/MechStars_determineWinds.C +++ b/src/enzo/MechStars_determineWinds.C @@ -17,7 +17,7 @@ int determineWinds(float age, float* eWinds, float* mWinds, float* zWinds, float massMsun, float zZsun, float TimeUnits, float dtFixed){ - bool oldEnough = (age < 0.01)?(false):(true); + bool oldEnough = (age < 0.0001)?(false):(true); float windE = 0, windM = 0, windZ = 0.0; float wind_factor = 0.0; float e_factor = 0.0; From ad5cc809fc70db1f5f54581108c45a715c5ed2aa Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Thu, 23 Apr 2020 22:20:56 -0500 Subject: [PATCH 073/115] put yet another print behind debug -- these shouldnt print with simple -d execution option --- src/enzo/MechStars_checkCreationCriteria.C | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index f793691bf..2f8d6af04 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -151,7 +151,8 @@ int checkCreationCriteria(float* Density, float* Metals, float Psi = 0.6*Tau*(0.01+Metals[index]/Density[index]/0.02)/ log(1+0.6*Phi+0.01*Phi*Phi); *shieldedFraction = 1.0 - 3.0/(1.0+4.0*Psi); - fprintf(stdout, "FS parts: Tau = %"GSYM" Phi = %"GSYM" Psi = %"GSYM" FS = %"GSYM"\n", + if (debug) + fprintf(stdout, "FS parts: Tau = %"GSYM" Phi = %"GSYM" Psi = %"GSYM" FS = %"GSYM"\n", Tau, Phi, Psi, *shieldedFraction); if (*shieldedFraction < 0) status = FAIL; From 3b5b1b773139594fccf7944599fdf0115d20aae5 Mon Sep 17 00:00:00 2001 From: John Regan Date: Wed, 20 May 2020 11:29:22 +0100 Subject: [PATCH 074/115] adding tests for smartstar --- .../BBCollapseTestAccretingParticle.enzo | 103 +++++++++ .../sinkslices.py | 142 ++++++++++++ .../CollapseTestSmartStars.enzo | 111 ++++++++++ .../CollapseTestSmartStars/shuprofile.py | 205 ++++++++++++++++++ src/enzo/ActiveParticle_SmartStar.C | 62 +++--- src/enzo/ActiveParticle_SmartStar.h | 9 +- src/enzo/GrackleReadParameters.C | 3 +- src/enzo/Grid.h | 4 + src/enzo/Grid_AveragedVelocityAtCell.C | 57 +++++ src/enzo/Grid_CollapseTestInitializeGrid.C | 117 ++++++++-- src/enzo/phys_constants.h | 2 +- 11 files changed, 757 insertions(+), 58 deletions(-) create mode 100644 run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestAccretingParticle.enzo create mode 100644 run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py create mode 100644 run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo create mode 100644 run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py diff --git a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestAccretingParticle.enzo b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestAccretingParticle.enzo new file mode 100644 index 000000000..ea5f48079 --- /dev/null +++ b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestAccretingParticle.enzo @@ -0,0 +1,103 @@ +# +# AMR PROBLEM DEFINITION FILE: Non-cosmological Collapse test +# Description: a sphere collapses until becoming pressure supported. +# +# define problem +# +ProblemType = 27 // Collapse test +TopGridRank = 3 +TopGridDimensions = 32 32 32 +SelfGravity = 1 // gravity on +TopGridGravityBoundary = 0 // periodic +LeftFaceBoundaryCondition = 3 3 3 // periodic +RightFaceBoundaryCondition = 3 3 3 + +# +# problem parameters +# + +CollapseTestRefineAtStart = 1 // check refinement before running +CollapseTestNumberOfSpheres = 1 +CollapseTestUseParticles = 0 +CollapseTestInitialTemperature = 1e3 // temperature of the background gas +CollapseTestSpherePosition[0] = 0.5 0.5 0.5 +CollapseTestSphereVelocity[0] = 0.0 0.0 0.0 +CollapseTestSphereRadius[0] = 0.15625 +CollapseTestSphereCoreRadius[0] = 0.05 // only used with sphere type 5 +CollapseTestSphereDensity[0] = 1e2 //100 // sphere density, the background density is 1 +CollapseTestSphereTemperature[0] = 10 // put sphere in pressure equilibrium (rho * T is constant) +CollapseTestFracKeplerianRot[0] = 0.7 +CollapseTestSphereType[0] = 11 // constant density + // 1: uniform + // 2: r^-2 power-law + // 3: NFW + // 4: Gaussian + // 5: r^-2 power-law with a core + // 11: Burkert & Bodenheimer setup +#EOSType = +# no cosmology for this run +# +ComovingCoordinates = 0 // Expansion OFF +# +# units +# +DensityUnits = 3.82e-20 // 10^4 cm^-3 +LengthUnits = 3.2e17 #5e17 // 1 pc in cm +TimeUnits = 1.0e12 // 10^4 yrs +GravitationalConstant = 0.0320327594 // 4*pi*G_{cgs}*DensityUnits*TimeUnits^2 +# +# set I/O and stop/start parameters +# +StopTime = 1.7 +dtDataDump = 6e-2 +#CycleSkipDataDump = 1 +DataDumpDir = DD +DataDumpName = DD +OutputTemperature = 1 // Output temperature field. +# +# set hydro parameters +# +Gamma = 1.001 +PPMDiffusionParameter = 0 // diffusion off +DualEnergyFormalism = 1 // use total & internal energy +InterpolationMethod = 1 // SecondOrderA +CourantSafetyNumber = 0.3 +FluxCorrection = 1 +ConservativeInterpolation = 0 +RiemannSolver = 4 +HydroMethod = 0 // PPM +SmallRho = 1e-8 +SmallE = 1e-8 +# +# chemistry/cooling +# +MultiSpecies = 0 // chemistry off +RadiativeCooling = 0 // cooling off +Mu = 3.0 +# +# set grid refinement parameters +# +StaticHierarchy = 0 // dynamic hierarchy +MaximumRefinementLevel = 7 // use up to 7 levels +RefineBy = 2 // refinement factor +CellFlaggingMethod = 2 6 // refine on baryon mass and Jeans Length +MinimumEfficiency = 0.3 +#OutputFirstTimeAtLevel = 4 // output when level 4, 5, 6, etc reached (commented out for now) +#StopFirstTimeAtLevel = 10 // stop if/when level 10 reached +RefineByJeansLengthSafetyFactor = 16 // resolve Jeans length by 4 cells (used with CellFlaggingMethod 6) + + +# +# set some global parameters +# +GreensFunctionMaxNumber = 10 // # of greens function at any one time +PotentialIterations = 100 +ComputePotential = 0 +WritePotential = 0 +# +# active particle parameters +# +AppendActiveParticleType = SmartStar +ActiveParticleDensityThreshold = 1e+30 //Jeans density criteria + others +SmartStarFeedback = 0 + diff --git a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py new file mode 100644 index 000000000..4cd335952 --- /dev/null +++ b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py @@ -0,0 +1,142 @@ +import matplotlib +matplotlib.use('Agg') +import yt +import numpy as np +import sys +import glob +import matplotlib.pyplot as plt +from yt.units import G, kboltz, mh +from yt.units.yt_array import YTQuantity, YTArray +yt.enable_parallelism() +Mu = 3.0 +CENTRE = [0.5, 0.5, 0.5] +#CENTRE = [0.50231934, 0.49035645, 0.49865723] +AccretionRadius = 4 +BASE = "/home/regan/data/SourceCodes/Enzo-RT/enzo-3.0-rt/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/GravPotential/" +BASE = "./GravPotential/" +fns = glob.glob(BASE + "DD002?/DD????.hierarchy") +fns.sort() +#print fns +WIDTH = 8000 + +ActiveParticle = "SmartStar" + + +for f in fns: + ff = f + ds = yt.load(ff) + print("Stats = ", ds.index.get_smallest_dx().in_units("au")) + dx = ds.index.get_smallest_dx().in_units("au") + print("dx = ", dx.d) + dd = ds.all_data() + centre = CENTRE + print("Time = ", ds.current_time.in_units("kyr")) + #Now create a slice of the density field through the sink particle + #slc = yt.SlicePlot(ds, "x", "density", center='c', width=(0.1, 'pc')) + #slc.set_zlim('density', 1e-17, 1e-20) + #slc.save("Slice_x_%s.png" % (ds)) + NumAPs = 0 + flist = dir(ds.fields) + ap = flist[0] + try: + NumAPs = len(dd[ap, "level"]) + print("Number of %s active particles = %d" % (flist[0], NumAPs)) + except: + print("No active particles found") + + #v,c = ds.find_max("velocity_magnitude") + #print "Max Vel = ", v.in_units("km/s") + #print "Loc = ", c + #centre = CENTRE + #v,c = ds.find_min("velocity_magnitude") + #print "Min Vel = ", v.in_units("km/s") + #print "Loc = ", c + #prj = yt.ProjectionPlot(ds, "x", 'density', center='c',width=(WIDTH, 'au'), + # weight_field=None) + #prj.set_zlim('density', 1e-1, 1e2) + #prj.annotate_scale(corner='upper_right') + #prj.annotate_timestamp(corner='upper_left', redshift=False, draw_inset_box=True) + + #prj.save("Proj_x_%s.png" % (ds)) + + #slc = yt.SlicePlot(ds, "y", "density", center='c', width=(0.25, 'pc')) + #slc.set_zlim('density', 1e-17, 1e-20) + #slc.save("Slice_y_%s.png" % (ds)) + #prj = yt.ProjectionPlot(ds, "y", 'density', center='c',width=(WIDTH, 'au'), + # weight_field=None) + #prj.set_zlim('density', 1e-1, 1e2) + #prj.annotate_timestamp(corner='upper_left', redshift=False, draw_inset_box=True) + #prj.annotate_scale(corner='upper_right') + #prj.save("Proj_y_%s.png" % (ds)) + + + slc = yt.SlicePlot(ds, "z", "density", center=centre, width=(WIDTH, 'au')) + #slc.set_zlim('density', 1e-13, 1e-19) + if(NumAPs > 0): + for i in range(NumAPs): + pos = dd[ActiveParticle, "particle_position"][i] + slc.annotate_sphere(pos, radius=(dx.d*AccretionRadius, 'au'), + circle_args={'color':'black', 'fill':True}) + slc.save("Slice_z_%s.png" % (ds)) + + prj = yt.ProjectionPlot(ds, "z", 'number_density', center=centre, width=(WIDTH, 'au'), + weight_field='density') + #prj.set_zlim('density', 1e-1, 1e2) + prj.annotate_timestamp(corner='upper_left', redshift=False, draw_inset_box=True) + #prj.annotate_scale(corner='upper_right') + if(NumAPs > 0): + for i in range(NumAPs): + pos = dd[ActiveParticle, "particle_position"][i] + prj.annotate_sphere(pos, radius=(dx.d*AccretionRadius,'au'), + circle_args={'color':'black', 'fill':True}) + prj.save("Proj_z_%s.png" % (ds)) + + slc = yt.SlicePlot(ds, "z", "velocity_magnitude", center=centre, width=(WIDTH, 'au')) + slc.set_unit("velocity_magnitude", "km/s") + #slc.set_zlim('velocity_magnitude', 0.01, 100) + if(NumAPs > 0): + for i in range(NumAPs): + pos = dd[ActiveParticle, "particle_position"][i] + slc.annotate_sphere(pos, radius=(dx.d*AccretionRadius, 'au'), + circle_args={'color':'black', 'fill':True}) + slc.save("Slice_z_Vel_%s.png" % (ds)) + + prj = yt.ProjectionPlot(ds, "z", 'velocity_magnitude', center=centre,width=(WIDTH, 'au'), + weight_field="velocity_magnitude") + prj.set_unit("velocity_magnitude", "km/s") + #prj.set_zlim('velocity_magnitude', 0.9, 2) + prj.annotate_timestamp(corner='upper_left', redshift=False, draw_inset_box=True) + #prj.annotate_scale(corner='upper_right') + if(NumAPs > 0): + for i in range(NumAPs): + pos = dd[ActiveParticle, "particle_position"][i] + prj.annotate_sphere(pos, radius = (dx.d*AccretionRadius, 'au'), + circle_args={'color':'black', 'fill':True}) + prj.save("Proj_z_Vel_%s.png" % (ds)) + #print dir(plt) + # + # Save the image. + # Optionally, give a string as an argument + # to name files with a keyword. + #slc = yt.SlicePlot(ds, "z", "PotentialField", center='c', width=(WIDTH, 'au')) + #print "Min/Max = ", np.nanmin(dd["PotentialField"]), np.nanmax(dd["PotentialField"]) + #slc.set_log('PotentialField', False) + #if(NumAPs > 0): + # for i in range(NumAPs): + # pos = dd["SmartStar", "particle_position"][i] + # slc.annotate_sphere(pos, radius=(5, 'au'), + # circle_args={'color':'black', 'fill':True}) + #slc.save("PotentialSlice_z_%s.png" % (ds)) + + + #prj = yt.ProjectionPlot(ds, "z", 'PotentialField', center='c',width=(WIDTH, 'au'), + # weight_field=None) + #prj.set_zlim('density', 1e-1, 1e2) + #prj.annotate_timestamp(corner='upper_left', redshift=False, draw_inset_box=True) + #prj.annotate_scale(corner='upper_right') + #if(NumAPs > 0): + # for i in range(NumAPs): + # pos = dd["SmartStar", "particle_position"][i] + # prj.annotate_sphere(pos, radius=(5, 'au'), + # circle_args={'color':'black', 'fill':True}) + #prj.save("Proj_z_%s.png" % (ds)) diff --git a/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo b/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo new file mode 100644 index 000000000..370b701fe --- /dev/null +++ b/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo @@ -0,0 +1,111 @@ +# +# AMR PROBLEM DEFINITION FILE: Collapse test Active Particles +# Description: a sphere collapses until becoming pressure supported. +# +# define problem +# +ProblemType = 27 // Collapse test +TopGridRank = 3 +TopGridDimensions = 64 64 64 +SelfGravity = 1 // gravity on +TopGridGravityBoundary = 0 // periodic +LeftFaceBoundaryCondition = 3 3 3 // periodic +RightFaceBoundaryCondition = 3 3 3 + +# +# problem parameters +# + +CollapseTestRefineAtStart = 1 // check refinement before running +CollapseTestNumberOfSpheres = 1 +CollapseTestUseParticles = 0 +CollapseTestInitialTemperature = 5e3 // temperature of the background gas +CollapseTestSpherePosition[0] = 0.5 0.5 0.5 +CollapseTestSphereVelocity[0] = 0.0 0.0 0.0 +CollapseTestSphereRadius[0] = 0.016203778 +CollapseTestSphereCoreRadius[0] = 0.05 // only used with sphere type 5 +CollapseTestSphereDensity[0] = 228.33 // sphere density, the background density is 1 +CollapseTestSphereTemperature[0] = 10 // put sphere in pressure equilibrium (rho * T is constant) +CollapseTestSphereType[0] = 2 // constant density + // 1: uniform + // 2: r^-2 power-law + // 3: NFW + // 4: Gaussian + // 5: r^-2 power-law with a core +# +# no cosmology for this run +# +ComovingCoordinates = 0 // Expansion OFF + +# +# units +# +DensityUnits = 1.673e-20 // 10^4 cm^-3 +LengthUnits = 3.0857e+18 // 1 pc in cm +TimeUnits = 3.1557e+11 // 10^4 yrs +GravitationalConstant = 1.39698e-3 // 4*pi*G_{cgs}*DensityUnits*TimeUnits^2 +# +# set I/O and stop/start parameters +# +StopTime = 1.8 +dtDataDump = 0.5 +#CycleSkipDataDump = 1 +DataDumpDir = DD +DataDumpName = DD +OutputTemperature = 1 // Output temperature field. +# +# set hydro parameters +# +Gamma = 1.0000001 +PPMDiffusionParameter = 0 // diffusion off +DualEnergyFormalism = 1 // use total & internal energy +InterpolationMethod = 1 // SecondOrderA +CourantSafetyNumber = 0.3 +FluxCorrection = 1 +ConservativeInterpolation = 1 +RiemannSolver = 4 +HydroMethod = 0 // PPM +SmallRho = 1e-8 +SmallE = 1e-8 +# +# chemistry/cooling +# +MultiSpecies = 0 // chemistry off +RadiativeCooling = 0 // cooling off +Mu = 3.0 +# +# set grid refinement parameters +# +StaticHierarchy = 0 // dynamic hierarchy +MaximumRefinementLevel = 5 // use up to 10 levels +RefineBy = 2 // refinement factor +CellFlaggingMethod = 2 4 // use baryon mass and Truelove criterion for refinement +MinimumEfficiency = 0.3 +#OutputFirstTimeAtLevel = 4 // output when level 4, 5, 6, etc reached (commented out for now) +#StopFirstTimeAtLevel = 10 // stop if/when level 10 reached +RefineByJeansLengthSafetyFactor = 64 // resolve Jeans length by 4 cells (used with CellFlaggingMethod 6) +#MustRefineRegionMinRefinementLevel = 4 +#MustRefineRegionLeftEdge = 0.3 0.3 0.3 +#MustRefineRegionRightEdge = 0.7 0.7 0.7 + +# +# set some global parameters +# +GreensFunctionMaxNumber = 10 // # of greens function at any one time +PotentialIterations = 100 +ComputePotential = 0 +WritePotential = 0 +# +# active particle parameters +# +AppendActiveParticleType = SmartStar +RadiativeTransfer = 0 +ActiveParticleDensityThreshold = 1e9 +MBHAccretion = 1 +SmartStarSMSLifetime = 1e100 +SmartStarFeedback = 0 //Sets feedback of any kind +SmartStarBHRadiativeFeedback = 0 //We don't want RT for a Black Hole +SmartStarRadiativeFeedback = 0 //Always required since we start life as an SMS? +SmartStarJetFeedback = 0 +SmartStarThermalFeedback = 0 +SmartStarJetVelocity = 1e-3 diff --git a/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py b/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py new file mode 100644 index 000000000..4b38b1a9c --- /dev/null +++ b/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py @@ -0,0 +1,205 @@ + +import matplotlib +matplotlib.use('Agg') +import yt +import numpy as np +import sys +import matplotlib.pyplot as plt +from yt.units import G, kboltz, mh +from yt.units.yt_array import YTQuantity, YTArray +import glob +from scipy.signal import savgol_filter +yt.enable_parallelism() + +mycolors = iter(['red', 'blue', 'black', 'green', 'magenta']) + +def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) + return -4.0*np.pi*data["radius"]*data["radius"]*data["density"]*data["radial_velocity"] + +#Add Derived Rates +yt.add_field(("gas", "shell_accretion_rate"), units="Msun/yr", + function=_Accretion_Rate) + +BASE = "/home/regan/data/SourceCodes/EnzoGit/fearmayo/enzo-dev/run/Hydro/Hydro-3D/CollapseTestSmartStars/" +Mu = 3.0 +CENTRE = [0.5, 0.5, 0.5] + + +Files = glob.glob(BASE + "DD00??/DD00??") +Files.sort() +#Files = ["DD0000/DD0000", +# "DD0001/DD0001", +# "DD0002/DD0002", +# "DD0003/DD0003"] +print("Files = ", Files) + + +Fields = ["density", "temperature", "radial_velocity", "cell_mass", + "shell_accretion_rate"] + +YFields = [] +FieldsFigure = {} +FieldsAxes = {} +for elem in Fields: + #Setup Figures + tmpfigure = plt.figure() + FieldsFigure[elem] = tmpfigure + FieldsAxes[elem] = tmpfigure.add_subplot(111) + YFields.append(elem) + +accrate = [] +ages = [] +for f in Files: + ff = f + ds = yt.load(ff) + dd = ds.all_data() + NumAPs = 0 + flist = dir(ds.fields) + if yt.is_root(): + print("Stats = %e cm" % (ds.index.get_smallest_dx().in_units("cm"))) + print("Stats = %e pc" % (ds.index.get_smallest_dx().in_units("pc"))) + print("Current Time = %e s" % (ds.current_time.in_units("s"))) + print("Current Time = %e code" % (ds.current_time.in_units("code_time"))) + print("Current Time = %e yr" % (ds.current_time.in_units("yr"))) + try: + NumAPs = len(dd["SmartStar", "level"]) + centre = dd["SmartStar", "particle_position"][0] + except: + centre = CENTRE + time = ds.current_time.in_units("yr") + if(time > 0): + timeindex = dd["SmartStar", "TimeIndex"][0].d + accrate = dd["SmartStar", "AccretionRate"][0][1:int(timeindex+1)].in_units("Msun/yr") + ages = dd["SmartStar", "AccretionRateTime"][0][1:int(timeindex+1)].in_units("yr") + deltaT = np.ediff1d(ages, to_begin=1) + masses = accrate*deltaT + #print("accrate = ", accrate) + #print("ages = ", ages) + #print("masses = ", masses) + print("NumAPs = ", NumAPs) + print("Accreting Particle Position = ", centre) + + # Create a sphere of radius 1 kpc in the center of the box. + my_sphere = ds.sphere(centre, (1.0, "pc")) + + # Create a profile of the average density vs. radius. + prof = yt.create_profile(my_sphere, "radius", YFields, + units = {'radius': 'cm'}, + weight_field="cell_mass") + + Radius = prof.x[prof["density"] > 0.0] + Density = prof["density"][prof["density"] > 0.0] + Temperature = prof["temperature"][prof["density"] > 0.0] + + #Plot Density + FieldsAxes["density"].loglog(Radius, Density, label="T = %2.2e yrs" % + (ds.current_time.in_units("yr")), linewidth=2.0) + + #Add in analytic expression from Shu et al. (1977) + T = ds.current_time.in_units("s") + cs = np.sqrt(kboltz*Temperature/(Mu*mh)) + #cs = 0.166 * 1e5 + m0 = np.sqrt(133.0) + csT = (cs*T).d + #print("cs = ", cs/1e5) + + shu_density = np.power(cs, 1.5)*m0/(4*np.pi*G*np.sqrt(2.0*T)*np.power(Radius, 1.5)) + shu_density = shu_density[Radius.d < 2e16] + shu_radius = Radius[Radius.d < 2e16] + FieldsAxes["density"].loglog(shu_radius, shu_density, ls='dotted', linewidth=2.0) + #Radial Velocity Plots + RadialVelocity = prof["radial_velocity"][prof["density"] > 0.0].in_units("km/s") + EnclosedMass = prof["cell_mass"][prof["density"] > 0.0] + + FieldsAxes["radial_velocity"].semilogx(Radius, RadialVelocity, + label="T = %2.2e yrs" % + (ds.current_time.in_units("yr")), + linewidth=2.0) + #Add in analytic expression from Shu et al. (1977) + shu_radial = -cs*m0*np.sqrt(2*cs*T/Radius)/1e5 + shu_radial = shu_radial[Radius.d < 2e16] + FieldsAxes["radial_velocity"].semilogx(shu_radius, shu_radial, ls='dotted', linewidth=2.0) + #Accretion Plots + AccretionRate = prof["shell_accretion_rate"][prof["density"] > 0.0] + #print "Accretion Rate = ", AccretionRate + if(np.sum(AccretionRate) > 0.0): + FieldsAxes["shell_accretion_rate"].loglog(Radius, AccretionRate, + label="T = %2.2e yrs" % + (ds.current_time.in_units("yr")) + ,linewidth=2.0) + #Add in analytic expression + shu_accretion_rate = (m0*m0*np.power(cs, 3.0)/G).d + shu_accretion_rate = YTArray(shu_accretion_rate, 'g/s', registry=ds.unit_registry) + #print "Shu Accretion Rate = ", shu_accretion_rate + shu_accretion_rate = shu_accretion_rate[Radius.d < 2e16].in_units("Msun/yr") + #print "Shu Accretion Rate = ", shu_accretion_rate + FieldsAxes["shell_accretion_rate"].loglog(shu_radius, shu_accretion_rate, + ls='dotted', linewidth=2.0) + + +XS = 1e15 +XE = 1e17 +#Add in accretion radius +#Add in minimum cell width +YCELLWIDTH = [1e-30, 1e-10] +XCELLWIDTH = np.zeros_like(YCELLWIDTH) +XCELLWIDTH[0] = ds.index.get_smallest_dx().in_units("cm") +XCELLWIDTH[1] = ds.index.get_smallest_dx().in_units("cm") +#print("XCELLWIDTH[0] = ", XCELLWIDTH[0]) +FieldsAxes["density"].loglog(XCELLWIDTH, YCELLWIDTH, ls='dashed', label="Minimum Cellwidth", linewidth=2.0) +FieldsAxes["density"].loglog(XCELLWIDTH*4.0, YCELLWIDTH, ls='dashed', label="Accretion Radius", linewidth=2.0) +FieldsAxes["density"].legend() +FieldsAxes["density"].set_xlim(XS, XE) +FieldsAxes["density"].set_ylim(1e-19, 1e-11) +FieldsAxes["density"].set_xlabel("R [cm]", fontsize=18) +FieldsAxes["density"].set_ylabel("$\\rho$ [g cm$^{-3}$]", fontsize=18) +FieldsAxes["density"].xaxis.labelpad = -2 +FieldsFigure["density"].savefig("DensityProfile.png") +FieldsFigure["density"].savefig("DensityProfile.pdf") + +YCELLWIDTH = [-30, 0] +FieldsAxes["radial_velocity"].semilogx(XCELLWIDTH, YCELLWIDTH, ls='dashed', label="Minimum Cellwidth", linewidth=2.0) +FieldsAxes["radial_velocity"].semilogx(XCELLWIDTH*4.0, YCELLWIDTH, ls='dashed', label="Accretion Radius", linewidth=2.0) +FieldsAxes["radial_velocity"].legend(loc='best') +FieldsAxes["radial_velocity"].set_xlabel("R [cm]", fontsize=18) +FieldsAxes["radial_velocity"].set_ylabel("V$_r$ [km s$^{-1}$]", fontsize=18) +FieldsAxes["radial_velocity"].set_xlim(XS, XE) +FieldsAxes["radial_velocity"].set_ylim(-5, 0) +FieldsAxes["radial_velocity"].xaxis.labelpad = -2 +FieldsFigure["radial_velocity"].savefig("RadialVelocityProfile.png") +FieldsFigure["radial_velocity"].savefig("RadialVelocityProfile.pdf") + +YCELLWIDTH = [1e-10, 1e2] +FieldsAxes["shell_accretion_rate"].loglog(XCELLWIDTH, YCELLWIDTH, ls='dashed', label="Minimum Cellwidth", linewidth=2.0) +FieldsAxes["shell_accretion_rate"].loglog(XCELLWIDTH*4.0, YCELLWIDTH, ls='dashed', label="Accretion Radius", linewidth=2.0) +FieldsAxes["shell_accretion_rate"].legend() +FieldsAxes["shell_accretion_rate"].set_xlim(XS, XE) +FieldsAxes["shell_accretion_rate"].set_ylim(1e-6, 1e-2) +FieldsAxes["shell_accretion_rate"].set_xlabel("R [cm]", fontsize=18) +FieldsAxes["shell_accretion_rate"].set_ylabel("Accretion Rate [M$_{\odot}$ yr$^{-1}$]", fontsize=18) +FieldsAxes["shell_accretion_rate"].xaxis.labelpad = -2 +FieldsFigure["shell_accretion_rate"].savefig("AccretionRateProfile.png") +FieldsFigure["shell_accretion_rate"].savefig("AccretionRateProfile.pdf") + + + + +plt.figure() + +accrate = savgol_filter(accrate, 33, 1,mode='nearest') +#plot the accretion rate over time +plt.plot(ages, accrate*1e4) +plt.xlabel("Time [yr]", fontsize=18) +plt.ylabel("Accretion Rate [M$_{\odot}$ yr$^{-1}$]", fontsize=18) +#plt.ylim(1e-5, 1e-3) +plt.savefig("AccretionRateEvolution.png") + +plt.figure() +masses = np.cumsum(masses) +masses = savgol_filter(masses, 5, 1,mode='nearest') +#plot the mass against time +plt.plot(ages, masses) +plt.xlabel("Time [yr]", fontsize=18) +plt.ylabel("Particle Mass [M$_{\odot}$]", fontsize=18) +plt.savefig("MassEvolution.png") + diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 9be165611..eecc00308 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -17,9 +17,9 @@ #define MINIMUMPOTENTIAL 1 #define CALCDIRECTPOTENTIAL 0 #define JEANSREFINEMENT 1 -#define MASSTHRESHOLDCHECK 1 +#define MASSTHRESHOLDCHECK 0 #define JEANSLENGTHCALC 1 -#define MASSTHRESHOLD 30 //Msolar in grid +#define MASSTHRESHOLD 0.1 //Msolar in grid #define COOLING_TIME 0 int DetermineSEDParameters(ActiveParticleType_SmartStar *SS,FLOAT Time, FLOAT dx); @@ -114,6 +114,7 @@ int ActiveParticleType_SmartStar::InitializeParticleType() int ActiveParticleType_SmartStar::EvaluateFormation (grid *thisgrid_orig, ActiveParticleFormationData &data) { + // No need to do the rest if we're not on the maximum refinement level. if (data.level != MaximumRefinementLevel) return SUCCESS; @@ -149,11 +150,11 @@ int ActiveParticleType_SmartStar::EvaluateFormation bool HasMetalField = (data.MetalNum != -1 || data.ColourNum != -1); bool JeansRefinement = false; bool MassRefinement = false; -#if CACLDIRECTPOTENTIAL float *PotentialField = NULL; -#else - float *PotentialField = thisGrid->BaryonField[data.GravPotentialNum]; -#endif + if(data.GravPotentialNum >= 0) + PotentialField = thisGrid->BaryonField[data.GravPotentialNum]; + + //printf("PotentialField = %p\n", PotentialField); const int offset[] = {1, GridDimension[0], GridDimension[0]*GridDimension[1]}; @@ -188,8 +189,9 @@ int ActiveParticleType_SmartStar::EvaluateFormation #if JEANSREFINEMENT if (JeansRefinement) { CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : data.Temperature[index]; + int JeansFactor = 1; //RefineByJeansLengthSafetyFactor JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / - POW(data.LengthUnits*dx*RefineByJeansLengthSafetyFactor,2); + POW(data.LengthUnits*dx*JeansFactor,2); JeansDensity /= data.DensityUnits; DensityThreshold = min(DensityThreshold,JeansDensity); @@ -234,7 +236,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation #if SSDEBUG fprintf(stdout, "%s: Negative Divergence passed\n", __FUNCTION__); #endif - + /* We now need to define a control volume - this is the region within an accretion radius of the cell identified */ centralpos[0] = thisGrid->CellLeftEdge[0][i] + 0.5*thisGrid->CellWidth[0][i]; @@ -281,24 +283,28 @@ int ActiveParticleType_SmartStar::EvaluateFormation #if SSDEBUG fprintf(stdout, "%s: Calculate Gravitational Potential\n", __FUNCTION__); #endif - - /* 4. Gravitational Minimum Check */ - /* - * Find the minimum of the potential over a Jeans Length. - */ - double JLength = JeansLength(CellTemperature, density[index], - data.DensityUnits)/data.LengthUnits; - GravitationalMinimum = thisGrid->FindMinimumPotential(centralpos, JLength*64.0, - PotentialField); - if(PotentialField[index] > GravitationalMinimum) { + if(PotentialField) { + /* 4. Gravitational Minimum Check */ + /* + * Find the minimum of the potential over a Jeans Length. + */ + double JLength = JeansLength(CellTemperature, density[index], + data.DensityUnits)/data.LengthUnits; + GravitationalMinimum = thisGrid->FindMinimumPotential(centralpos, + JLength*RefineByJeansLengthSafetyFactor*4.0, + PotentialField); + if(PotentialField[index] > GravitationalMinimum) { #if SSDEBUG - printf("FAILURE: GravitationalMinimum = %g\t " \ - "PotentialField[index] = %g\n\n", GravitationalMinimum, PotentialField[index]); + printf("FAILURE: GravitationalMinimum = %g\t " \ + "PotentialField[index] = %g\n\n", GravitationalMinimum, PotentialField[index]); #endif - continue; + continue; + } + //#if SSDEBUG + fprintf(stdout, "%s: Gravitational Potential Passed!\n", __FUNCTION__); + //#endif } - - + #endif #ifdef GRAVENERGY static int mincount = 0; @@ -343,9 +349,9 @@ int ActiveParticleType_SmartStar::EvaluateFormation float *apvel = new float[MAX_DIMENSION]; /* Calculate AP velocity by taking average of - * surrounding cells + * surrounding 125 cells */ - apvel = thisGrid->AveragedVelocityAtCell(index, data.DensNum, data.Vel1Num); + apvel = thisGrid->AveragedVelocityAtCell3D(index, data.DensNum, data.Vel1Num); np->vel[0] = apvel[0]; np->vel[1] = apvel[1]; np->vel[2] = apvel[2]; @@ -371,10 +377,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation * (0.04 Msun/yr) for longer than 1000 yrs then the spectrum needs * to change to a bluer spectrum. */ -#if SSDEBUG - printf("Forming a SMS - H2Fraction (Threshold) = %e (%e) \n", - data.H2Fraction[index], PopIIIH2CriticalFraction); -#endif + np->ParticleClass = SMS; //1 np->RadiationLifetime=SmartStarSMSLifetime*yr_s/data.TimeUnits; np->NotEjectedMass = 0.0; @@ -389,7 +392,6 @@ int ActiveParticleType_SmartStar::EvaluateFormation printf("Particles (%d) Created and done in Evaulate Formation\n", data.NumberOfNewParticles); fflush(stdout); } - #if CALCDIRECTPOTENTIAL delete [] PotentialField; #endif diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 3754bea10..2d56e6576 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -34,7 +34,7 @@ #define ACCRETIONRADIUS 4 #define NUMRADIATIONBINS 5 #define CRITICAL_ACCRETION_RATE 0.04 //Msolar/yr -#define TIMEGAP 900 //yrs +#define TIMEGAP 90 //yrs /* Prototypes */ int GetUnits(float *DensityUnits, float *LengthUnits, @@ -220,11 +220,8 @@ void ActiveParticleType_SmartStar::MergeSmartStars( FLOAT ParticleCoordinates[3*(*nParticles)]; fflush(stdout); - /* Particles merge once they come within 4 cells of one another */ - /* This is OK since we only want to merge particles when they come really - * close to one another. Their accretion zones overlapping does - * not necessarily constitute a merger. - */ + /* Particles merge once they come within 3 accretion radii of one another */ + FLOAT MergingRadius = LevelArray[ThisLevel]->GridData->GetCellWidth(0,0)*ACCRETIONRADIUS; MergingRadius = MergingRadius*3.0; for (i=0; i<(*nParticles); i++) { diff --git a/src/enzo/GrackleReadParameters.C b/src/enzo/GrackleReadParameters.C index f074eed92..473f6ef94 100644 --- a/src/enzo/GrackleReadParameters.C +++ b/src/enzo/GrackleReadParameters.C @@ -193,7 +193,8 @@ int GrackleReadParameters(FILE *fptr, FLOAT InitTime) code_units grackle_units; grackle_units.a_units = 1.0; float DensityUnits = 1.0, LengthUnits = 1.0, TemperatureUnits = 1.0, - TimeUnits = 1.0, VelocityUnits = 1.0, MassUnits = 1.0; + TimeUnits = 1.0, VelocityUnits = 1.0; + double MassUnits = 1.0; if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, &MassUnits, InitTime) == FAIL) { ENZO_FAIL("Error in GetUnits.\n"); diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index 4757742a1..b6559645e 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2622,6 +2622,10 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], float* AveragedVelocityAtCell(int index, int DensNum, int Vel1Num); + /* Returns averaged velocity from the 26 neighbor cells and itself */ + + float* AveragedVelocityAtCell3D(int index, int DensNum, int Vel1Num); + /* Find the minumum of the angular momentum in a given region */ float FindAngularMomentumMinimum(FLOAT *cellpos, FLOAT radius, int DensNum, int Vel1Num, int Vel2Num, int Vel3Num); diff --git a/src/enzo/Grid_AveragedVelocityAtCell.C b/src/enzo/Grid_AveragedVelocityAtCell.C index 445ee5ac5..052ff7594 100644 --- a/src/enzo/Grid_AveragedVelocityAtCell.C +++ b/src/enzo/Grid_AveragedVelocityAtCell.C @@ -71,3 +71,60 @@ float* grid::AveragedVelocityAtCell(int index, int DensNum, int Vel1Num) return vel; } +#define LEFT -2 +#define RIGHT 2 +#define NUM_NEIGHBOURS 125 +float* grid::AveragedVelocityAtCell3D(int index, int DensNum, int Vel1Num) +{ + + const int offset[] = {1, GridDimension[0], GridDimension[0]*GridDimension[1]}; + + int i, dim, indices[NUM_NEIGHBOURS]; + float weight; + float *vel = new float[MAX_DIMENSION]; + float *rho = BaryonField[DensNum]; + float *allv[] = {BaryonField[Vel1Num], + BaryonField[Vel1Num+1], + BaryonField[Vel1Num+2]}; + + + int count = 0; + for (int x = LEFT; x <= RIGHT; x++) { + for(int y = LEFT; y <= RIGHT; y++) { + for(int z = LEFT; z <= RIGHT; z++) { + int celloffset = GRIDINDEX_NOGHOST(x,y,z); + indices[count] = index + celloffset; + count = count + 1; + } + } + } + + if (HydroMethod == Zeus_Hydro) { + + for (dim = 0; dim < GridRank; dim++) { + weight = 0; + vel[dim] = 0; + for (i = 0; i < NUM_NEIGHBOURS; i++) { + weight += rho[indices[i]]; + vel[dim] += 0.5 * (allv[dim][indices[i]] + allv[dim][indices[i]+offset[dim]]); + } + vel[dim] /= weight; + } // ENDFOR dim + + } else { + + for (dim = 0; dim < GridRank; dim++) { + weight = 0; + vel[dim] = 0; + for (i = 0; i < NUM_NEIGHBOURS; i++) { + weight += rho[indices[i]]; + vel[dim] += allv[dim][indices[i]] * rho[indices[i]]; + } + vel[dim] /= weight; + } // ENDFOR dim + + } // ENDELSE !Zeus + + return vel; + +} diff --git a/src/enzo/Grid_CollapseTestInitializeGrid.C b/src/enzo/Grid_CollapseTestInitializeGrid.C index 7c0282d73..2e53f875c 100644 --- a/src/enzo/Grid_CollapseTestInitializeGrid.C +++ b/src/enzo/Grid_CollapseTestInitializeGrid.C @@ -324,6 +324,15 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, SphereRadius[sphere]); break; + case 2: + SphereMass = 4*pi*pow((SphereRadius[sphere]*LengthUnits), 3) * + (SphereDensity[sphere]*DensityUnits); + mu = Mu; + printf("mass = %"GSYM", lunit = %"GSYM", dunit = %"GSYM", rho = %"GSYM", r = %"GSYM"\n", + SphereMass, LengthUnits, DensityUnits, SphereDensity[sphere], + SphereRadius[sphere]); + break; + case 3: SphereMass = m200*SolarMass; break; @@ -420,13 +429,32 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, ThickenTransitionRadius, InnerScaleHeight); break; + + case 11: + printf("%s: Do BurkertBodenheimer setup\n", __FUNCTION__); + mu = Mu; + SphereMass = (4.0*M_PI/3.0)*pow((SphereRadius[sphere]*LengthUnits), 3) * + (SphereDensity[sphere]*DensityUnits); + //SphereAng1[sphere] = 0.0; + //SphereAng2[sphere] = 0.0; + printf("mass = %"GSYM", lunit = %"GSYM", dunit = %"GSYM", rho = %"GSYM", r = %"GSYM"\n", + SphereMass, LengthUnits, DensityUnits, SphereDensity[sphere], + SphereRadius[sphere]); + break; } // ENDSWITCH SphereType - + + printf("\nSphere Radius = %e cm\n", SphereRadius[sphere]*(LengthUnits)); printf("\nSphere Mass (M_sun): %"FSYM"\n", SphereMass/SolarMass); + printf("\nSphere Mass (M_sun): %1.20e g\n", SphereMass); + printf("\nSphere Density (R = %g) = %"GSYM" g cm^-3\n", SphereRadius[sphere]*(LengthUnits), + SphereDensity[sphere]*DensityUnits); + printf("G = %e\n", GravConst); VelocityKep = sqrt(GravConst*SphereMass/(SphereRadius[sphere]*(LengthUnits))); - + printf("\nVelocityKep = %e\n", VelocityKep); + + printf("\nSphereFracKeplerianRot[%d] = %e\n", sphere, SphereFracKeplerianRot[sphere]); if (SphereFracKeplerianRot[sphere] > 0) { - SphereRotationalPeriod[sphere] = 2*pi*SphereRadius[sphere]*(LengthUnits)/ + SphereRotationalPeriod[sphere] = 2*M_PI*SphereRadius[sphere]*(LengthUnits)/ (SphereFracKeplerianRot[sphere]*VelocityKep); SphereRotationalPeriod[sphere] /= TimeUnits; } else @@ -436,15 +464,17 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, * SphereFracKeplerianRot[sphere]*TimeUnits); printf("\nSphere Rotation Period (s): %"GSYM"\n", SphereRotationalPeriod[sphere] * TimeUnits); - + printf("\nSphere Angular Velocity (rads/s): %e\n", 2*M_PI/(SphereRotationalPeriod[sphere] + * TimeUnits)); + printf("Temperature = %f K\n", SphereTemperature[sphere]); + printf("Mu = %f\n", mu); // Calculate speed of sound for this sphere VelocitySound[sphere] = sqrt((SphereTemperature[sphere] * Gamma * kboltz) / (mu * mh)) / VelocityUnits; - printf("\nVelocitySound (cm s^-1): %"GSYM"\n", VelocitySound[sphere] * - VelocityUnits); - + printf("\nVelocitySound (km s^-1): %e\n", VelocitySound[sphere] * + VelocityUnits/1e5); } // ENDFOR sphere - + //exit(-99); for (k = 0; k < GridDimension[2]; k++) for (j = 0; j < GridDimension[1]; j++) for (i = 0; i < GridDimension[0]; i++, n++) { @@ -536,6 +566,22 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, } else { RotVelocity[0] = RotVelocity[1] = RotVelocity[2] = 0; } + //double AV = 2*M_PI/SphereRotationalPeriod[sphere]; + //printf("AV = %e\n", AV); + //printf("xpos, ypos, zpos = %e %e %e\n", xpos*LengthUnits, ypos*LengthUnits, zpos*LengthUnits); + //printf("r = %e cm\n", sqrt(xpos*xpos + ypos*ypos + zpos*zpos)*LengthUnits); + //printf("a = %f\n", a); + //printf("cos(a) = %f\t sin(a) = %f\n", cos(a), sin(a)); + + //printf("Velocity [cm/s] = %e %e %e\n", RotVelocity[0]*VelocityUnits, RotVelocity[1]*VelocityUnits, RotVelocity[2]*VelocityUnits); + + //RotVelocity[0] = -AV*ypos; + //RotVelocity[1] = AV*xpos; + //printf("EE: Velocity [cm/s] = %e %e %e\n\n", RotVelocity[0]*VelocityUnits, RotVelocity[1]*VelocityUnits, RotVelocity[2]*VelocityUnits); + + //getchar(); + + Velocity[0] += SphereTurbulence[sphere] * Maxwellian(VelocitySound[sphere], VelocityUnits, mu, Gamma); Velocity[1] += SphereTurbulence[sphere] * @@ -747,15 +793,41 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, } // end: disk - /* 11) stellar wind, with r^-2 POWer law density*/ - if (SphereType[sphere] == 11) { - radial_velocity = StellarWindSpeed/VelocityUnits; - dens1 = StellarWindDensity*POW(r/StellarWindRadius, -2); - Velocity[0] += radial_velocity * xpos / r; - Velocity[1] += radial_velocity * ypos / r; - Velocity[2] += radial_velocity * zpos / r; - } // end stellar wind - + /* 11) Burkert-Bodenheimer Sphere */ + + if (SphereType[sphere] == 11) { + dens1 = SphereDensity[sphere]; + + //density = dens1; + // compute the azimuthal angle + FLOAT cosphi = xpos/sqrt(xpos*xpos+ypos*ypos); + FLOAT sinphi = ypos/sqrt(xpos*xpos+ypos*ypos); + FLOAT phi = acos(xpos/sqrt(xpos*xpos+ypos*ypos)); + FLOAT cos2phi = cosphi*cosphi -sinphi*sinphi; + // Burkert & Bodenheimer (1993) m=2 perturbation: + float m2mode = 1.0 + 0.1*cos(2.*phi); + float p, cs, h, dpdrho, dpde, gamma=Gamma; + /* Perturb density field */ + dens1 *= m2mode; + // BUT keep the pressure constant everywhere + // to avoid discontinuities at the sphere boundaries +#ifdef EOS + if(density <= 0.25*1e-15/DensityUnits) + gamma = 1.000001; + else if(density <= 5.0*1e-15/DensityUnits) + gamma = 1.1; + else + gamma = 4.0/3.0; + + eint = pow(VelocitySound[sphere], 2)/(gamma-1.0)/m2mode; + //printf("BB: eint = %g\n", eint); + p = pow(VelocitySound[sphere], 2)*density/gamma; + + //EOS(p, density, eint, h, cs, dpdrho, dpde, EOSType, 1); + //printf("BB (after EOS): eint = %g\n", eint); +#endif + + } /* If the density is larger than the background (or the previous sphere), then set the velocity. */ @@ -763,9 +835,11 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, if (density <= InitialDensity) { old_density = 0; density = dens1; + //printf("1. set density = %e\n", dens1*DensityUnits); } else { old_density = density; density += dens1; + //printf("2. add %e to density", dens1*DensityUnits); } weight = dens1/density; @@ -791,7 +865,10 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, sigma = sigma1; if (SphereType[sphere] != 10) for (dim = 0; dim < GridRank; dim++) - Velocity[dim] = Velocity[dim] + SphereVelocity[sphere][dim]; + { + Velocity[dim] = Velocity[dim] + SphereVelocity[sphere][dim]; + + } // Velocity[dim] = (1-weight)*Velocity[dim] + // weight*SphereVelocity[sphere][dim]; else @@ -816,7 +893,8 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, //metallicity += SphereMetallicity[sphere]; metallicity = SphereMetallicity[sphere]; - + if(temperature != 10.0) + printf("temperature = %f\n", temperature); } // end: if (r < SphereRadius) else { @@ -959,7 +1037,6 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, BaryonField[ivel+dim][n] = Velocity[dim] + UniformVelocity[dim]; /* Set energy (thermal and then total if necessary). */ - BaryonField[1][n] = temperature/TemperatureUnits/ ((Gamma-1.0)*mu); if (DualEnergyFormalism) diff --git a/src/enzo/phys_constants.h b/src/enzo/phys_constants.h index e39c79c1b..b485e072a 100644 --- a/src/enzo/phys_constants.h +++ b/src/enzo/phys_constants.h @@ -64,7 +64,7 @@ /* Gravitational constant [cm3g-1s-2]*/ -#define GravConst 6.67428e-8 +#define GravConst 6.6740831e-8 //6.67428e-8 /* Solar mass [g] */ From f76821ec85ff0e3b78d8571a2b61a61e314c199a Mon Sep 17 00:00:00 2001 From: John Regan Date: Wed, 20 May 2020 11:35:03 +0100 Subject: [PATCH 075/115] couple of minor updates --- .../CollapseTestSmartStars/CollapseTestSmartStars.enzo | 8 ++++---- src/enzo/ActiveParticle_SmartStar.C | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo b/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo index 370b701fe..f5795af68 100644 --- a/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo +++ b/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo @@ -6,7 +6,7 @@ # ProblemType = 27 // Collapse test TopGridRank = 3 -TopGridDimensions = 64 64 64 +TopGridDimensions = 128 128 128 SelfGravity = 1 // gravity on TopGridGravityBoundary = 0 // periodic LeftFaceBoundaryCondition = 3 3 3 // periodic @@ -76,8 +76,8 @@ Mu = 3.0 # # set grid refinement parameters # -StaticHierarchy = 0 // dynamic hierarchy -MaximumRefinementLevel = 5 // use up to 10 levels +StaticHierarchy = 1 // dynamic hierarchy +MaximumRefinementLevel = 0 // use up to 10 levels RefineBy = 2 // refinement factor CellFlaggingMethod = 2 4 // use baryon mass and Truelove criterion for refinement MinimumEfficiency = 0.3 @@ -100,7 +100,7 @@ WritePotential = 0 # AppendActiveParticleType = SmartStar RadiativeTransfer = 0 -ActiveParticleDensityThreshold = 1e9 +ActiveParticleDensityThreshold = 1e10 MBHAccretion = 1 SmartStarSMSLifetime = 1e100 SmartStarFeedback = 0 //Sets feedback of any kind diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index eecc00308..a0da09d4a 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -300,9 +300,9 @@ int ActiveParticleType_SmartStar::EvaluateFormation #endif continue; } - //#if SSDEBUG +#if SSDEBUG fprintf(stdout, "%s: Gravitational Potential Passed!\n", __FUNCTION__); - //#endif +#endif } #endif @@ -389,7 +389,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation } // j } // k if(data.NumberOfNewParticles > 0) { - printf("Particles (%d) Created and done in Evaulate Formation\n", data.NumberOfNewParticles); + printf("Particles (%d) Created and done in %s\n", data.NumberOfNewParticles, __FUNCTION__); fflush(stdout); } #if CALCDIRECTPOTENTIAL From 668a4a34175af3a301ea89ba29a4a11bef2732df Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 22 May 2020 09:27:04 +0100 Subject: [PATCH 076/115] Committing the Burkert Bodenheimer parameter file --- ...icle.enzo => BBCollapseTestSmartStarParticle.enzo} | 0 .../CollapseTestSmartStars.enzo | 2 +- src/enzo/ActiveParticle_SmartStar.C | 11 +++++++---- src/enzo/Grid_CollapseTestInitializeGrid.C | 3 +++ 4 files changed, 11 insertions(+), 5 deletions(-) rename run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/{BBCollapseTestAccretingParticle.enzo => BBCollapseTestSmartStarParticle.enzo} (100%) diff --git a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestAccretingParticle.enzo b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo similarity index 100% rename from run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestAccretingParticle.enzo rename to run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo diff --git a/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo b/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo index f5795af68..897f666d6 100644 --- a/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo +++ b/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo @@ -100,7 +100,7 @@ WritePotential = 0 # AppendActiveParticleType = SmartStar RadiativeTransfer = 0 -ActiveParticleDensityThreshold = 1e10 +ActiveParticleDensityThreshold = 1.33e7 MBHAccretion = 1 SmartStarSMSLifetime = 1e100 SmartStarFeedback = 0 //Sets feedback of any kind diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index a0da09d4a..3a3356ec6 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -9,7 +9,7 @@ #include "ActiveParticle_SmartStar.h" #include "phys_constants.h" -#define SSDEBUG 0 +#define SSDEBUG 1 #define SSDEBUG_TOTALMASS 0 #define DYNAMIC_ACCRETION_RADIUS 0 @@ -206,11 +206,12 @@ int ActiveParticleType_SmartStar::EvaluateFormation if (density[index] <= DensityThreshold) continue; + #if SSDEBUG + printf("Time = %e yr\n", thisGrid->ReturnTime()*data.TimeUnits/yr_s); printf("Density = %g\t DensityThreshold = %g\n", density[index]*data.DensityUnits/mh, DensityThreshold*data.DensityUnits/mh); printf("JeansDensity = %g\t APThreshold = %g\n", JeansDensity*data.DensityUnits/mh, ActiveParticleDensityThreshold); #endif - mass = density[index]*dx*dx*dx; #if SSDEBUG fprintf(stdout, "%s: Excellent! Density threshold exceeeded - density = %g cm^-3\n", @@ -280,10 +281,11 @@ int ActiveParticleType_SmartStar::EvaluateFormation thisGrid->CalculatePotentialField(PotentialField, data.DensNum, data.DensityUnits, data.TimeUnits,data.LengthUnits); } #endif + if(PotentialField) { + #if SSDEBUG - fprintf(stdout, "%s: Calculate Gravitational Potential\n", __FUNCTION__); + fprintf(stdout, "%s: Calculate Gravitational Potential\n", __FUNCTION__); #endif - if(PotentialField) { /* 4. Gravitational Minimum Check */ /* * Find the minimum of the potential over a Jeans Length. @@ -391,6 +393,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation if(data.NumberOfNewParticles > 0) { printf("Particles (%d) Created and done in %s\n", data.NumberOfNewParticles, __FUNCTION__); fflush(stdout); + exit(-99); } #if CALCDIRECTPOTENTIAL delete [] PotentialField; diff --git a/src/enzo/Grid_CollapseTestInitializeGrid.C b/src/enzo/Grid_CollapseTestInitializeGrid.C index 2e53f875c..c285f3a2e 100644 --- a/src/enzo/Grid_CollapseTestInitializeGrid.C +++ b/src/enzo/Grid_CollapseTestInitializeGrid.C @@ -468,11 +468,14 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, * TimeUnits)); printf("Temperature = %f K\n", SphereTemperature[sphere]); printf("Mu = %f\n", mu); + printf("Initial cell width (Domain Width) = %e cm (%e cm)\n", CellWidth[0][0]*LengthUnits, + CellWidth[0][0]*LengthUnits*128.0); // Calculate speed of sound for this sphere VelocitySound[sphere] = sqrt((SphereTemperature[sphere] * Gamma * kboltz) / (mu * mh)) / VelocityUnits; printf("\nVelocitySound (km s^-1): %e\n", VelocitySound[sphere] * VelocityUnits/1e5); + } // ENDFOR sphere //exit(-99); for (k = 0; k < GridDimension[2]; k++) From b92e89fcadbb38f25b3b39de196cb0c3617d043c Mon Sep 17 00:00:00 2001 From: John Regan Date: Thu, 12 Nov 2020 12:16:48 +0000 Subject: [PATCH 077/115] interim commit --- src/enzo/ActiveParticle_SmartStar.C | 42 +++++++++++++++++++++++++++-- src/enzo/ActiveParticle_SmartStar.h | 3 +++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 3a3356ec6..7d04c3747 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -392,8 +392,6 @@ int ActiveParticleType_SmartStar::EvaluateFormation } // k if(data.NumberOfNewParticles > 0) { printf("Particles (%d) Created and done in %s\n", data.NumberOfNewParticles, __FUNCTION__); - fflush(stdout); - exit(-99); } #if CALCDIRECTPOTENTIAL delete [] PotentialField; @@ -746,10 +744,50 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, NumberOfGrids = GenerateGridArray(LevelArray, ThisLevel, &Grids); for (i = 0; i < nParticles; i++) { + + + /* + * Accretion is only allowed if it makes sense: + * 1. Black Holes in general are always allowed to accrete. + * 2. SMS can accrete if there is sufficient resolution to do so + * 3. PopIII stars can accrete if there is sufficient resolution + * 4. PopII stars never accrete + */ + + float MassInSolar = ParticleList[i]->ReturnMass()*MassConversion/SolarMass; AccretionRadius = static_cast(ParticleList[i])->AccretionRadius; int pclass = static_cast(ParticleList[i])->ParticleClass; + FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc + if(pclass == POPIII) { + /* + * We only accrete onto POPIII stars if our maximum + * spatial resolution is better than 1e-3 pc + */ + if(dx_pc > POPIII_RESOLUTION) //we don't have sufficient resolution + continue; + } + else if(pclass == SMS) { + /* + * We only accrete onto SMSs if our maximum + * spatial resolution is better than 1e-1 pc + */ + if(dx_pc > SMS_RESOLUTION) //we don't have sufficient resolution + continue; + + } + else if(pclass == BH) { + /* We always accrete onto BHs */ + ; + } + else if(pclass == POPII) { + /* We never accrete onto POPII stars */ + continue; + } + + printf("Accreting: Particle Class %d\n", pclass); + exit(-99); grid* FeedbackZone = ConstructFeedbackZone(ParticleList[i], int(AccretionRadius/dx), dx, Grids, NumberOfGrids, ALL_FIELDS); grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 2d56e6576..d7f79b469 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -35,6 +35,8 @@ #define NUMRADIATIONBINS 5 #define CRITICAL_ACCRETION_RATE 0.04 //Msolar/yr #define TIMEGAP 90 //yrs +#define POPIII_RESOLUTION 0.001 //pc +#define SMS_RESOLUTION 0.1 //pc /* Prototypes */ int GetUnits(float *DensityUnits, float *LengthUnits, @@ -46,6 +48,7 @@ static float R_ISCO(float a); #define POPIII 0 #define SMS 1 #define BH 2 +#define POPII 3 //Accretion Modes #define SPHERICAL_BONDI_HOYLE_FORMALISM 1 From 7cbf88eef90720a917eaeff02f98e570282bf44b Mon Sep 17 00:00:00 2001 From: John Regan Date: Tue, 8 Dec 2020 11:38:03 +0000 Subject: [PATCH 078/115] first pass through adding SNae and PopII formation to SmartStars --- src/enzo/ActiveParticleRoutines.C | 42 ++ src/enzo/ActiveParticle_SmartStar.C | 525 ++++++++++++++++-- src/enzo/ActiveParticle_SmartStar.h | 26 +- src/enzo/DetermineSEDParameters.C | 137 +++-- src/enzo/Grid.h | 17 +- .../Grid_ApplySmartStarParticleFeedback.C | 390 +++++++------ src/enzo/Grid_ApplySphericalFeedbackToGrid.C | 167 ++++++ .../Grid_CalculateSmartStarAccretionRate.C | 16 +- src/enzo/Grid_GetEnclosedMassInShell.C | 23 +- src/enzo/Grid_RemoveMassFromGrid.C | 164 ++++++ src/enzo/Grid_Shine.C | 2 +- src/enzo/Make.config.objects | 1 + src/enzo/RadiativeTransferInitialize.C | 6 + src/enzo/Star_FindFeedbackSphere.C | 5 +- 14 files changed, 1221 insertions(+), 300 deletions(-) create mode 100644 src/enzo/Grid_ApplySphericalFeedbackToGrid.C diff --git a/src/enzo/ActiveParticleRoutines.C b/src/enzo/ActiveParticleRoutines.C index 2994604d3..9436d668d 100644 --- a/src/enzo/ActiveParticleRoutines.C +++ b/src/enzo/ActiveParticleRoutines.C @@ -45,6 +45,7 @@ int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, FLOAT Time); int CosmologyComputeExpansionFactor(FLOAT time, FLOAT *a, FLOAT *dadt); +unsigned_long_int mt_random(void); /******************************* CONSTRUCTORS AND DESTRUCTOR @@ -498,3 +499,44 @@ int ActiveParticleType_SmartStar::CalculateAccretedAngularMomentum() return SUCCESS; } +void ActiveParticleType_SmartStar::AssignMassFromIMF() +{ + float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, + VelocityUnits, MassConversion; + GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, CurrentGrid->Time); + unsigned_long_int random_int = mt_random(); + const int max_random = (1<<16); + float x = (float) (random_int%max_random) / (float) (max_random); + float dm = log10(PopIIIUpperMassCutoff / PopIIILowerMassCutoff) / + (float) (IMF_TABLE_ENTRIES-1); + + /* (binary) search for the mass bin corresponding to the random + number */ + + int width = IMF_TABLE_ENTRIES/2; + int bin_number = IMF_TABLE_ENTRIES/2; + + while (width > 1) { + width /= 2; + if (x > IMFData[bin_number]) + bin_number += width; + else if (x < IMFData[bin_number]) + bin_number -= width; + else + break; + } + + this->Mass = PopIIILowerMassCutoff * POW(10.0, bin_number * dm); + + /* Adjust the lifetime (taken from the fit in Schaerer 2002) now we + know the stellar mass. It was set to the lifetime of a star with + M=PopIIILowerMassCutoff in pop3_maker.src as a placeholder. */ + + float logm = log10((float)this->Mass); + + // First in years, then convert to code units + this->RadiationLifetime = POW(10.0, (9.785 - 3.759*logm + 1.413*logm*logm - + 0.186*logm*logm*logm)) / (TimeUnits/yr_s); + +} diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 7d04c3747..2fb72a76a 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -21,7 +21,7 @@ #define JEANSLENGTHCALC 1 #define MASSTHRESHOLD 0.1 //Msolar in grid #define COOLING_TIME 0 - +#define NUMSSPARTICLETYPES 4 int DetermineSEDParameters(ActiveParticleType_SmartStar *SS,FLOAT Time, FLOAT dx); @@ -52,6 +52,7 @@ static void UpdateAccretionRadius(ActiveParticleType* ThisParticle, float newma FLOAT AccretionRadius, FLOAT dx, float avgtemp, float mass_units, float length_units); static float GetStellarRadius(float cmass, float accrate); +int StarParticlePopIII_IMFInitialize(void); int ActiveParticleType_SmartStar::InitializeParticleType() { @@ -97,6 +98,7 @@ int ActiveParticleType_SmartStar::InitializeParticleType() ah.push_back(new Handler("MassToBeEjected")); ah.push_back(new Handler("eta_disk")); ah.push_back(new Handler("beta_jet")); + ah.push_back(new Handler("InfluenceRadius")); ah.push_back(new Handler("epsilon_deltat")); ah.push_back(new Handler("mass_in_accretion_sphere")); ah.push_back(new ArrayHandler("Accreted_angmom", 0)); @@ -107,6 +109,12 @@ int ActiveParticleType_SmartStar::InitializeParticleType() //ah.push_back(new ArrayHandler("particle_acceleration_x", 0)); //ah.push_back(new ArrayHandler("particle_acceleration_y", 1)); //ah.push_back(new ArrayHandler("particle_acceleration_z", 2)); + + /* Initialize the IMF lookup table if requested and not defined */ + + if (PopIIIInitialMassFunction) + StarParticlePopIII_IMFInitialize(); + printf("SmartStar Initialisation complete\n"); fflush(stdout); return SUCCESS; } @@ -114,7 +122,13 @@ int ActiveParticleType_SmartStar::InitializeParticleType() int ActiveParticleType_SmartStar::EvaluateFormation (grid *thisgrid_orig, ActiveParticleFormationData &data) { - + //Particle Lifetimes + float SmartStarLifetime[4]; + SmartStarLifetime[0] = 2e6; //in yrs + SmartStarLifetime[1] = 2e6; //in yrs + SmartStarLifetime[2] = 1e20; //in yrs + SmartStarLifetime[3] = 2e7; //in yrs + // No need to do the rest if we're not on the maximum refinement level. if (data.level != MaximumRefinementLevel) return SUCCESS; @@ -153,7 +167,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation float *PotentialField = NULL; if(data.GravPotentialNum >= 0) PotentialField = thisGrid->BaryonField[data.GravPotentialNum]; - + FLOAT dx_pc = dx*data.LengthUnits/pc_cm; //in pc //printf("PotentialField = %p\n", PotentialField); const int offset[] = {1, GridDimension[0], GridDimension[0]*GridDimension[1]}; @@ -330,17 +344,59 @@ int ActiveParticleType_SmartStar::EvaluateFormation if(KineticEnergy + ThermalEnergy + GravitationalEnergy >= 0.0) continue; #endif - + /* + * Now we need to check the H2 fraction and the accretion rate now. + * If the H2fraction > PopIIIH2CriticalFraction then we are ok to form a PopIII star + * If H2fraction < PopIIIH2CriticalFraction then we should form a SMS only if the + * accretion rate onto the protostar (cell) is above a critical value + * + */ + float *cellvel = new float[MAX_DIMENSION]; + cellvel[0] = velx[index]; cellvel[1] = vely[index]; cellvel[2] = velz[index]; + float accrate = thisGrid->ConvergentMassFlow(data.DensNum, data.Vel1Num, + dx*ACCRETIONRADIUS, centralpos, + cellvel, -1, -1, -1); + ExtraDensity = density[index] - DensityThreshold; + /* We have the main conditions for SF now but we need to decide on the type of star + * that forms now. There are a few cases to consider: + * 1. If the metallicity is high then a cluster of PopII stars can form + * 2. If the metallicity is low but the H2 fraction is high then a PopIII star forms + * 3. If the metallicty is low and the H2 fraction is low but the accretion rate is high + * then a SMS can form + * We want to avoid spurious SF in a minihalo that is being heated (e.g. by LW or dynamical + * heating). Therefore we insist on the mass accretion criteria. If the mass accretion rate + * is low we don't allow the SMS pathway to trigger spurious SF. + */ + int stellar_type = -99999; + if(HasMetalField && data.TotalMetals[index] > PopIIIMetalCriticalFraction) { + stellar_type = POPII; + // float PopIIMass = StarClusterFormEfficiency*ExtraDensity*dx*dx*dx*ConverttoSolar; + // if(PopIIMass < StarClusterMinimumMass) + // continue; + } + else if(data.H2Fraction[index] > PopIIIH2CriticalFraction) { + stellar_type = POPIII; + } + else if(accrate*3.154e7*ConverttoSolar/data.TimeUnits > 1e-2) { + stellar_type = SMS; + } + + if(stellar_type < 0) + continue; ActiveParticleType_SmartStar *np = new ActiveParticleType_SmartStar(); data.NumberOfNewParticles++; data.NewParticles.insert(*np); - ExtraDensity = density[index] - DensityThreshold; - np->Mass = ExtraDensity; // Particle 'masses' are actually densities - np->type = np->GetEnabledParticleID(); - np->BirthTime = thisGrid->ReturnTime(); + + np->type = np->GetEnabledParticleID(); + /* + * Set Bithtime to -1.0 initially. If everything is ok and the + * star particle can form then we can update this to its correct value. + */ + np->BirthTime = -1.0; + np->ParticleClass = stellar_type; np->level = data.level; np->GridID = data.GridID; np->CurrentGrid = thisGrid; @@ -357,34 +413,37 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->vel[0] = apvel[0]; np->vel[1] = apvel[1]; np->vel[2] = apvel[2]; - + + if (HasMetalField) np->Metallicity = data.TotalMetals[index]; else np->Metallicity = 0.0; - np->oldmass = np->Mass; + np->TimeIndex = 0; //Start at 0 - we'll increment at the start of the update function. - for(int acc = 0; acc < NTIMES; acc++) { + np->AccretionRadius = dx*ACCRETIONRADIUS; + for(int acc = 1; acc < NTIMES; acc++) { np->AccretionRate[acc] = -11111.0; np->AccretionRateTime[acc] = -11111.0; } - np->AccretionRate[0] = -36.0; + + /* Calculate initial accretion rate onto cell */ + np->AccretionRate[0] = accrate; np->AccretionRateTime[0] = np->BirthTime; + + np->RadiationLifetime=SmartStarLifetime[np->ParticleClass]*yr_s/data.TimeUnits; + np->NotEjectedMass = 0.0; - np->AccretionRadius = dx*ACCRETIONRADIUS; - /* What kind of object did we just form? - * This depends only on the accretion rate for metal free systems - * For simplicity we assume the star is initially a super-massive - * protostar. If the accretion rate drops below a critical value - * (0.04 Msun/yr) for longer than 1000 yrs then the spectrum needs - * to change to a bluer spectrum. + /* The mass of the particles formed depends on the resolution and is handled + * in a call to `RemoveMassFromGridAfterFormation` which is called from + * `AfterEvolveLevel`. np->Mass is initally set here but can get overwritten + * RemoveMassFromGridAfterFormation. The cell values are not updated here but + * instead are updated in `RemoveMassFromGridAfterFormation`. + * We set the initial mass to zero so that merging works ok i.e. nothing spurious + * happens in this case. */ + np->Mass = 0.0; - np->ParticleClass = SMS; //1 - np->RadiationLifetime=SmartStarSMSLifetime*yr_s/data.TimeUnits; - np->NotEjectedMass = 0.0; - density[index] = DensityThreshold; - //printf("%s: Particle Created!\n", __FUNCTION__); //printf("%s: Total Mass in Accretion Region = %g Msolar (Threshold = %g)\n", __FUNCTION__, // TotalMass*ConverttoSolar, (double)MASSTHRESHOLD); } // i @@ -646,26 +705,21 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel dx = LevelArray[ThisParticle->level]->GridData->GetCellWidth(0,0); MassConversion = (double) (dx*dx*dx * mfactor); //Converts to Solar Masses source = ThisParticle->RadiationSourceInitialize(); - double PMass = 0.0; - if(POPIII == ThisParticle->ParticleClass) { - FLOAT Time = LevelArray[ThisParticle->level]->GridData->ReturnTime(); - float Age = (Time - ThisParticle->BirthTime)*TimeUnits/yr_s; - PMass = min(ThisParticle->Mass*MassConversion, 4000000.0); //cap lum mass at 40 Msolar -#if SSDEBUG - printf("%s: Star Mass set to %f Msolar from %f Msolar for Particle Class %d. " \ - "Age = %f kyrs\n", - __FUNCTION__, PMass, - ThisParticle->Mass*MassConversion, ThisParticle->ParticleClass, Age/1000.0); -#endif + double PMass = ThisParticle->Mass*MassConversion; + float ramptime = 0.0; + if(POPIII == ThisParticle->ParticleClass || + SMS == ThisParticle->ParticleClass) { + ramptime = yr_s * 1e4 / TimeUnits; + } + if(POPII == ThisParticle->ParticleClass) { + ramptime = yr_s * StarClusterMinDynamicalTime / TimeUnits; } - else - PMass = ThisParticle->Mass*MassConversion; - /* Call Function to return SED parameters */ - if(DetermineSEDParameters(ThisParticle, Time, dx) == FAIL) - return FAIL; + if(ThisParticle->DetermineSEDParameters(Time, dx) == FAIL) + return FAIL; source->LifeTime = RadiationLifetime; - source->Luminosity = (ThisParticle->LuminosityPerSolarMass * LConv) * PMass; + source->Luminosity = (ThisParticle->LuminosityPerSolarMass * LConv) * PMass; + source->RampTime = ramptime; source->EnergyBins = RadiationSEDNumberOfBins; source->Energy = new float[RadiationSEDNumberOfBins]; source->SED = new float[RadiationSEDNumberOfBins]; @@ -707,6 +761,395 @@ grid* ConstructFeedbackZone(ActiveParticleType* ThisParticle, int FeedbackRadius int DistributeFeedbackZone(grid* FeedbackZone, HierarchyEntry** Grids, int NumberOfGrids, int SendField); + +int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticles, + ActiveParticleList& ParticleList, + LevelHierarchyEntry *LevelArray[], int ThisLevel) +{ + + float StellarMasstoRemove = 0.0, CellDensityAfterFormation = 0.0; + /* Skip accretion if we're not on the maximum refinement level. + This should only ever happen right after creation and then + only in pathological cases where sink creation is happening at + the edges of two regions at the maximum refinement level */ + + if (ThisLevel < MaximumRefinementLevel) + return SUCCESS; + FLOAT Time = LevelArray[ThisLevel]->GridData->ReturnTime(); + float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, + VelocityUnits; + double MassUnits; + GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, Time); + MassUnits = DensityUnits * POW(LengthUnits,3); + + float tdyn_code = StarClusterMinDynamicalTime/(TimeUnits/yr_s); + for (int i = 0; i < nParticles; i++) { + grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); + + if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { + ActiveParticleType_SmartStar* SS; + SS = static_cast(ParticleList[i]); + + /* + * Only interested in newly formed particles + */ + if(SS->TimeIndex != 0) + continue; + + FLOAT dx = APGrid->CellWidth[0][0]; + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, + PressureUnits = 0, GEUnits = 0, VelUnits = 0; + double MassUnits = 1, CellVolume = 1; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, Time) == FAIL) { + ENZO_FAIL("Error in GetUnits."); + } + MassUnits = DensityUnits * POW(LengthUnits,3); + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + if (APGrid->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) + { + ENZO_FAIL("Error in IdentifyPhysicalQuantities."); + } + int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, + DINum, DIINum, HDINum; + if (MultiSpecies) + if (APGrid->IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, + HeIIINum, HMNum, H2INum, H2IINum, DINum, + DIINum, HDINum) == FAIL) { + ENZO_FAIL("Error in grid->IdentifySpeciesFields."); + } + FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc + float *density = APGrid->BaryonField[DensNum]; + int cellindex_x = (SS->pos[0] - APGrid->GridLeftEdge[0])/dx, + cellindex_y = (SS->pos[1] - APGrid->GridLeftEdge[1])/dx, + cellindex_z = (SS->pos[2] - APGrid->GridLeftEdge[2])/dx; + int cellindex = APGrid->GetIndex(cellindex_x, cellindex_y, cellindex_y); + float DensityThreshold = ActiveParticleDensityThreshold*mh/DensityUnits; + +#if JEANSREFINEMENT + bool JeansRefinement = false; + for (int method = 0; method < MAX_FLAGGING_METHODS; method++) + if (CellFlaggingMethod[method] == 6) + JeansRefinement = true; + if (JeansRefinement) { + int size = APGrid->GetGridSize(); + float *Temperature = new float[size](); + APGrid->ComputeTemperatureField(Temperature); + float CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : Temperature[cellindex]; + int JeansFactor = 1; //RefineByJeansLengthSafetyFactor + float JeansDensityUnitConversion = (Gamma*pi*kboltz) / (Mu*mh*GravConst); + float JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / + POW(LengthUnits*dx*JeansFactor,2); + JeansDensity /= DensityUnits; + DensityThreshold = min(DensityThreshold,JeansDensity); + } +#endif + + float ParticleDensity = density[cellindex] - DensityThreshold; + if(ParticleDensity < 0.0) + ENZO_FAIL("Particle Density is negative. Oh dear.\n"); + float newcelldensity = density[cellindex] - ParticleDensity; + if(SMS == SS->ParticleClass) { + + if(dx_pc <= SMS_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ + density[cellindex] = newcelldensity; + SS->BirthTime = APGrid->ReturnTime(); + SS->Mass = ParticleDensity; + SS->oldmass = SS->Mass; + return SUCCESS; + } + } + + else if(POPIII == SS->ParticleClass) { + if(dx_pc <= POPIII_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ + density[cellindex] = newcelldensity; + SS->BirthTime = APGrid->ReturnTime(); + SS->Mass = ParticleDensity; + SS->oldmass = SS->Mass; + return SUCCESS; + } + } + else if(POPII == SS->ParticleClass) { + /* + * For PopII stars we do this if the mass exceeds the minimum mass + */ + float PopIIMass = SS->Mass*dx*dx*dx*MassUnits/SolarMass; + if(PopIIMass > StarClusterMinimumMass) { + density[cellindex] = (1 - StarClusterFormEfficiency)*density[cellindex]; + SS->BirthTime = APGrid->ReturnTime(); + SS->Mass = StarClusterFormEfficiency*density[cellindex]; + SS->oldmass = SS->Mass; + return SUCCESS; + } + } + + /* + * If the formation mass is below a resolution based threshold + * Remove mass from grid and replace by a uniform density sphere which accounts for the + * subgrid ionisation that has taken place and accounts for the mass that should have been + * accreted. + */ + + /*********************************************************************** + + For star formation, we need to find a sphere with enough mass to + accrete. We step out by a cell width when searching. + + ***********************************************************************/ + + FLOAT Radius = 0.0; + int feedback_flag = -99999; + float MassEnclosed = 0; + float Metallicity2 = 0; + float Metallicity3 = 0; + float ColdGasMass = 0; + float AvgVelocity[MAX_DIMENSION]; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] = 0.0; + bool SphereTooSmall = true; + float ShellMass, ShellMetallicity2, ShellMetallicity3, ShellColdGasMass, + ShellVelocity[MAX_DIMENSION]; + while (SphereTooSmall) { + Radius += APGrid->CellWidth[0][0]; + bool IsSphereContained = SS->SphereContained(LevelArray, ThisLevel, Radius); + if (IsSphereContained == false) + break; + ShellMass = 0; + ShellMetallicity2 = 0; + ShellMetallicity3 = 0; + ShellColdGasMass = 0; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + ShellVelocity[dim] = 0.0; + + bool MarkedSubgrids = false; + LevelHierarchyEntry *Temp = NULL; + HierarchyEntry *Temp2 = NULL; + for (int l = ThisLevel; l < MAX_DEPTH_OF_HIERARCHY; l++) { + Temp = LevelArray[l]; + while (Temp != NULL) { + + /* Zero under subgrid field */ + + if (!MarkedSubgrids) { + Temp->GridData-> + ZeroSolutionUnderSubgrid(NULL, ZERO_UNDER_SUBGRID_FIELD); + Temp2 = Temp->GridHierarchyEntry->NextGridNextLevel; + while (Temp2 != NULL) { + Temp->GridData->ZeroSolutionUnderSubgrid(Temp2->GridData, + ZERO_UNDER_SUBGRID_FIELD); + Temp2 = Temp2->NextGridThisLevel; + } + } // ENDIF !MarkedSubgrids + + /* Sum enclosed mass in this grid */ + + Temp->GridData->GetEnclosedMassInShell(SS->pos, Radius-APGrid->CellWidth[0][0], Radius, + ShellMass, ShellMetallicity2, + ShellMetallicity3, + ShellColdGasMass, ShellVelocity, + -1); + + Temp = Temp->NextGridThisLevel; + + } // END: Grids + + } // END: level + + MarkedSubgrids = true; + float values[7]; + values[0] = ShellMetallicity2; + values[1] = ShellMetallicity3; + values[2] = ShellMass; + values[3] = ShellColdGasMass; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + values[4+dim] = ShellVelocity[dim]; + + LCAPERF_START("star_FindFeedbackSphere_Sum"); + CommunicationAllSumValues(values, 7); + LCAPERF_STOP("star_FindFeedbackSphere_Sum"); + + ShellMetallicity2 = values[0]; + ShellMetallicity3 = values[1]; + ShellMass = values[2]; + ShellColdGasMass = values[3]; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + ShellVelocity[dim] = values[4+dim]; + + MassEnclosed += ShellMass; + ColdGasMass += ShellColdGasMass; + // Must first make mass-weighted, then add shell mass-weighted + // (already done in GetEnclosedMassInShell) velocity and + // metallicity. We divide out the mass after checking if mass is + // non-zero. + Metallicity2 = Metallicity2 * (MassEnclosed - ShellMass) + ShellMetallicity2; + Metallicity3 = Metallicity3 * (MassEnclosed - ShellMass) + ShellMetallicity3; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] = AvgVelocity[dim] * (MassEnclosed - ShellMass) + + ShellVelocity[dim]; + + if (MassEnclosed == 0) { + IsSphereContained = false; + return SUCCESS; + } + + Metallicity2 /= MassEnclosed; + Metallicity3 /= MassEnclosed; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] /= MassEnclosed; + + + /* Now remove mass based on star particle type */ + + /* Convert CGS density to Msolar */ + double ConversiontoMsolar = 4*pi/3.0 * pow(Radius*LengthUnits, 3)/SolarMass; + if(POPIII == SS->ParticleClass) { + SS->AssignMassFromIMF(); + SphereTooSmall = MassEnclosed < (2*ParticleDensity*DensityUnits*ConversiontoMsolar); + // to make the total mass PopIIIStarMass + StellarMasstoRemove = ParticleDensity*DensityUnits*ConversiontoMsolar; // [Msolar] + } + else if(SMS == SS->ParticleClass) { + /* I think we need a heavy seed IMF here */ + SphereTooSmall = MassEnclosed < (2*ParticleDensity*DensityUnits*ConversiontoMsolar); + StellarMasstoRemove = ParticleDensity*DensityUnits*ConversiontoMsolar; //[Msolar] + } + else if(POPII == SS->ParticleClass) { + float AvgDensity = (float) + (double(SolarMass * MassEnclosed) / + double(4*pi/3.0 * pow(Radius*LengthUnits, 3))); /* cgs density */ + float DynamicalTime = sqrt((3.0 * pi) / (32.0 * GravConst * AvgDensity)) / + TimeUnits; + float ColdGasFraction = ColdGasMass / MassEnclosed; + StellarMasstoRemove = ColdGasFraction * StarClusterFormEfficiency * MassEnclosed; //[Msolar] + SphereTooSmall = DynamicalTime < tdyn_code; + + } + // Remove the stellar mass from the sphere and distribute the + // gas evenly in the sphere since this is what will happen once + // the I-front passes through it. + + CellDensityAfterFormation = (float) + (double(SolarMass * (MassEnclosed - StellarMasstoRemove)) / + double(4.0*pi/3.0 * POW(Radius*LengthUnits, 3)) / + DensityUnits); /* converted to code density */ + + } /* end while(SphereTooSmall) */ +#ifdef NOT_NECESSARY + /* Don't allow the sphere to be too large (2x leeway) */ + const float epsMass = 9.0; + float eps_tdyn; + if ((PopIII == SS->ParticleClass || SMS == SS->ParticleClass) && LevelArray[level+1] != NULL) { + if (MassEnclosed > (1.0+epsMass)*(StellarMasstoRemove)) { + SphereContained = FALSE; + return SUCCESS; + } + } + else if (PopII == SS->ParticleClass && LevelArray[level+1] != NULL) { + eps_tdyn = sqrt(1.0+epsMass) * tdyn_code; + if (DynamicalTime > eps_tdyn) { + SphereContained = FALSE; + return SUCCESS; + } + } +#endif + + /* The Radius of influence is set by the sphere over which we had to + * loop to find sufficient enclosed mass. + */ + float InfluenceRadius = Radius; + /* Update cell information */ + int index = 0; + FLOAT delx = 0.0, dely = 0.0, delz = 0.0, radius2 = 0.0, DomainWidth[MAX_DIMENSION]; + int MetallicityField = FALSE; + int SNColourNum, MetalNum, Metal2Num, MBHColourNum, Galaxy1ColourNum, + Galaxy2ColourNum, MetalIaNum, MetalIINum; + + if (APGrid->IdentifyColourFields(SNColourNum, Metal2Num, MetalIaNum, + MetalIINum, MBHColourNum, Galaxy1ColourNum, + Galaxy2ColourNum) == FAIL) + ENZO_FAIL("Error in grid->IdentifyColourFields.\n"); + + MetalNum = max(Metal2Num, SNColourNum); + MetallicityField = (MetalNum > 0) ? TRUE : FALSE; + float metallicity = 0.0; + for (int dim = 0; dim < APGrid->GridRank; dim++) + DomainWidth[dim] = DomainRightEdge[dim] - DomainLeftEdge[dim]; + for (int k = 0; k < APGrid->GridDimension[2]; k++) { + + delz = APGrid->CellLeftEdge[2][k] + 0.5*APGrid->CellWidth[2][k] - SS->pos[2]; + int sz = sign(delz); + delz = fabs(delz); + delz = min(delz, DomainWidth[2]-delz); + + for (int j = 0; j < APGrid->GridDimension[1]; j++) { + + dely = APGrid->CellLeftEdge[1][j] + 0.5*APGrid->CellWidth[1][j] - SS->pos[1]; + int sy = sign(dely); + dely = fabs(dely); + dely = min(dely, DomainWidth[1]-dely); + + for (int i = 0; i < APGrid->GridDimension[0]; i++, index++) { + float ionizedFraction = 0.999; // Assume an initial HII region + delx = APGrid->CellLeftEdge[0][i] + 0.5*APGrid->CellWidth[0][i] - SS->pos[0]; + int sx = sign(delx); + delx = fabs(delx); + delx = min(delx, DomainWidth[0]-delx); + + radius2 = delx*delx + dely*dely + delz*delz; + if (radius2 <= InfluenceRadius*InfluenceRadius) { + + radius2 = max(radius2, 0.0625*APGrid->CellWidth[0][i]*APGrid->CellWidth[0][i]); // (0.25*dx)^2 + + if (MetallicityField == TRUE) + metallicity = APGrid->BaryonField[MetalNum][index] / APGrid->BaryonField[DensNum][index]; + else + metallicity = 0; + float fh = CoolData.HydrogenFractionByMass; + float fhz = fh * (1-metallicity); + float fhez = (1-fh) * (1-metallicity); + SS->BirthTime = APGrid->ReturnTime(); + double ConversiontoMsolar = 4*pi/3.0 * pow(InfluenceRadius*LengthUnits, 3)/SolarMass; + SS->Mass = StellarMasstoRemove/ConversiontoMsolar; //g/cm^3 + SS->Mass /= DensityUnits; //convert to code density + SS->oldmass = SS->Mass; + APGrid->BaryonField[DensNum][index] = CellDensityAfterFormation; + + if (MultiSpecies) { + APGrid->BaryonField[DeNum][index] = APGrid->BaryonField[DensNum][index] * ionizedFraction; + APGrid->BaryonField[HINum][index] = APGrid->BaryonField[DensNum][index] * (1-ionizedFraction) * fhz; + APGrid->BaryonField[HIINum][index] = APGrid->BaryonField[DensNum][index] * ionizedFraction * fhz; + APGrid->BaryonField[HeINum][index] = APGrid->BaryonField[DensNum][index] * (1-ionizedFraction) * fhez; + APGrid->BaryonField[HeIINum][index] = APGrid->BaryonField[DensNum][index] * (ionizedFraction) * fhez; + APGrid->BaryonField[HeIIINum][index] = 1e-10 * APGrid->BaryonField[DensNum][index]; + } + if (MultiSpecies > 1) { + APGrid->BaryonField[HMNum][index] = tiny_number; + APGrid->BaryonField[H2INum][index] = tiny_number; + APGrid->BaryonField[H2IINum][index] = tiny_number; + } + if (MultiSpecies > 2) { + APGrid->BaryonField[DINum][index] = APGrid->BaryonField[DensNum][index] * fh * + CoolData.DeuteriumToHydrogenRatio * (1-ionizedFraction); + APGrid->BaryonField[DIINum][index] = APGrid->BaryonField[DensNum][index] * fh * + CoolData.DeuteriumToHydrogenRatio * ionizedFraction; + APGrid->BaryonField[HDINum][index] = tiny_number * APGrid->BaryonField[DensNum][index]; + } + + } // END if inside radius + + } // END i-direction + } // END j-direction + } // END k-direction + + + + } /*This Processor */ + } /* End loop over APs */ + return SUCCESS; +} int ActiveParticleType_SmartStar::Accrete(int nParticles, ActiveParticleList& ParticleList, FLOAT AccretionRadius, FLOAT dx, diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index d7f79b469..98f9f6658 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -33,7 +33,7 @@ #define MAXACCRETIONRADIUS 128 /* Times the minimum cell width */ #define ACCRETIONRADIUS 4 #define NUMRADIATIONBINS 5 -#define CRITICAL_ACCRETION_RATE 0.04 //Msolar/yr +#define CRITICAL_ACCRETION_RATE 0.001 //Msolar/yr (Haemerlee et al (2018)) #define TIMEGAP 90 //yrs #define POPIII_RESOLUTION 0.001 //pc #define SMS_RESOLUTION 0.1 //pc @@ -45,11 +45,13 @@ int GetUnits(float *DensityUnits, float *LengthUnits, static FLOAT Dist(FLOAT *tempPos, FLOAT *tempPos1); static float R_ISCO(float a); //Particle Classes + #define POPIII 0 #define SMS 1 #define BH 2 #define POPII 3 + //Accretion Modes #define SPHERICAL_BONDI_HOYLE_FORMALISM 1 #define ANGULAR_MOMENTUM_LIMITED_ACCRETION 4 @@ -71,6 +73,7 @@ class ActiveParticleType_SmartStar : public ActiveParticleType mass_in_accretion_sphere = 0; epsilon_deltat = 1.0; beta_jet = 0.0; + InfluenceRadius = 0.0; for(int i = 0; i < 3; i++) { Accreted_angmom[i] = 0.0; @@ -135,6 +138,8 @@ class ActiveParticleType_SmartStar : public ActiveParticleType int TopGridDims[], int ActiveParticleID); + + static int SmartStarParticleFeedback( int nParticles, ActiveParticleList& ParticleList, @@ -145,9 +150,11 @@ class ActiveParticleType_SmartStar : public ActiveParticleType static int CreateParticle(grid *thisgrid_orig, ActiveParticleFormationData &supp_data, int particle_index); static int InitializeParticleType(); - void SmartMerge(ActiveParticleType_SmartStar *a); + void SmartMerge(ActiveParticleType_SmartStar *a); + void AssignMassFromIMF(); int CalculateAccretedAngularMomentum(); int SmartStarAddFeedbackSphere(); + int DetermineSEDParameters(FLOAT Time, FLOAT dx); ENABLED_PARTICLE_ID_ACCESSOR bool IsARadiationSource(FLOAT Time); @@ -170,7 +177,9 @@ class ActiveParticleType_SmartStar : public ActiveParticleType FLOAT dx, LevelHierarchyEntry *LevelArray[], int ThisLevel); - + static int RemoveMassFromGridAfterFormation(int nParticles, + ActiveParticleList& ParticleList, + LevelHierarchyEntry *LevelArray[], int ThisLevel); static float EjectedMassThreshold; FLOAT AccretionRadius; // in units of CellWidth on the maximum refinement level static int RadiationParticle; @@ -191,6 +200,7 @@ class ActiveParticleType_SmartStar : public ActiveParticleType float NotEjectedMass, eta_disk, mass_in_accretion_sphere, MassToBeEjected; float beta_jet, epsilon_deltat; float Accreted_angmom[MAX_DIMENSION]; + float InfluenceRadius; static std::vector AttributeHandlers; }; @@ -350,6 +360,16 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( FLOAT dx = (DomainRightEdge[0] - DomainLeftEdge[0]) / (MetaData->TopGridDims[0]*POW(FLOAT(RefineBy),FLOAT(MaximumRefinementLevel))); + /* Remove mass from grid from newly formed particles */ + RemoveMassFromGridAfterFormation(nParticles, ParticleList, + LevelArray, ThisLevel); + + + //thisGrid->RemoveMassFromGridAfterFormation(np->pos, np->ParticleClass, np->AccretionRadius, + // np->Mass, + // index, DensityThreshold, ExtraDensity); + + /* Do Merging */ ActiveParticleList MergedParticles; diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index 3143f55bf..b90bbcfd5 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -126,13 +126,13 @@ double BHArray[100][6] = {{8.536889e+47, 1.444555e-04, 3.879133e-05, 2.669210e-0 static int CalculateArrayIndex(float Mass, float AccRate); extern "C" void FORTRAN_NAME(stellar)(float *smdot, float *dt_enzo, float *slum, float *rad); -int DetermineSEDParameters(ActiveParticleType_SmartStar *SS, FLOAT Time, FLOAT dx) +int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) { if((SmartStarBHRadiativeFeedback == FALSE) && (SmartStarStellarRadiativeFeedback == FALSE)) { for(int bin = 0; bin < NUMRADIATIONBINS; bin++) { - SS->RadiationEnergyBins[bin] = 0.0; - SS->RadiationSED[bin] = 0.0; + this->RadiationEnergyBins[bin] = 0.0; + this->RadiationSED[bin] = 0.0; } return SUCCESS; } @@ -143,55 +143,120 @@ int DetermineSEDParameters(ActiveParticleType_SmartStar *SS, FLOAT Time, FLOAT d &TimeUnits, &VelocityUnits, Time); MassUnits = DensityUnits * POW(LengthUnits,3); double MassConversion = (float) (dx*dx*dx * double(MassUnits)); //convert to g from a density - double ParticleMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses + double _mass = this->ReturnMass()*MassConversion/SolarMass; //In solar masses #if STELLAR static float ptime=0.0; - if(SS->ParticleClass == POPIII || SS->ParticleClass == SMS) { - SS->RadiationLifetime = 1e6*yr_s/TimeUnits; //Code Time - SS->LuminosityPerSolarMass = 6.696798e49/40.0; //In physical units + if(this->ParticleClass == POPIII || this->ParticleClass == SMS) { + this->RadiationLifetime = 1e6*yr_s/TimeUnits; //Code Time + this->LuminosityPerSolarMass = 6.696798e49/40.0; //In physical units float smdot, dt_enzo, slum, rad; - smdot=SS->AccretionRate[SS->TimeIndex]*MassUnits/TimeUnits; + smdot=this->AccretionRate[this->TimeIndex]*MassUnits/TimeUnits; dt_enzo=Time-ptime; if(ptime>0.0){ FORTRAN_NAME(stellar)(&smdot, &dt_enzo, &slum, &rad); - SS->LuminosityPerSolarMass = slum/ParticleMass; + this->LuminosityPerSolarMass = slum/ParticleMass; } else{ - SS->LuminosityPerSolarMass = 1e10; + this->LuminosityPerSolarMass = 1e10; } } ptime = Time; return SUCCESS; #endif - /* - * The PopIII values are taken from Schaerer et al. 2002 Table 4. - * Luminosity is NOT in ergs/s but in photons/s - */ - if(SS->ParticleClass == POPIII) { - SS->RadiationLifetime = SmartStarSMSLifetime*yr_s/TimeUnits; //Code Time - SS->LuminosityPerSolarMass = 6.696798e49/40.0; //In physical units + + float x = log10((float)(_mass)); + float x2 = x*x; + if(this->ParticleClass == POPIII) { + + float E[NUMRADIATIONBINS] = {2.0, 12.8, 28.0, 30.0, 58.0}; + float Q[NUMRADIATIONBINS] = {0.0, 0.0, 0.0, 0.0, 0.0}; + for(int bin = 0; bin < NUMRADIATIONBINS; bin++) { - SS->RadiationEnergyBins[bin] = PopIIIEnergyBins[bin]; - SS->RadiationSED[bin] = PopIIISEDFracBins[bin]; + this->RadiationEnergyBins[bin] = E[bin]; + } + + _mass = max(min((float)(_mass), 500), 5); + if (_mass > 9 && _mass <= 500) { + Q[0] = 0.0; //IR + Q[1] = pow(10.0, 44.03 + 4.59*x - 0.77*x2); //LW + Q[2] = pow(10.0, 43.61 + 4.9*x - 0.83*x2); //HI + Q[3] = pow(10.0, 42.51 + 5.69*x - 1.01*x2); //HeI + if(PopIIIHeliumIonization) + Q[4] = pow(10.0, 26.71 + 18.14*x - 3.58*x2); //HeII + else + Q[4] = 0.0; + + } else if (_mass > 5 && _mass <= 9) { + Q[0] = 0.0; //IR + Q[1] = pow(10.0, 44.03 + 4.59*x - 0.77*x2); //LW + Q[2] = pow(10.0, 39.29 + 8.55*x); //HI + Q[3] = pow(10.0, 29.24 + 18.49*x); //HeI + if(PopIIIHeliumIonization) + Q[4] = pow(10.0, 26.71 + 18.14*x - 3.58*x2); //HeII + else + Q[4] = 0.0; + } // ENDELSE + else { + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) Q[bin] = 0.0; + } + + + float QTotal = 0; + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) { + this->RadiationSED[bin] = Q[bin]; + } + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) QTotal += Q[bin]; + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) Q[bin] /= QTotal; + this->LuminosityPerSolarMass = QTotal/_mass; } + else if(this->ParticleClass == POPII) { + float EnergyFractionLW = 1.288; + float EnergyFractionHeI = 0.2951; + float EnergyFractionHeII = 2.818e-4; + + float E[NUMRADIATIONBINS] = {2.0, 12.8, 21.62, 30.0, 60.0}; + float Q[NUMRADIATIONBINS] = {0.0, 0.0, 0.0, 0.0, 0.0}; + float Qbase = StarClusterIonizingLuminosity * _mass; + Q[0] = 0.0; //IR + Q[1] = EnergyFractionLW * Qbase; //LW + if (StarClusterHeliumIonization) { + Q[2] = Qbase*(1.0 - EnergyFractionHeI - EnergyFractionHeII); //HI + Q[3] = EnergyFractionHeI * Qbase; //HeI + Q[4] = EnergyFractionHeII * Qbase; //HeII + } else { + Q[3] = 0.0; + Q[4] = 0.0; + } + + float QTotal = 0; + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) { + this->RadiationSED[bin] = Q[bin]; + } + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) QTotal += Q[bin]; + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) Q[bin] /= QTotal; + this->LuminosityPerSolarMass = QTotal/_mass; + + } + + /* * For the SMS spectrum I assume a blackbody with an effective * temperature of 6000K. * Luminosity is NOT in ergs/s but in photons/s */ - else if (SS->ParticleClass == SMS) { - SS->RadiationLifetime = SmartStarSMSLifetime*yr_s/TimeUnits; //Code Times - SS->LuminosityPerSolarMass = 1.4e51/500.0; + else if (this->ParticleClass == SMS) { + + this->LuminosityPerSolarMass = 1.4e51/500.0; /* Ideally we call SLUG here. Hardcoded for now */ for(int bin = 0; bin < NUMRADIATIONBINS; bin++) { - SS->RadiationEnergyBins[bin] = SMSEnergyBins[bin]; - SS->RadiationSED[bin] = SMSSEDFracBins[bin]; + this->RadiationEnergyBins[bin] = SMSEnergyBins[bin]; + this->RadiationSED[bin] = SMSSEDFracBins[bin]; } } @@ -202,17 +267,16 @@ int DetermineSEDParameters(ActiveParticleType_SmartStar *SS, FLOAT Time, FLOAT d * The values are hardcoded into the table above and valid for black * hole masses from 1e0 to 1e9 and accretion rates from 1e-7 to 1e2 */ - else if(SS->ParticleClass == BH && SmartStarBHRadiativeFeedback == TRUE) { - SS->RadiationLifetime = 1e14*yr_s/TimeUnits; //code time - double accrate = (SS->AccretionRate[SS->TimeIndex]*(MassUnits/SolarMass)/TimeUnits)*yr_s; //Msolar/yr - double BHMass = ParticleMass; - float epsilon = SS->eta_disk; + else if(this->ParticleClass == BH && SmartStarBHRadiativeFeedback == TRUE) { + double accrate = (this->AccretionRate[this->TimeIndex]*(MassUnits/SolarMass)/TimeUnits)*yr_s; //Msolar/yr + double BHMass = _mass; + float epsilon = this->eta_disk; double eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(epsilon*clight*sigma_thompson); // g/s eddrate = eddrate*yr_s/SolarMass; //in Msolar/yr accrate = max(accrate, 1e-6); BHMass = min(BHMass, 1.0); int arrayindex = CalculateArrayIndex(BHMass, accrate); - SS->LuminosityPerSolarMass = BHArray[arrayindex][0]/BHMass; //erg/s/msun + this->LuminosityPerSolarMass = BHArray[arrayindex][0]/BHMass; //erg/s/msun if(SmartStarSuperEddingtonAdjustment == TRUE) { if(accrate > eddrate) { @@ -226,26 +290,26 @@ int DetermineSEDParameters(ActiveParticleType_SmartStar *SS, FLOAT Time, FLOAT d //printf("LuminosityPerSolarMass in Superdd Case is %e erg/s/msun\n", LSuperEdd/ParticleMass); epsilon = LSuperEdd/(accrate_cgs*clight*clight); //printf("epsilon updated to %f\n", epsilon); - SS->LuminosityPerSolarMass = LSuperEdd/BHMass; + this->LuminosityPerSolarMass = LSuperEdd/BHMass; } } /* Employ some ramping to stop numerical meltdown */ - float Age = (Time - SS->ReturnBirthTime())*TimeUnits/yr_s; + float Age = (Time - this->ReturnBirthTime())*TimeUnits/yr_s; //printf("%s: BH Age = %e yrs\n", __FUNCTION__, Age); if(Age < RAMPAGE) { float ramp = (Age/RAMPAGE); //printf("%s: ramp = %g\n", __FUNCTION__, ramp); - SS->LuminosityPerSolarMass = SS->LuminosityPerSolarMass*ramp; + this->LuminosityPerSolarMass = this->LuminosityPerSolarMass*ramp; } /* Use values from the BHArray to set the SED Fractions */ for(int bin = 0; bin < NUMRADIATIONBINS; bin++) { - SS->RadiationEnergyBins[bin] = BHEnergyBins[bin]; - SS->RadiationSED[bin] = BHArray[arrayindex][bin+1]; + this->RadiationEnergyBins[bin] = BHEnergyBins[bin]; + this->RadiationSED[bin] = BHArray[arrayindex][bin+1]; } } else { - fprintf(stderr, "%s: Particle Class = %d but no Radiative Feedback\n", __FUNCTION__, SS->ParticleClass); + fprintf(stderr, "%s: Particle Class = %d but no Radiative Feedback\n", __FUNCTION__, this->ParticleClass); return SUCCESS; } @@ -286,3 +350,4 @@ float MadauFit(float a, float mdot, float medddot) return L; } + diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index b6559645e..c789fd53a 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -2802,10 +2802,11 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int GetEnclosedMass(FLOAT star_pos[], float radius, float &mass, float &metallicity, float &coldgas_mass, float AvgVelocity[], float &OneOverRSquaredSum); - int GetEnclosedMassInShell(Star *star, float radius0, float radius1, + int GetEnclosedMassInShell(FLOAT *pos, float radius0, float radius1, float &mass, float &metallicity2, float &metallicity3, - float &coldgas_mass, float AvgVelocity[]); + float &coldgas_mass, float AvgVelocity[], + int feedback_flag); int RemoveParticle(int ID, bool disable=false); @@ -2865,6 +2866,13 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], float *AccretedMass, float *DeltaV, FLOAT KernelRadius, FLOAT SumOfWeights, float MaxAccretionRate); + int RemoveMassFromGridAfterFormation(FLOAT* starpos, int ParticleClass, + FLOAT AccretionRadius, + float particle_mass, + int cellindex, + float newcelldensity, + float original_pmass); + int GetVorticityComponent(FLOAT *pos, FLOAT *vorticity); float CenAccretionRate(float density, FLOAT AccretionRadius, FLOAT *pos, float *vel, float mparticle); @@ -2883,7 +2891,10 @@ int zEulerSweep(int j, int NumberOfSubgrids, fluxes *SubgridFluxes[], int ApplyGalaxyParticleGravity(ActiveParticleType** ThisParticle); int ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle); - + int ApplySphericalFeedbackToGrid(ActiveParticleType** ThisParticle, + float EjectaDenity, + float EjectaThermalEnergy, + float EjectaMetalDensity); //------------------------------------------------------------------------ // Radiative transfer methods that don't fit in the TRANSFER define //------------------------------------------------------------------------ diff --git a/src/enzo/Grid_ApplySmartStarParticleFeedback.C b/src/enzo/Grid_ApplySmartStarParticleFeedback.C index 859199933..2ad7c8c29 100644 --- a/src/enzo/Grid_ApplySmartStarParticleFeedback.C +++ b/src/enzo/Grid_ApplySmartStarParticleFeedback.C @@ -34,12 +34,17 @@ #define IMPOSETHRESHOLD 1 #define THRESHOLDFRACTION 1 //Solarmasses ejected per jet event #define OPENING_ANGLE pi/360.0 //pi/3.9 + +int search_lower_bound(float *arr, float value, int low, int high, + int total); + int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ /* Return if this doesn't involve us */ if (MyProcessorNumber != ProcessorNumber) return SUCCESS; - + if(SmartStarFeedback == FALSE) + return SUCCESS; if(SmartStarBHFeedback == FALSE) return SUCCESS; if (SmartStarBHJetFeedback == FALSE && SmartStarBHThermalFeedback == FALSE) { @@ -47,8 +52,21 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ } ActiveParticleType_SmartStar *SS = static_cast(* ThisParticle); - if(SS->ParticleClass != BH) - return SUCCESS; + const float PISNLowerMass = 140, PISNUpperMass = 260; + const float TypeIILowerMass = 11, TypeIIUpperMass = 40.1; + + // From Nomoto et al. (2006) + const float HypernovaMetals[] = {3.36, 3.53, 5.48, 7.03, 8.59}; // SolarMass + const float HypernovaEnergy[] = {10, 10, 20, 25, 30}; // 1e51 erg + const float CoreCollapseMetals[] = {3.63, 4.41, 6.71, 8.95, 11.19}; // SolarMass + const float CoreCollapseEnergy[] = {1, 1, 1, 1, 1}; // 1e51 erg + + const float SNExplosionMass[] = {19.99, 25, 30, 35, 40.01}; // SolarMass + const float *SNExplosionMetals = (PopIIIUseHypernova ==TRUE) ? + HypernovaMetals : CoreCollapseMetals; + const float *SNExplosionEnergy = (PopIIIUseHypernova ==TRUE) ? + HypernovaEnergy : CoreCollapseEnergy; + /* Check whether the cube that circumscribes the accretion zone intersects with this grid */ FLOAT *pos = SS->ReturnPosition(); @@ -66,13 +84,15 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ /* Set the units. */ float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1, + TimeUnits = 1, VelocityUnits = 1, PressureUnits = 0, GEUnits = 0, VelUnits = 0; + double MassUnits = 1.0; if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, this->ReturnTime()) == FAIL) { ENZO_FAIL("Error in GetUnits."); } MassUnits = DensityUnits * POW(LengthUnits,3); + double MassConversion = (double) (dx*dx*dx * MassUnits); //convert to g int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, Vel3Num, TENum) == FAIL) { @@ -91,43 +111,114 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ } if(SS->AccretionRate[SS->TimeIndex] <= 0.0) { float mdot = SS->AccretionRate[SS->TimeIndex]; //CodeMass/CodeTime - float MassConversion = (float) (dx*dx*dx * double(MassUnits)); //convert to g + float accrate = mdot*MassUnits/(SolarMass*TimeUnits)*3.154e7; //in Msolar/s printf("%s: AccretionRate = %e Msolar/yr %e (code)\n", __FUNCTION__, accrate, SS->AccretionRate[SS->TimeIndex]); printf("%s: Returning until accretion rate is updated\n", __FUNCTION__); return SUCCESS; } + + /*********************************************************************** + SUPERNOVAE + ************************************************************************/ + + // Assume that the remnant is still in the free expansion stage and + // hasn't had any radiative losses. In this case, the ejecta will + // be at 3/4 the radius of the shock front (see Ostriker & McKee + // 1988 or Tenorio-Tagle 1996). + + float ionizedFraction = 0.999; // Assume supernova is ionized + FLOAT Time = this->ReturnTime(); + if(SS->ParticleClass == POPIII) + { + float Age = Time - SS->BirthTime; + + if(SS->RadiationLifetime < Age) {/* Star needs to go supernovae and change type */ + double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ + double SNEnergy, HeliumCoreMass, Delta_SF, MetalMass; + FLOAT Radius = PopIIISupernovaRadius * pc_cm / LengthUnits; + float StarLevelCellWidth = this->CellWidth[0][0]; + Radius = max(Radius, 3.5*StarLevelCellWidth); + float EjectaVolume = 4.0/3.0 * pi * pow(Radius*LengthUnits, 3); + float EjectaDensity = StellarMass * SolarMass / EjectaVolume / DensityUnits; + float EjectaMetalDensity = 0.0, EjectaThermalEnergy = 0.0; + // pair-instability SNe + if (StellarMass >= PISNLowerMass && StellarMass <= PISNUpperMass) { + HeliumCoreMass = (13./24.) * (StellarMass - 20); + SNEnergy = (5.0 + 1.304 * (HeliumCoreMass - 64)) * 1e51; + EjectaMetalDensity = HeliumCoreMass * SolarMass / EjectaVolume / + DensityUnits; + } + // Type II SNe + else if (StellarMass >= TypeIILowerMass && StellarMass <= TypeIIUpperMass) { + if (StellarMass < 20.0) { // Normal Type II + SNEnergy = 1e51; + MetalMass = 0.1077 + 0.3383 * (StellarMass - 11.0); // Fit to Nomoto+06 + } else { // Hypernova (should we add the "failed" SNe?) + int bin = search_lower_bound((float*)SNExplosionMass, StellarMass, 0, 5, 5); + float frac = (SNExplosionMass[bin+1] - StellarMass) / + (SNExplosionMass[bin+1] - SNExplosionMass[bin]); + SNEnergy = 1e51 * (SNExplosionEnergy[bin] + + frac * (SNExplosionEnergy[bin+1] - SNExplosionEnergy[bin])); + MetalMass = (SNExplosionMetals[bin] + + frac * (SNExplosionMetals[bin+1] - SNExplosionMetals[bin])); + } + EjectaMetalDensity = MetalMass * SolarMass / EjectaVolume / DensityUnits; + } + EjectaThermalEnergy = SNEnergy / (StellarMass * SolarMass) / VelocityUnits / + VelocityUnits; + + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + EjectaMetalDensity); + + } + } + + if(SS->ParticleClass == POPII) + { + float Age = Time - SS->BirthTime; + float StarLevelCellWidth = this->CellWidth[0][0]; + FLOAT Radius = StarClusterSNRadius * pc_cm / LengthUnits; + if (Radius < 2*StarLevelCellWidth) { + Radius = 2*StarLevelCellWidth; + } + float dtForThisStar = this->ReturnTimeStep(); + double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ + double Delta_SF = StarMassEjectionFraction * StellarMass * dtForThisStar * + TimeUnits / (16.0*Myr_s); + float EjectaVolume = 4.0/3.0 * pi * pow(Radius*LengthUnits, 3); + float EjectaDensity = Delta_SF * SolarMass / EjectaVolume / DensityUnits; + float EjectaMetalDensity = EjectaDensity * StarMetalYield; + float EjectaThermalEnergy = StarClusterSNEnergy / SolarMass / + (VelocityUnits * VelocityUnits); + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + EjectaMetalDensity); + } /*********************************************************************** MBH_THERMAL ************************************************************************/ - int CellsModified = 0; + // Similar to Supernova, but here we assume the followings: // EjectaDensity = 0.0 // EjectaMetalDensity = 0.0 + float EjectaDensity = 0.0, EjectaMetalDensity = 0.0; // The unit of EjectaThermalEnergy = ergs/cm^3, not ergs/g if (SmartStarBHThermalFeedback == TRUE) { float epsilon = SS->eta_disk; - FLOAT outerRadius2 = POW(1.2*rad, 2.0); + /* find mdot */ float mdot = SS->AccretionRate[SS->TimeIndex]; //CodeMass/CodeTime - - /* Debug */ - float MassConversion = (float) (dx*dx*dx * double(MassUnits)); //convert to g float accrate = mdot*MassUnits/(SolarMass*TimeUnits)*3.154e7; //in Msolar/yr float mdot_cgs = mdot*MassUnits/TimeUnits; //g/s //printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); printf("%s: AccretionRate = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, accrate, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); /*end Debug*/ - float newGE = 0.0, oldGE = 0.0; - float maxGE = MAX_TEMPERATURE / (TemperatureUnits * (Gamma-1.0) * 0.6); - - FLOAT radius2 = 0.0; + float EjectaVolumeCGS = 4.0/3.0 * PI * pow(SS->AccretionRadius*LengthUnits, 3); float EjectaVolume = 4.0/3.0 * PI * pow(SS->AccretionRadius, 3); - printf("%s: OuterRadius = %e\n", __FUNCTION__, sqrt(outerRadius2)*LengthUnits/pc_cm); - CellsModified = 0; + float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses float eddrate = 4*M_PI*GravConst*BHMass*mh/(SS->eta_disk*clight*sigma_thompson); // Msolar/s eddrate = eddrate*3.154e7; //in Msolar/yr @@ -164,203 +255,109 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ printf("BH Age = %f yrs, ramp = %f\n", Age, Age/(float)RAMPTIME); EjectaThermalEnergy *= Age/(float)RAMPTIME; } - for (int k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { - for (int j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { - int index = GRIDINDEX_NOGHOST(GridStartIndex[0],j,k); - for (int i = GridStartIndex[0]; i <= GridEndIndex[0]; i++, index++) { - - radius2 = POW(CellLeftEdge[0][i] + 0.5*dx - pos[0],2.0) + - POW(CellLeftEdge[1][j] + 0.5*dx - pos[1],2.0) + - POW(CellLeftEdge[2][k] + 0.5*dx - pos[2],2.0); - if (radius2 < outerRadius2) { - float r1 = sqrt(radius2) / rad; - float norm = 0.98; - float ramp = norm*(0.5 - 0.5 * tanh(10.0*(r1-1.0))); - /* 1/1.2^3 factor to dilute the density since we're - depositing a uniform ejecta in a sphere of 1.2*radius - without a ramp. The ramp is only applied to the - energy*density factor. */ - float factor = 0.578704; - - float Density = this->BaryonField[DensNum][index]; - /* Get specific energy */ - if (GENum >= 0 && DualEnergyFormalism) { - - /* When injected energy is uniform throughout the volume; - EjectaThermalEnergy in EnergyUnits/VolumeUnits */ - oldGE = this->BaryonField[GENum][index]; - newGE = (Density * this->BaryonField[GENum][index] + - ramp * factor * EjectaThermalEnergy) / Density; - - newGE = min(newGE, maxGE); - //printf("%s: Energy Before = %e\t Energy injected = %e\t Increase = %e\n", __FUNCTION__, - // oldGE,ramp * factor * EjectaThermalEnergy / Density, (newGE - oldGE)/oldGE); - fflush(stdout); - - this->BaryonField[GENum][index] = newGE; - this->BaryonField[TENum][index] = newGE; - - for (int dim = 0; dim < GridRank; dim++) - this->BaryonField[TENum][index] += - 0.5 * this->BaryonField[Vel1Num+dim][index] * - this->BaryonField[Vel1Num+dim][index]; - - //printf("%s: Increase in GE energy is %e\n", __FUNCTION__, (newGE - oldGE)/oldGE); - - } else { - - newGE = (Density * this->BaryonField[TENum][index] + - ramp * factor * EjectaThermalEnergy) / Density; - - newGE = min(newGE, maxGE); - this->BaryonField[TENum][index] = newGE; - - } //end if(GENum >= 0 && DualEnergyFormalism) - - /* Update species and colour fields */ - - float fh = CoolData.HydrogenFractionByMass; - float fhez = (1-fh); - float ionizedFraction = 0.999; - if (MultiSpecies) { - this->BaryonField[DeNum][index] = - this->BaryonField[DensNum][index] * ionizedFraction; - this->BaryonField[HINum][index] = - this->BaryonField[DensNum][index] * fh * (1-ionizedFraction); - this->BaryonField[HIINum][index] = - this->BaryonField[DensNum][index] * fh * ionizedFraction; - this->BaryonField[HeINum][index] = - 0.5*this->BaryonField[DensNum][index] * fhez * (1-ionizedFraction); - this->BaryonField[HeIINum][index] = - 0.5*this->BaryonField[DensNum][index] * fhez * (1-ionizedFraction); - this->BaryonField[HeIIINum][index] = - this->BaryonField[DensNum][index] * fhez * ionizedFraction; - } -#ifdef IDONTSEEWHYTHESEELEMENTSAREEFFECTED - if (MultiSpecies > 1) { - this->BaryonField[HMNum][index] = tiny_number * this->BaryonField[DensNum][index]; - this->BaryonField[H2INum][index] = - tiny_number * this->BaryonField[DensNum][index]; - this->BaryonField[H2IINum][index] = - tiny_number * this->BaryonField[DensNum][index]; - } - if (MultiSpecies > 2) { - this->BaryonField[DINum][index] = this->BaryonField[DensNum][index] * fh * - CoolData.DeuteriumToHydrogenRatio * (1-ionizedFraction); - this->BaryonField[DIINum][index] = this->BaryonField[DensNum][index] * fh * - CoolData.DeuteriumToHydrogenRatio * ionizedFraction; - this->BaryonField[HDINum][index] = - tiny_number * this->BaryonField[DensNum][index]; - } -#endif - CellsModified++; - - } // END if inside radius - } // END i-direction - } // END j-direction - } // END k-direction - //printf("CellsModified = %d\n", CellsModified); - } // END MBH_THERMAL - - CellsModified = 0; - /*********************************************************************** - MBH_JETS - ************************************************************************/ + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + EjectaMetalDensity); - // Inject bipolar jets along the direction of the angular momentum - // vector L of the MBH particle (angular momentum accreted thus far) - // or along the z-axis - Ji-hoon Kim, Nov.2009 - int i = 0, j = 0, k = 0; - #define MAX_SUPERCELL_NUMBER 1000 - int SUPERCELL = 1; //2 for supercell of 5 cells wide = 5^3 - int ind_cell_inside[MAX_SUPERCELL_NUMBER], ind_cell_edge[MAX_SUPERCELL_NUMBER]; - float nx_cell_edge[MAX_SUPERCELL_NUMBER], ny_cell_edge[MAX_SUPERCELL_NUMBER], - nz_cell_edge[MAX_SUPERCELL_NUMBER], anglefactor[MAX_SUPERCELL_NUMBER] = {0}; - int n_cell_inside = 0, n_cell_edge = 0, ibuff = NumberOfGhostZones; - int ii = 0, jj = 0, kk = 0, r_s = 0, ic = 0, sign = 0; - float m_cell_inside = 0.0, m_cell_edge = 0.0; - float L_x, L_y, L_z, L_s, nx_L = 0.0, ny_L = 0.0, nz_L = 0.0, costheta = cos(OPENING_ANGLE); - float SSMass = SS->ReturnMass(); - float totalenergybefore = 0.0, totalenergyafter = 0.0, totalenergyadded = 0.0; - float sumkeadded = 0.0; - - if (SmartStarBHJetFeedback == FALSE || SS->MassToBeEjected*MassUnits/SolarMass < 1e-10) { - return SUCCESS; } + if(SmartStarBHJetFeedback == TRUE) { + /*********************************************************************** + MBH_JETS + ************************************************************************/ + + // Inject bipolar jets along the direction of the angular momentum + // vector L of the MBH particle (angular momentum accreted thus far) + // or along the z-axis - Ji-hoon Kim, Nov.2009 + int i = 0, j = 0, k = 0; +#define MAX_SUPERCELL_NUMBER 1000 + int SUPERCELL = 1; //2 for supercell of 5 cells wide = 5^3 + int ind_cell_inside[MAX_SUPERCELL_NUMBER], ind_cell_edge[MAX_SUPERCELL_NUMBER]; + float nx_cell_edge[MAX_SUPERCELL_NUMBER], ny_cell_edge[MAX_SUPERCELL_NUMBER], + nz_cell_edge[MAX_SUPERCELL_NUMBER], anglefactor[MAX_SUPERCELL_NUMBER] = {0}; + int n_cell_inside = 0, n_cell_edge = 0, ibuff = NumberOfGhostZones; + int ii = 0, jj = 0, kk = 0, r_s = 0, ic = 0, sign = 0; + float m_cell_inside = 0.0, m_cell_edge = 0.0; + float L_x, L_y, L_z, L_s, nx_L = 0.0, ny_L = 0.0, nz_L = 0.0, costheta = cos(OPENING_ANGLE); + float SSMass = SS->ReturnMass(); + float totalenergybefore = 0.0, totalenergyafter = 0.0, totalenergyadded = 0.0; + float sumkeadded = 0.0; + + if (SmartStarBHJetFeedback == FALSE || SS->MassToBeEjected*MassUnits/SolarMass < 1e-10) { + return SUCCESS; + } - /* i, j, k are the number of cells from the edge of the grid to the smartstar*/ - i = (int)((pos[0] - this->CellLeftEdge[0][0]) / dx); - j = (int)((pos[1] - this->CellLeftEdge[1][0]) / dx); - k = (int)((pos[2] - this->CellLeftEdge[2][0]) / dx); - - /* Note that we need to inject feedback only for the finest grid the SS belongs to */ - - if (i < ibuff || i > this->GridDimension[0]-ibuff-1 || - j < ibuff || j > this->GridDimension[1]-ibuff-1 || - k < ibuff || k > this->GridDimension[2]-ibuff-1 || + /* i, j, k are the number of cells from the edge of the grid to the smartstar*/ + i = (int)((pos[0] - this->CellLeftEdge[0][0]) / dx); + j = (int)((pos[1] - this->CellLeftEdge[1][0]) / dx); + k = (int)((pos[2] - this->CellLeftEdge[2][0]) / dx); + + /* Note that we need to inject feedback only for the finest grid the SS belongs to */ + + if (i < ibuff || i > this->GridDimension[0]-ibuff-1 || + j < ibuff || j > this->GridDimension[1]-ibuff-1 || + k < ibuff || k > this->GridDimension[2]-ibuff-1 || this == NULL || SS->level < MaximumRefinementLevel) { fprintf(stdout, "grid::AddFS: MBH_JETS - MBH doesn't belong to this grid.\n"); return SUCCESS; - } + } - float MassConversion = (float) (dx*dx*dx * double(MassUnits)); //convert to g - /* find mdot */ - float mdot = SS->AccretionRate[SS->TimeIndex]; - float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses - float eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(SS->eta_disk*clight*sigma_thompson); // g/s - eddrate = eddrate*3.154e7/SolarMass; //in Msolar/yr - - float AccretionRate = mdot*MassUnits/(SolarMass*TimeUnits); //in Msolar/s - /* - * Now in the case where we are subgriding the accretion formalism - * re-calculate the actual accretion rate and check if we are in the correct band - */ - //AccretionRate *= SS->epsilon_deltat; - - /* Debug */ - printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\t Ratio = %f\n", __FUNCTION__, - eddrate, AccretionRate*3.154e7, AccretionRate*3.154e7/eddrate); - printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); - printf("%s: AccretionRate (*deltat) = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, - AccretionRate*3.154e7, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); - float MassEjected = SS->NotEjectedMass + SS->MassToBeEjected; //code mass - - SS->NotEjectedMass = MassEjected; + /* find mdot */ + float mdot = SS->AccretionRate[SS->TimeIndex]; + float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses + float eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(SS->eta_disk*clight*sigma_thompson); // g/s + eddrate = eddrate*3.154e7/SolarMass; //in Msolar/yr + + float AccretionRate = mdot*MassUnits/(SolarMass*TimeUnits); //in Msolar/s + /* + * Now in the case where we are subgriding the accretion formalism + * re-calculate the actual accretion rate and check if we are in the correct band + */ + //AccretionRate *= SS->epsilon_deltat; + + /* Debug */ + printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\t Ratio = %f\n", __FUNCTION__, + eddrate, AccretionRate*3.154e7, AccretionRate*3.154e7/eddrate); + printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); + printf("%s: AccretionRate (*deltat) = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, + AccretionRate*3.154e7, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); + float MassEjected = SS->NotEjectedMass + SS->MassToBeEjected; //code mass + + + SS->NotEjectedMass = MassEjected; #if IMPOSETHRESHOLD #if SSFEED_DEBUG - printf("SSFEED_DEBUG: %s: Mass Accumulated thus far = %e Msolar (Threshold = %e Msolar)\n", - __FUNCTION__, SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); -#endif - if (SS->NotEjectedMass*MassUnits/SolarMass <= SS->EjectedMassThreshold) { - fprintf(stdout, "grid::AddFS: MBH_JETS - accumulated mass (%f Msolar) not passed threshold (%f Msolar).\n", - SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); - return SUCCESS; - } + printf("SSFEED_DEBUG: %s: Mass Accumulated thus far = %e Msolar (Threshold = %e Msolar)\n", + __FUNCTION__, SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); #endif - - if(AccretionRate*3.154e7/eddrate < 1e-30 || AccretionRate*3.154e7/eddrate > 1.0) - { - printf("%s: AccrateionRateRatio = %f. We are in the right band to release jets\n", __FUNCTION__, - AccretionRate*3.154e7/eddrate); - } - else - { - printf("%s: AccrateionRateRatio = %f. No jets this time\n", __FUNCTION__, - AccretionRate*3.154e7/eddrate); + if (SS->NotEjectedMass*MassUnits/SolarMass <= SS->EjectedMassThreshold) { + fprintf(stdout, "grid::AddFS: MBH_JETS - accumulated mass (%f Msolar) not passed threshold (%f Msolar).\n", + SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); return SUCCESS; } - /*end Debug*/ - +#endif + + if(AccretionRate*3.154e7/eddrate < 1e-30 || AccretionRate*3.154e7/eddrate > 1.0) + { + printf("%s: AccrateionRateRatio = %f. We are in the right band to release jets\n", __FUNCTION__, + AccretionRate*3.154e7/eddrate); + } + else + { + printf("%s: AccrateionRateRatio = %f. No jets this time\n", __FUNCTION__, + AccretionRate*3.154e7/eddrate); + return SUCCESS; + } + /*end Debug*/ + #if SSFEED_DEBUG - - printf("SSFEED_DEBUG: %s: Mass Accreted = %e Msolar\t Mass to be Ejected = %e Msolar\n", - __FUNCTION__, mdot*dt*MassUnits/SolarMass, MassEjected*MassUnits/SolarMass); + + printf("SSFEED_DEBUG: %s: Mass Accreted = %e Msolar\t Mass to be Ejected = %e Msolar\n", + __FUNCTION__, mdot*dt*MassUnits/SolarMass, MassEjected*MassUnits/SolarMass); #endif - + if (i < ibuff+SUPERCELL || i > this->GridDimension[0]-ibuff-SUPERCELL-1 || j < ibuff+SUPERCELL || j > this->GridDimension[1]-ibuff-SUPERCELL-1 || k < ibuff+SUPERCELL || k > this->GridDimension[2]-ibuff-SUPERCELL-1) { @@ -650,7 +647,6 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ this->BaryonField[HDINum][index] *= increase; } - CellsModified++; } #if IMPOSETHRESHOLD @@ -668,7 +664,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ SS->NotEjectedMass = 0.0; #endif - CellsModified = 0; + } return SUCCESS; } diff --git a/src/enzo/Grid_ApplySphericalFeedbackToGrid.C b/src/enzo/Grid_ApplySphericalFeedbackToGrid.C new file mode 100644 index 000000000..6fbad3f5a --- /dev/null +++ b/src/enzo/Grid_ApplySphericalFeedbackToGrid.C @@ -0,0 +1,167 @@ +/*********************************************************************** +/ +/ Algorithm for applying thermal feedback to the temporary grid of an active particle +/ +/ written by: John Regan +/ date: December, 2020 +/ +/ note: Based on methods originally implemented by Stephen Skory +************************************************************************/ +#include "preincludes.h" + +#include "ErrorExceptions.h" +#include "macros_and_parameters.h" +#include "typedefs.h" +#include "global_data.h" +#include "units.h" +#include "Fluxes.h" +#include "GridList.h" +#include "phys_constants.h" +#include "ExternalBoundary.h" +#include "Grid.h" +#include "Hierarchy.h" +#include "ActiveParticle.h" +#include "phys_constants.h" +#include "ActiveParticle_SmartStar.h" +#define MAX_TEMPERATURE 1e8 + +int grid::ApplySphericalFeedbackToGrid(ActiveParticleType** ThisParticle, + float EjectaDensity, + float EjectaThermalEnergy, + float EjectaMetalDensity) { + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, + PressureUnits = 0, GEUnits = 0, VelUnits = 0; + double MassUnits = 1.0; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, this->ReturnTime()) == FAIL) { + ENZO_FAIL("Error in GetUnits."); + } + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) { + ENZO_FAIL("Error in IdentifyPhysicalQuantities.\n"); + } + int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, + DINum, DIINum, HDINum; + if (MultiSpecies) + if (this->IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, + HeIIINum, HMNum, H2INum, H2IINum, DINum, + DIINum, HDINum) == FAIL) { + ENZO_FAIL("Error in grid->IdentifySpeciesFields."); + } + int SNColourNum, MetalNum, Metal2Num, MBHColourNum, Galaxy1ColourNum, + Galaxy2ColourNum, MetalIaNum, MetalIINum; + int MetallicityField = FALSE; + + if (this->IdentifyColourFields(SNColourNum, Metal2Num, MetalIaNum, + MetalIINum, MBHColourNum, Galaxy1ColourNum, + Galaxy2ColourNum) == FAIL) + ENZO_FAIL("Error in grid->IdentifyColourFields.\n"); + + MetalNum = max(Metal2Num, SNColourNum); + MetallicityField = (MetalNum > 0) ? TRUE : FALSE; + ActiveParticleType_SmartStar *SS = static_cast(* ThisParticle); + FLOAT radius = SS->InfluenceRadius; + float MetalRadius = 1.0; + FLOAT MetalRadius2 = radius * radius * MetalRadius * MetalRadius; + float dx = float(this->CellWidth[0][0]); + FLOAT *pos = SS->ReturnPosition(); + FLOAT outerRadius2 = POW(1.2*radius, 2.0); + float maxGE = MAX_TEMPERATURE / (TemperatureUnits * (Gamma-1.0) * 0.6); + float delta_fz = 0.0; + for (int k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { + for (int j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { + int index = GRIDINDEX_NOGHOST(GridStartIndex[0],j,k); + for (int i = GridStartIndex[0]; i <= GridEndIndex[0]; i++, index++) { + + FLOAT radius2 = POW(CellLeftEdge[0][i] + 0.5*dx - pos[0],2.0) + + POW(CellLeftEdge[1][j] + 0.5*dx - pos[1],2.0) + + POW(CellLeftEdge[2][k] + 0.5*dx - pos[2],2.0); + if (radius2 < outerRadius2) { + float r1 = sqrt(radius2) / radius; + float norm = 0.98; + float ramp = norm*(0.5 - 0.5 * tanh(10.0*(r1-1.0))); + /* 1/1.2^3 factor to dilute the density since we're + depositing a uniform ejecta in a sphere of 1.2*radius + without a ramp. The ramp is only applied to the + energy*density factor. */ + float factor = 0.578704; + + float OldDensity = this->BaryonField[DensNum][index]; + BaryonField[DensNum][index] += factor*EjectaDensity; + /* Get specific energy */ + if (GENum >= 0 && DualEnergyFormalism) { + + /* When injected energy is uniform throughout the volume; + EjectaThermalEnergy in EnergyUnits/VolumeUnits */ + float oldGE = this->BaryonField[GENum][index]; + float newGE = (OldDensity * this->BaryonField[GENum][index] + + ramp * factor * EjectaThermalEnergy * EjectaDensity) + / BaryonField[DensNum][index] ; + + newGE = min(newGE, maxGE); + //printf("%s: Energy Before = %e\t Energy injected = %e\t Increase = %e\n", __FUNCTION__, + // oldGE,ramp * factor * EjectaThermalEnergy / Density, (newGE - oldGE)/oldGE); + fflush(stdout); + + this->BaryonField[GENum][index] = newGE; + this->BaryonField[TENum][index] = newGE; + + for (int dim = 0; dim < GridRank; dim++) + this->BaryonField[TENum][index] += + 0.5 * this->BaryonField[Vel1Num+dim][index] * + this->BaryonField[Vel1Num+dim][index]; + + //printf("%s: Increase in GE energy is %e\n", __FUNCTION__, (newGE - oldGE)/oldGE); + + } else { + + float newGE = (OldDensity * this->BaryonField[TENum][index] + + ramp * factor * EjectaDensity * EjectaThermalEnergy) / + BaryonField[DensNum][index]; + + newGE = min(newGE, maxGE); + this->BaryonField[TENum][index] = newGE; + + } //end if(GENum >= 0 && DualEnergyFormalism) + + /* Update species and colour fields */ + if (MetallicityField == TRUE && radius2 <= MetalRadius2) + delta_fz = EjectaMetalDensity / OldDensity; + else + delta_fz = 0.0; + float increase = BaryonField[DensNum][index] / OldDensity - delta_fz; + + if (MultiSpecies) { + BaryonField[DeNum][index] *= increase; + BaryonField[HINum][index] *= increase; + BaryonField[HIINum][index] *= increase; + BaryonField[HeINum][index] *= increase; + BaryonField[HeIINum][index] *= increase; + BaryonField[HeIIINum][index] *= increase; + } + if (MultiSpecies > 1) { + BaryonField[HMNum][index] *= increase; + BaryonField[H2INum][index] *= increase; + BaryonField[H2IINum][index] *= increase; + } + if (MultiSpecies > 2) { + BaryonField[DINum][index] *= increase; + BaryonField[DIINum][index] *= increase; + BaryonField[HDINum][index] *= increase; + } + + if (MetallicityField == TRUE) + BaryonField[MetalNum][index] += EjectaMetalDensity; + + /* MBHColour injected */ + if (MBHColourNum > 0) + BaryonField[MBHColourNum][index] += factor*EjectaDensity; + + } // END if inside radius + } // END i-direction + } // END j-direction + } // END k-direction + return SUCCESS; +} diff --git a/src/enzo/Grid_CalculateSmartStarAccretionRate.C b/src/enzo/Grid_CalculateSmartStarAccretionRate.C index a45e7fee7..1b7cd9007 100644 --- a/src/enzo/Grid_CalculateSmartStarAccretionRate.C +++ b/src/enzo/Grid_CalculateSmartStarAccretionRate.C @@ -522,13 +522,17 @@ float grid::ConvergentMassFlow(int DensNum, int Vel1Num, FLOAT AccretionRadius, float accrate = 0.0; if(radialvelocity < 0) { #if USEBOUNDEDNESS - float ke = pow(gasvelx[index], 2.0) + pow(gasvely[index], 2.0) + pow(gasvelz[index], 2.0); - float te = BaryonField[GENum][index]; - FLOAT dist = sqrt(radius2); - float ge = Gcode*SSmass/dist; - if(ke+te-ge<0) { /*Only add if we are bound */ - continue; + if(SSMass > 0.0){ + float ke = pow(gasvelx[index], 2.0) + pow(gasvely[index], 2.0) + pow(gasvelz[index], 2.0); + float te = BaryonField[GENum][index]; + FLOAT dist = sqrt(radius2); + float ge = Gcode*SSmass/dist; + if(ke+te-ge<0) { /*Only add if we are bound */ + continue; + } } + else + ; #endif numincells++; accrate = density[index]*relposmag*relposmag*radialvelocity; diff --git a/src/enzo/Grid_GetEnclosedMassInShell.C b/src/enzo/Grid_GetEnclosedMassInShell.C index 465b21217..4e580ac7f 100644 --- a/src/enzo/Grid_GetEnclosedMassInShell.C +++ b/src/enzo/Grid_GetEnclosedMassInShell.C @@ -29,10 +29,11 @@ int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, FLOAT Time); -int grid::GetEnclosedMassInShell(Star *star, float radius0, float radius1, +int grid::GetEnclosedMassInShell(FLOAT *pos, float radius0, float radius1, float &mass, float &metallicity2, float &metallicity3, - float &coldgas_mass, float AvgVelocity[]) + float &coldgas_mass, float AvgVelocity[], + int feedback_flag) { if (MyProcessorNumber != ProcessorNumber) @@ -46,10 +47,10 @@ int grid::GetEnclosedMassInShell(Star *star, float radius0, float radius1, bool inside_outer = true, contained_inner = true; for (dim = 0; dim < GridRank; dim++) { - contained_inner &= (GridLeftEdge[dim] >= star->pos[dim] - radius0 && - GridRightEdge[dim] <= star->pos[dim] + radius0); - inside_outer &= !(star->pos[dim] - radius1 > GridRightEdge[dim] || - star->pos[dim] + radius1 < GridLeftEdge[dim]); + contained_inner &= (GridLeftEdge[dim] >= pos[dim] - radius0 && + GridRightEdge[dim] <= pos[dim] + radius0); + inside_outer &= !(pos[dim] - radius1 > GridRightEdge[dim] || + pos[dim] + radius1 < GridLeftEdge[dim]); } if (!inside_outer || contained_inner) @@ -83,7 +84,7 @@ int grid::GetEnclosedMassInShell(Star *star, float radius0, float radius1, int Vel1Num = FindField(Velocity1, FieldType, NumberOfBaryonFields); int GENum = FindField(InternalEnergy, FieldType, NumberOfBaryonFields); int ColorField = FindField(ForbiddenRefinement, FieldType, NumberOfBaryonFields); - if ((ColorField < 0) && (star->ReturnFeedbackFlag() == COLOR_FIELD)) + if ((ColorField < 0) && (feedback_flag == COLOR_FIELD)) ENZO_FAIL("Couldn't Find Color Field!"); /* Find metallicity field and set flag. */ @@ -132,10 +133,10 @@ int grid::GetEnclosedMassInShell(Star *star, float radius0, float radius1, radius1_2 = radius1 * radius1; for (k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { - delz = CellLeftEdge[2][k] + 0.5*CellWidth[2][k] - star->pos[2]; + delz = CellLeftEdge[2][k] + 0.5*CellWidth[2][k] - pos[2]; delz = min(delz, DomainWidth[2]-delz); for (j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { - dely = CellLeftEdge[1][j] + 0.5*CellWidth[1][j] - star->pos[1]; + dely = CellLeftEdge[1][j] + 0.5*CellWidth[1][j] - pos[1]; dely = min(dely, DomainWidth[1]-dely); index = (k*GridDimension[1] + j)*GridDimension[0] + GridStartIndex[0]; for (i = GridStartIndex[0]; i <= GridEndIndex[0]; i++, index++) { @@ -143,7 +144,7 @@ int grid::GetEnclosedMassInShell(Star *star, float radius0, float radius1, if (BaryonField[NumberOfBaryonFields][index] != 0.0) continue; - delx = CellLeftEdge[0][i] + 0.5*CellWidth[0][i] - star->pos[0]; + delx = CellLeftEdge[0][i] + 0.5*CellWidth[0][i] - pos[0]; delx = min(delx, DomainWidth[0]-delx); dr2 = delx*delx + dely*dely + delz*delz; @@ -151,7 +152,7 @@ int grid::GetEnclosedMassInShell(Star *star, float radius0, float radius1, if (dr2 >= radius0_2 && dr2 < radius1_2) { gasmass = BaryonField[DensNum][index] * MassConversion; mass += gasmass; - if (star->ReturnFeedbackFlag() == COLOR_FIELD) + if (feedback_flag == COLOR_FIELD) BaryonField[ColorField][index] = BaryonField[DensNum][index]; for (dim = 0; dim < GridRank; dim++) AvgVelocity[dim] += BaryonField[Vel1Num+dim][index] * gasmass; diff --git a/src/enzo/Grid_RemoveMassFromGrid.C b/src/enzo/Grid_RemoveMassFromGrid.C index d1f9ba0f2..ade5af590 100644 --- a/src/enzo/Grid_RemoveMassFromGrid.C +++ b/src/enzo/Grid_RemoveMassFromGrid.C @@ -467,3 +467,167 @@ int grid::RemoveMassFromGrid(ActiveParticleType* ThisParticle, return SUCCESS; } + +#ifdef DONOTCOMPILE +/* + * Remove mass from Grid after AP formation. + * The mass should be removed in a resolution dependent way. + */ + +int grid::RemoveMassFromGridAfterFormation(FLOAT* starpos, + int ParticleClass, + FLOAT AccretionRadius, + float particle_mass, + int cellindex, + float newcelldensity, + float original_pmass) + +{ + FLOAT dx = CellWidth[0][0]; + float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, + TimeUnits = 1, VelocityUnits = 1, + PressureUnits = 0, GEUnits = 0, VelUnits = 0; + double MassUnits = 1, CellVolume = 1; + if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, Time) == FAIL) { + ENZO_FAIL("Error in GetUnits."); + } + MassUnits = DensityUnits * POW(LengthUnits,3); + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) + { + ENZO_FAIL("Error in IdentifyPhysicalQuantities."); + } + FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc + float *density = BaryonField[DensNum]; + if(SMS == ParticleClass) { + + if(dx_pc <= SMS_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ + density[cellindex] = newcelldensity; + return SUCCESS; + } + } + + else if(POPIII == ParticleClass) { + if(dx_pc <= POPIII_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ + density[cellindex] = newcelldensity; + return SUCCESS; + } + } + else if(POPII == ParticleClass) { + /* + * For PopII stars we do this if the mass exceeds the minimum mass + */ + float PopIIMass = particle_mass*dx*dx*dx*MassUnits/SolarMass; + if(PopIIMass > StarClusterMinimumMass) { + density[cellindex] = (1 - StarClusterFormEfficiency)*density[cellindex]; + return SUCCESS; + } + } + + + + /* + * If the formation mass is below a resolution based threshold + * Remove mass from grid and replace by a uniform density sphere which accounts for the + * subgrid ionisation that has taken place and accounts for the mass that should have been + * accreted. + */ + + /*********************************************************************** + + For star formation, we need to find a sphere with enough mass to + accrete. We step out by a cell width when searching. + + ***********************************************************************/ + + FLOAT Radius = AccretionRadius; + int feedback_flag = -99999; + float MassEnclosed = 0; + float Metallicity2 = 0; + float Metallicity3 = 0; + float ColdGasMass = 0; + float AvgVelocity[MAX_DIMENSION]; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] = 0.0; + bool SphereTooSmall = true; + float ShellMass, ShellMetallicity2, ShellMetallicity3, ShellColdGasMass, + ShellVelocity[MAX_DIMENSION]; + while (SphereTooSmall) { + Radius += CellWidth[0][0]; + SphereContained = this->SphereContained(LevelArray, level, Radius); + if (SphereContained == FALSE) + break; + + + ShellMass = 0; + ShellMetallicity2 = 0; + ShellMetallicity3 = 0; + ShellColdGasMass = 0; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + ShellVelocity[dim] = 0.0; + + /* Sum enclosed mass in this grid */ + this->GetEnclosedMassInShell(starpos, Radius-CellWidth[0][0], Radius, + ShellMass, ShellMetallicity2, + ShellMetallicity3, + ShellColdGasMass, ShellVelocity, + feedback_flag); + + values[0] = ShellMetallicity2; + values[1] = ShellMetallicity3; + values[2] = ShellMass; + values[3] = ShellColdGasMass; + for (dim = 0; dim < MAX_DIMENSION; dim++) + values[4+dim] = ShellVelocity[dim]; + + LCAPERF_START("star_FindFeedbackSphere_Sum"); + CommunicationAllSumValues(values, 7); + LCAPERF_STOP("star_FindFeedbackSphere_Sum"); + + ShellMetallicity2 = values[0]; + ShellMetallicity3 = values[1]; + ShellMass = values[2]; + ShellColdGasMass = values[3]; + for (dim = 0; dim < MAX_DIMENSION; dim++) + ShellVelocity[dim] = values[4+dim]; + + MassEnclosed += ShellMass; + ColdGasMass += ShellColdGasMass; + + // Must first make mass-weighted, then add shell mass-weighted + // (already done in GetEnclosedMassInShell) velocity and + // metallicity. We divide out the mass after checking if mass is + // non-zero. + Metallicity2 = Metallicity2 * (MassEnclosed - ShellMass) + ShellMetallicity2; + Metallicity3 = Metallicity3 * (MassEnclosed - ShellMass) + ShellMetallicity3; + for (dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] = AvgVelocity[dim] * (MassEnclosed - ShellMass) + + ShellVelocity[dim]; + + if (MassEnclosed == 0) { + return SUCCESS; + } + + Metallicity2 /= MassEnclosed; + Metallicity3 /= MassEnclosed; + for (dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] /= MassEnclosed; + + + + + if(POPII == ParticleClass) { + + ; + + + } + SphereTooSmall = false; + } + + + return SUCCESS; +} +#endif diff --git a/src/enzo/Grid_Shine.C b/src/enzo/Grid_Shine.C index 923a1c5ea..f99aba8c7 100644 --- a/src/enzo/Grid_Shine.C +++ b/src/enzo/Grid_Shine.C @@ -151,7 +151,7 @@ int grid::Shine(RadiationSourceEntry *RadiationSource) if(RS->Energy[ebin] <= 13.6 && RadiativeTransferOpticallyThinH2 == 1) continue; - /* If we slected no ionising radiation */ + /* If we selected no ionising radiation */ if(RadiativeTransferNoIonisingRadiation == 1 && RS->Energy[ebin] >= 13.6) continue; diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index 3567f8754..08dddbed0 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -359,6 +359,7 @@ OBJS_CONFIG_LIB = \ Grid_ApplyGalaxyParticleFeedback.o \ Grid_ApplyGalaxyParticleGravity.o \ Grid_ApplySmartStarParticleFeedback.o \ + Grid_ApplySphericalFeedbackToGrid.o \ Grid_ApplyTimeAction.o \ Grid_AveragedVelocityAtCell.o \ Grid_CalculateAngularMomentum.o \ diff --git a/src/enzo/RadiativeTransferInitialize.C b/src/enzo/RadiativeTransferInitialize.C index 63636720c..dae308f3c 100644 --- a/src/enzo/RadiativeTransferInitialize.C +++ b/src/enzo/RadiativeTransferInitialize.C @@ -206,6 +206,12 @@ int RadiativeTransferInitialize(char *ParameterFile, TypesToAdd[FieldsToAdd++] = Metallicity; AddedMetallicity = true; } + if (StarClusterUseMetalField && + SmartStarFeedback > 0) { + TypesToAdd[FieldsToAdd++] = Metallicity; + AddedMetallicity = true; + } + if (RadiativeTransferLoadBalance) TypesToAdd[FieldsToAdd++] = RaySegments; } diff --git a/src/enzo/Star_FindFeedbackSphere.C b/src/enzo/Star_FindFeedbackSphere.C index f74626ecf..5f3e22c37 100644 --- a/src/enzo/Star_FindFeedbackSphere.C +++ b/src/enzo/Star_FindFeedbackSphere.C @@ -146,10 +146,11 @@ int Star::FindFeedbackSphere(LevelHierarchyEntry *LevelArray[], int level, /* Sum enclosed mass in this grid */ - Temp->GridData->GetEnclosedMassInShell(this, Radius-CellWidth, Radius, + Temp->GridData->GetEnclosedMassInShell(this->pos, Radius-CellWidth, Radius, ShellMass, ShellMetallicity2, ShellMetallicity3, - ShellColdGasMass, ShellVelocity); + ShellColdGasMass, ShellVelocity, + FeedbackFlag); Temp = Temp->NextGridThisLevel; From f62a65e0e48ff3ad93580693381218bc28cd2f07 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Tue, 12 Jan 2021 10:52:28 -0800 Subject: [PATCH 079/115] many updates to MechStars, and its coupling to radiation modules. testing well on home pc, needs larger scale tests on 256^3 at frontera --- src/enzo/Grid_AddFields.C | 16 ++++- .../Grid_CosmologySimulationInitializeGrid.C | 2 + src/enzo/Grid_FindAllStarParticles.C | 2 +- src/enzo/Grid_MechStarsCreation.C | 24 ++++--- src/enzo/Grid_MechStarsDepositFeedback.C | 2 +- src/enzo/Grid_MechStarsFeedbackRoutine.C | 21 ++++--- src/enzo/MechStars_calcPhotonRates.C | 11 +--- src/enzo/MechStars_checkCreationCriteria.C | 29 +++++---- src/enzo/MechStars_determineSN.C | 8 +-- src/enzo/MechStars_determineWinds.C | 6 +- src/enzo/StarParticleAddFeedback.C | 62 ++++++++++++++++--- src/enzo/StarParticleRadTransfer.C | 1 - src/enzo/Star_ComputePhotonRates.C | 27 ++++++-- src/enzo/Star_IsARadiationSource.C | 7 ++- 14 files changed, 149 insertions(+), 69 deletions(-) diff --git a/src/enzo/Grid_AddFields.C b/src/enzo/Grid_AddFields.C index 744a8ac6d..fc7f89ab6 100644 --- a/src/enzo/Grid_AddFields.C +++ b/src/enzo/Grid_AddFields.C @@ -44,11 +44,21 @@ int grid::AddFields(int TypesToAdd[], int NumberOfFields) } BaryonField[n] = new float[size]; - value = (TypesToAdd[i] == SNColour || TypesToAdd[i] == Metallicity || + + // added conditional for using a metallicity floor with rad-hydro + if (TypesToAdd[i] == Metallicity ){ + value = 6.475e-6; + for (j = 0; j < size; j++) + BaryonField[n][j] = value * BaryonField[0][j]; + } + else{ + value = (TypesToAdd[i] == SNColour || TypesToAdd[i] == MetalSNIaDensity || TypesToAdd[i]==MetalSNIIDensity) ? tiny_number : 0.0; + for (j = 0; j < size; j++) - BaryonField[n][j] = value; - } // ENDIF this processor + BaryonField[n][j] = value; + } + } // ENDIF this processor } // ENDFOR i diff --git a/src/enzo/Grid_CosmologySimulationInitializeGrid.C b/src/enzo/Grid_CosmologySimulationInitializeGrid.C index 57a83f1d7..f23fcc5ce 100644 --- a/src/enzo/Grid_CosmologySimulationInitializeGrid.C +++ b/src/enzo/Grid_CosmologySimulationInitializeGrid.C @@ -512,6 +512,8 @@ int grid::CosmologySimulationInitializeGrid( if (UseMetallicityField && ReadData) { for (i = 0; i < size; i++) + if (i==0) + fprintf(stdout, "Setting initial metals: %12.5e * %12.5e = %12.5e", CosmologySimulationInitialFractionMetal, BaryonField[0][i],CosmologySimulationInitialFractionMetal * BaryonField[0][i] ); BaryonField[MetalNum][i] = CosmologySimulationInitialFractionMetal * BaryonField[0][i]; diff --git a/src/enzo/Grid_FindAllStarParticles.C b/src/enzo/Grid_FindAllStarParticles.C index fed78df3a..1bfb75dc7 100644 --- a/src/enzo/Grid_FindAllStarParticles.C +++ b/src/enzo/Grid_FindAllStarParticles.C @@ -92,7 +92,7 @@ int grid::FindAllStarParticles(int level) InsertStarAfter(Stars, NewStar); NumberOfStars++; if (StarParticleFeedback == MECHANICAL){ - NewStar->SetFeedbackFlag(15); + NewStar->SetFeedbackFlag(MECHANICAL); NewStar->LifeTime = huge_number; // Mechanical stars never "die", they can reaccrete or just deposit wind } /* For MBHFeedback = 2 to 5 (FeedbackFlag=MBH_JETS), you need diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C index 42f764d43..b27805dd0 100644 --- a/src/enzo/Grid_MechStarsCreation.C +++ b/src/enzo/Grid_MechStarsCreation.C @@ -22,7 +22,7 @@ int checkCreationCriteria(float* Density, float* Metals, float* Temperature,float* DMField, - float* Vel1, float* Vel2, float* Vel3, + float* Vel1, float* Vel2, float* Vel3, float* TotE, float* CoolingTime, int* GridDim, float* shieldedFraction, float* freeFallTime, float* dynamicalTime, int i, int j, int k, @@ -49,7 +49,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, */ bool gridShouldFormStars=false, notEnoughMetals = true; - bool debug = false; + bool debug = true; // local debug flag; theres a lot of printing in here //get field numbers @@ -104,6 +104,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, int *seedIndex = new int [3]; FLOAT dx = CellWidth[0][0]; + FLOAT cell_vol = dx*dx*dx; int GZ = int(NumberOfGhostZones); int nCreated = *NumberOfParticlesSoFar; //fprintf(stdout, "Starting creation with %d prior particles\n",nCreated); @@ -133,7 +134,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, createStar = checkCreationCriteria(BaryonField[DensNum], totalMetal, Temperature, DMField, BaryonField[Vel1Num], BaryonField[Vel2Num], - BaryonField[Vel3Num], + BaryonField[Vel3Num], BaryonField[TENum], CoolingTime, GridDimension, &shieldedFraction, &freeFallTime, &dynamicalTime, i,j,k,Time, BaryonField[NumberOfBaryonFields], CellWidth[0][0], @@ -145,19 +146,26 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, /* Determine Mass of new particle */ float MassShouldForm = (shieldedFraction * BaryonField[DensNum][index] - * MassUnits / freeFallTime * this->dtFixed*TimeUnits/3.1557e13); + * MassUnits / (freeFallTime * TimeUnits) * Myr_s); + // Probability has the last word here + // FIRE-2 uses p = 1 - exp (-MassShouldForm*dt / M_gas_particle) to convert a whole particle to star particle + float p_form = 1.0 - exp(-1*MassShouldForm * this->dtFixed / (StarMakerMaximumFormationMass)); + float random = (float) rand() / (float)(RAND_MAX); + printf("Expected Mass = %12.5e; Cell_mass = %12.5e; f_s = %12.5e; t_ff = %12.5e; time-factor = %12.5e; nb = %12.5e; pform = %12.5e, rand = %12.5e; rand_max = %ld\n", + MassShouldForm, BaryonField[DensNum][index] * MassUnits, shieldedFraction, freeFallTime*TimeUnits, 1.0/(freeFallTime*TimeUnits) * Myr_s, + BaryonField[DensNum][index]*DensityUnits/(mh/0.6), p_form, random, RAND_MAX); if (MassShouldForm < 0){ printf("Negative formation mass: %f %f",shieldedFraction, freeFallTime); continue; } - /* limit new mass to 1/2 gas in cell */ - float newMass = min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]); + /* limit new mass to 1/2 gas in cell, or StarMakerMaximumFormationMass */ + float newMass = min(min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]), StarMakerMaximumFormationMass/MassUnits); // only if mass is large enough - if (newMass*MassUnits < StarMakerMinimumMass){ + if ((newMass*MassUnits < StarMakerMinimumMass) || (random > p_form)){ // too small mass or probability is not in your favor, young one. continue; } float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; @@ -165,7 +173,7 @@ int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, // fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); ParticleArray->ParticleMass[nCreated] = newMass; if (StarParticleRadiativeFeedback) - ParticleArray->ParticleAttribute[1][nCreated] = 27*TimeUnits*3.1517e6; // need 27 Myr lifetime for ray tracing feedback + ParticleArray->ParticleAttribute[1][nCreated] = 25.0 * Myr_s * TimeUnits; // need 25 Myr lifetime for ray tracing feedback else ParticleArray->ParticleAttribute[1][nCreated] = 0.0; // Tracking SNE in TDP field dynamicalTime/TimeUnits; ParticleArray->ParticleAttribute[0][nCreated] = Time; diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 06ea8555b..82bb410c1 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -284,7 +284,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, // if we resolve free expansion, all energy is thermally coupled - float p_free = 0.0; //sqrt(ejectaMass*SolarMass*ejectaEnergy)/SolarMass/1e5;//1.73e4*sqrt(ejectaMass*ejectaEnergy/1e51/3.); // free exp. momentum eq 15 + float p_free = sqrt(ejectaMass*SolarMass*ejectaEnergy)/SolarMass/1e5;//1.73e4*sqrt(ejectaMass*ejectaEnergy/1e51/3.); // free exp. momentum eq 15 float r_free = 2.75 * pow(ejectaMass / 3 / nmean, 1. / 3.); // free exp radius eq 2 // assuming r_sedov == dx, solve for t3 diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 3d206701d..cd38905f4 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -28,7 +28,7 @@ int determineWinds(float age, float *eWinds, float *zWinds, float *mWinds, float massMsun, float zZsun, float TimeUnits, float dtFixed); int checkCreationCriteria(float *Density, float *Metals, float *Temperature, float *DMField, - float *Vel1, float *Vel2, float *Vel3, + float *Vel1, float *Vel2, float *Vel3, float* TotE, float *CoolingTime, int *GridDim, float *shieldedFraction, float *freeFallTime, float *dynamicalTime, int i, int j, int k, @@ -49,6 +49,7 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta //fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", //SingleSN, StellarWinds, UnrestrictedSN); + float Zsolar = 0.02; float stretchFactor = 1.0; // radius from star particle to feedback cloud particle (in units of dx) bool debug = false; float startFB = MPI_Wtime(); @@ -201,6 +202,7 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta float shieldedFraction = 0, dynamicalTime = 0, freeFallTime = 0; bool gridShouldFormStars = true, notEnoughMetals = false; float zFraction = totalMetal[index]; + float pmassMsun = ParticleMass[pIndex] * MassUnits; if (ParticleMass[pIndex] * MassUnits < StarMakerMaximumMass && ProblemType != 90) /* Check for continual formation. Continually forming new mass allows the @@ -214,25 +216,26 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta if the age is old, we'd rather form a new particle to get some more supernova and high-power winds popping off. */ - if (age < 50) + if (age < 5) createStar = checkCreationCriteria(BaryonField[DensNum], &zFraction, Temperature, DMField, BaryonField[Vel1Num], BaryonField[Vel2Num], - BaryonField[Vel3Num], + BaryonField[Vel3Num], BaryonField[TENum], CoolingTime, GridDimension, &shieldedFraction, &freeFallTime, &dynamicalTime, ip, jp, kp, Time, BaryonField[NumberOfBaryonFields], CellWidth[0][0], &gridShouldFormStars, ¬EnoughMetals, 1, NULL); if (createStar) { - float MassShouldForm = min((shieldedFraction * BaryonField[DensNum][index] * MassUnits / freeFallTime * this->dtFixed * TimeUnits / 3.1557e13), + float MassShouldForm = min((shieldedFraction * BaryonField[DensNum][index] * MassUnits / (freeFallTime * TimeUnits) * this->dtFixed * Myr_s), 0.5 * BaryonField[DensNum][index] * MassUnits); + MassShouldForm = min(MassShouldForm, StarMakerMaximumMass-pmassMsun); // dont form if the star is already at the top of the mass allowed //printf("Adding new mass %e\n",MassShouldForm); /* Dont allow negative mass, or taking all gas in cell */ if (MassShouldForm < 0) MassShouldForm = 0; - if (MassShouldForm > 0.5 * BaryonField[DensNum][index] * MassUnits) - MassShouldForm = 0.5 * BaryonField[DensNum][index] * MassUnits; + // if (MassShouldForm > 0.5 * BaryonField[DensNum][index] * MassUnits) + // MassShouldForm = 0.5 * BaryonField[DensNum][index] * MassUnits; // Set units and modify particle MassShouldForm /= MassUnits; @@ -294,8 +297,8 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta float energySN = (nSNII + nSNIA) * 1e51; /*10.5 Msun ejecta for type II and IA*/ - SNMassEjected = (nSNII + nSNIA) * 10.5; - float starMetal = (ParticleAttribute[2][pIndex] / 0.02); //determines metal content of SNeII + SNMassEjected = nSNII*10.5 + nSNIA * 1.5; + float starMetal = (ParticleAttribute[2][pIndex] / Zsolar); //determines metal content of SNeII MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, Temperature, &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], @@ -319,7 +322,7 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta if (StellarWinds && age > 0.001 && ParticleMass[pIndex] * MassUnits > 1) { // printf("Checking Winds\n"); - float zZsun = min(ParticleAttribute[2][pIndex] / 0.02, MechStarsCriticalMetallicity); + float zZsun = min(ParticleAttribute[2][pIndex] / Zsolar, MechStarsCriticalMetallicity); determineWinds(age, &windEnergy, &windMass, &windMetals, ParticleMass[pIndex] * MassUnits, zZsun, diff --git a/src/enzo/MechStars_calcPhotonRates.C b/src/enzo/MechStars_calcPhotonRates.C index 44bbcaed9..c6ebf9d0c 100644 --- a/src/enzo/MechStars_calcPhotonRates.C +++ b/src/enzo/MechStars_calcPhotonRates.C @@ -1,14 +1,5 @@ /* - Couples the mechanical stars to the radiation machinery in ENZO by filling - in the emissivity0 field. - Code must be compiled with "make emissivity-yes" and "make photon-yes". - Usage at runtime determined by the StarMakerUseEmissivity flag. - Unlike the CIC depositions in the rest of this module, the emissivity is set - solely for the cell hosting the star particle (or its kicked location). - - The radiation deposited here is time varying depending on the age of the particle (and mass). - A better implementation will make the individual bands of radiation time dependent - (more UV early, more IR late). + Calculates the luminosity of a mechanical star based on Hopkins 2018 */ #include #include diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index 2f8d6af04..df8c2e7cc 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -25,7 +25,7 @@ #define PASS 1; int checkCreationCriteria(float* Density, float* Metals, float* Temperature,float* DMField, - float* Vel1, float* Vel2, float* Vel3, + float* Vel1, float* Vel2, float* Vel3, float* TotE, float* CoolingTime, int* GridDim, float* shieldedFraction, float* freeFallTime, float* dynamicalTime, int i, int j, int k, @@ -33,8 +33,9 @@ int checkCreationCriteria(float* Density, float* Metals, bool* gridShouldFormStars, bool* notEnoughMetals, int continuingFormation, int* seedIndex) { + float Zsolar = 0.02; float maxZ = 0.0; - bool debug = false; + bool debug = true; bool status = PASS; float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; @@ -61,7 +62,7 @@ int checkCreationCriteria(float* Density, float* Metals, float dmean = (Density[index]*10.0+Density[iminus] + Density[iplus]+Density[jplus] + Density[jminus]+Density[kminus] - + Density[kplus])/17.0; + + Density[kplus])/17.0 * DensityUnits / (mh/0.6); if (dmean < StarMakerOverDensityThreshold) { return FAIL; @@ -102,12 +103,14 @@ int checkCreationCriteria(float* Density, float* Metals, +dzvx*dzvx+dzvy*dzvy+dzvz*dzvz); /* approximate taking gas as monatomic and mu = 0.6*/ + /* Gravitational constant [cm3g-1s-2]*/ float Gcode = GravConst*DensityUnits*pow(TimeUnits,2); float KBcode = kboltz*MassUnits/(LengthUnits*CellWidth)/pow(TimeUnits,2); cSound = sqrt(5/3*kboltz*Temperature[index]/mh/0.6)/VelocityUnits; alpha = ((vfactor) + pow(cSound/(CellWidth), 2.0)) / (8.0 * M_PI* Gcode * Density[index]); + float AltAlpha = TotE[index]*MassUnits / (8.0 * M_PI * GravConst/MassUnits); if (alpha > 1.0) return FAIL; @@ -131,6 +134,7 @@ int checkCreationCriteria(float* Density, float* Metals, float IsoSndSpeed = 1.3095e8 * Temperature[index]; float jeansMass = pi/(6.0*pow(Density[index]*DensityUnits, 0.5)) *pow(pi*IsoSndSpeed/GravConst, 1.5)/SolarMass; + float altJeans = 2 * pow(cSound*VelocityUnits/1e5/0.2, 3) * pow((Density[index]*DensityUnits/(mh/0.6)/1e3), -0.5); if (jeansMass > max(baryonMass, 1e3)) return FAIL; /* Is self Shielded fraction > 0.0 by Krumholz & Gnedin */ @@ -146,9 +150,9 @@ int checkCreationCriteria(float* Density, float* Metals, float TauFactor = 434.8/*cm**2/g*/ * MassUnits/pow(LengthUnits*CellWidth, 2); // cm**2/g float Tau = TauFactor * Density[index] *(CellWidth+Density[index]/gradRho); - float Phi = 0.756*pow(1+3.1*Metals[index]/Density[index]/0.02, 0.365); + float Phi = 0.756*pow(1+3.1*Metals[index]/Density[index]/Zsolar, 0.365); - float Psi = 0.6*Tau*(0.01+Metals[index]/Density[index]/0.02)/ + float Psi = 0.6*Tau*(0.01+Metals[index]/Density[index]/Zsolar)/ log(1+0.6*Phi+0.01*Phi*Phi); *shieldedFraction = 1.0 - 3.0/(1.0+4.0*Psi); if (debug) @@ -157,19 +161,20 @@ int checkCreationCriteria(float* Density, float* Metals, if (*shieldedFraction < 0) status = FAIL; - *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; + *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; // that theres code-time if (status && debug) { - fprintf(stdout, "Check Creation positive! rho = %"GSYM" gradRho = %"GSYM" Fs = %"FSYM" M_j = %"GSYM" VirialPar = %"FSYM" divergence = %"FSYM" Temperature = %"GSYM"\n", - Density[index], gradRho, *shieldedFraction, jeansMass, alpha, div, Temperature[index]); - } - if (status && (Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity || !MechStarsSeedField)){ - return status; + fprintf(stdout, "Check Creation positive! n_b = %"GSYM" M_b = %"GSYM" gradRho = %"GSYM" Fs = %"FSYM" M_j = %"GSYM" VirialPar = %"FSYM" divergence = %"FSYM" Temperature = %"GSYM" cSnd = %"GSYM" AltJeans = %"GSYM" AltAlpha = %"GSYM"\n", + dmean, baryonMass, gradRho, *shieldedFraction, jeansMass, alpha, div, Temperature[index], cSound*VelocityUnits/1e5, altJeans); } //if (status && debug) fprintf(stdout, "passed creation criteria\n"); if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity && !continuingFormation) *notEnoughMetals = false; - if (status && Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity && MechStarsSeedField + if (status && (Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity)){ + status = FAIL; + } + + else if (status && Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity && MechStarsSeedField && !continuingFormation) { // if (debug) fprintf(stdout,"No metals, criteria passed, but not forming\n"); diff --git a/src/enzo/MechStars_determineSN.C b/src/enzo/MechStars_determineSN.C index fafae8c7d..a8fba3010 100644 --- a/src/enzo/MechStars_determineSN.C +++ b/src/enzo/MechStars_determineSN.C @@ -53,13 +53,13 @@ int determineSN(float age, int* nSNII, int* nSNIA, RII = 0.0; RIA = 5.2e-8+1.6e-5*exp(-1.0*pow((age-50.0)/10.0, 2)/2.0); } - // fprintf(stdout, "Rates: %f %f %f\n", age, RII, RIA); + fprintf(stdout, "Rates: For age %f Myr, RII = %f; RIA = %f\n", age, RII, RIA); /* rates -> probabilities */ if (RII > 0){ srand(seed); // printf("Zcpl = %e", zCouple); - PII = RII * massMsun / 3.1557e13 *TimeUnits*dt; - // printf("PII =%f\n %f %e %f\n", PII, RII, massMsun, age); + PII = RII * massMsun / Myr_s *TimeUnits*dt; + printf("PII =%f\n %f %e %f\n", PII, RII, massMsun, age); random = float(rand())/float(RAND_MAX); if (PII > 1.0 && UnrestrictedSN == TRUE){ int round = (int)PII; @@ -79,7 +79,7 @@ int determineSN(float age, int* nSNII, int* nSNIA, if (RIA > 0){ srand(seed); - PIA = RIA*massMsun/3.1557e13*TimeUnits*dt; + PIA = RIA*massMsun / Myr_s * TimeUnits * dt; float random = float(rand())/float(RAND_MAX); if (PIA > 1.0 && UnrestrictedSN == TRUE) diff --git a/src/enzo/MechStars_determineWinds.C b/src/enzo/MechStars_determineWinds.C index ca68a520c..200ea3566 100644 --- a/src/enzo/MechStars_determineWinds.C +++ b/src/enzo/MechStars_determineWinds.C @@ -16,7 +16,7 @@ int determineWinds(float age, float* eWinds, float* mWinds, float* zWinds, float massMsun, float zZsun, float TimeUnits, float dtFixed){ - + float Zsolar = 0.02; bool oldEnough = (age < 0.0001)?(false):(true); float windE = 0, windM = 0, windZ = 0.0; float wind_factor = 0.0; @@ -47,7 +47,7 @@ int determineWinds(float age, float* eWinds, float* mWinds, float* zWinds, wind_factor = 0.42*pow(age/1000, -1.1)/(19.81/log(age)); } windM = massMsun * wind_factor; //Msun/Gyr - windM = windM*dtFixed*TimeUnits/3.1557e16; //Msun + windM = windM*dtFixed*TimeUnits/(1e3 * Myr_s); //Msun // if (debug) printf("First winds mass = %e\nFrom wf = %f, dt=%f Z = %e\n", windM, wind_factor, dtFixed, zZsun); //printf("eFactor = %f age = %f\n", e_factor, age); if (windM > massMsun){ @@ -55,7 +55,7 @@ int determineWinds(float age, float* eWinds, float* mWinds, float* zWinds, windM, massMsun, age, zZsun); windM = 0.125*massMsun; // limit loss to huge if necessary. } - windZ = max(0.02, 0.016+0.0041*max(zZsun, 1.65)+0.0118)*windM; + windZ = max(Zsolar, 0.016+0.0041*max(zZsun, 1.65)+0.0118)*windM; windE = e_factor * 1e12 * windM; //fprintf(stdout, "Age = %e Ewinds = %e Mwinds = %e Zwinds = %e Zsun = %e\n", // age, windE, windM, windZ, zZsun); diff --git a/src/enzo/StarParticleAddFeedback.C b/src/enzo/StarParticleAddFeedback.C index 232281d91..b89b9476f 100644 --- a/src/enzo/StarParticleAddFeedback.C +++ b/src/enzo/StarParticleAddFeedback.C @@ -230,21 +230,44 @@ int StarParticleAddFeedback(TopGridData *MetaData, float metalFrac; float rescale = 1.0; FLOAT MassUnits = DensityUnits*pow(LengthUnits,3)/SolarMass; //code -> Msun if mult. by cell volume + + /* + For Pop2 SN, only deposit on grid local to task if not using load balancing. + This way, we avoid the MPI_Allreduce and incur minimal error when the SN bubble overlaps + task boundaries + */ + // loop over level heirarchy to find processor number that hosts the stars grid + int StarProc = 0; + int StarLevel = cstar->ReturnLevel(); + int StarGrid = cstar->ReturnGridID(); + for (Temp = LevelArray[StarLevel]; Temp; Temp = Temp->NextGridThisLevel){ + if (Temp->GridData->GetGridID() == StarGrid){ + StarProc = Temp->GridData->ReturnProcessorNumber(); + break; + } + } + + // printf("star proc: %d, my proc = %d, load_bal = %d", + // StarProc, MyProcessorNumber, + // LoadBalancing); + bool dep_p2_this_task = (LoadBalancing == 0 + && cstar->ReturnType() == PopII + && cstar->ReturnFeedbackFlag()==SUPERNOVA); // true when skipping mpi_allreduce for (l=level; l < MAX_DEPTH_OF_HIERARCHY; l++){ // initially l=level; lReturnFeedbackFlag() == SUPERNOVA || cstar->ReturnFeedbackFlag() == FORMATION) { - /* + /* Spheres interacting with grids isnt consistent; Do a first pass with no deposition to validate the volume we will deposit into, then rescale the deposition accordingly. --AIW */ - + bool rescaleSN = cstar->ReturnFeedbackFlag()==SUPERNOVA && (cstar->ReturnType() == PopIII); bool PopIIRescale = cstar->ReturnFeedbackFlag() == SUPERNOVA && cstar->ReturnType() == PopII; - + // Things we'll sum across grids int nCells = 0; @@ -273,12 +296,33 @@ int StarParticleAddFeedback(TopGridData *MetaData, // (sphere can be across procs as well!) -AIW // IMPROVEMENT: Use the chaining mesh with MPI_GatherV to only // sum across adjacent grids - - MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - + // if (!dep_p2_this_task){ // if not load balance and doing p2 deposition, dont sum across tasks. + MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // } + + // int comm_id = MPI_UNDEFINED; // MPI_UNDEFINED get assigned to no communicator + // if (vol_modified > 0.0){ + // comm_id = 1; + // } + // // Define a new comm that only has the tasks with modified volumes + // MPI_Comm vol_mod_comm; + // MPI_Comm_split(MPI_COMM_WORLD, comm_id, MyProcessorNumber, &vol_mod_comm); + // if (comm_id != MPI_UNDEFINED){ + // MPI_Allreduce(&vol_modified, &AllVol,1,MPI_DOUBLE, MPI_SUM, vol_mod_comm); + // MPI_Allreduce(&mass_dep, &allMass,1,MPI_DOUBLE, MPI_SUM, vol_mod_comm); + // MPI_Allreduce(&metal_dep, &allMetal,1,MPI_DOUBLE, MPI_SUM, vol_mod_comm); + // MPI_Allreduce(&metal2_dep, &allMetal2,1,MPI_DOUBLE, MPI_SUM, vol_mod_comm); + // } + // // MPI_Comm_free(&vol_mod_comm); + // if not mpi_allreducing, non-star-local task quantities to re-zerod + // if (dep_p2_this_task && StarProc != MyProcessorNumber){ + // allMass = 0; + // allMetal = 0; + // allMetal2 = 0; + // } // set the volume of the lowest level to deposit into // WHY IS THIS NOT THE HIGHEST VOLUME?? if (AVL0 == 0) diff --git a/src/enzo/StarParticleRadTransfer.C b/src/enzo/StarParticleRadTransfer.C index 80524d80e..2899da6c4 100644 --- a/src/enzo/StarParticleRadTransfer.C +++ b/src/enzo/StarParticleRadTransfer.C @@ -79,7 +79,6 @@ int StarParticleRadTransfer(LevelHierarchyEntry *LevelArray[], int level, float TimeInYears = yr_s / TimeUnits; for (cstar = AllStars; cstar; cstar = cstar->NextStar) { - // Check the rules if this star particle is radiative if (cstar->IsARadiationSource(PhotonTime)) { float dtForThisStar = LevelArray[level]->GridData->ReturnTimeStep(); diff --git a/src/enzo/Star_ComputePhotonRates.C b/src/enzo/Star_ComputePhotonRates.C index a324f7495..1faf1c282 100644 --- a/src/enzo/Star_ComputePhotonRates.C +++ b/src/enzo/Star_ComputePhotonRates.C @@ -36,7 +36,6 @@ int Star::ComputePhotonRates(const float TimeUnits, const float Time, int &nbins, float E[], double Q[], float dtForThisStar) { - int i; double L_UV, cgs_convert, _mass; float x, x2, EnergyFractionLW, MeanEnergy, XrayLuminosityFraction; @@ -191,11 +190,27 @@ int Star::ComputePhotonRates(const float TimeUnits, const float Time, // Calculate Delta(M_SF) for Cen & Ostriker star particles #ifdef TRANSFER if (FeedbackFlag == MECHANICAL){ - E[0] = 13.6; // H ionizing radiation - L_UV = MechStars_calcPhotonRates(this, Time);// returns [L_UV] = L_sun/M_sun - cgs_convert = SolarMass/TimeUnits; - - Q[0] = L_UV*eV_erg*SolarLuminosity/E[0]* this->Mass*(dtPhoton); + // L_ionization taken from Hopkins 2018, + // energy fractions and bins after that are + // taken from the P2 star cluster method + EnergyFractionLW = 1.288; + EnergyFractionHeI = 0.2951; + EnergyFractionHeII = 2.818e-4; + E[0] = 21.62; // eV (good for a standard, low-Z IMF) + E[1] = 30.0; + E[2] = 60.0; + E[3] = 12.8; + L_UV = MechStars_calcPhotonRates(this, Time);// returns [L_UV] = L_sun/M_sun for HI ionizing radiation + Q[0] = L_UV * this->Mass * SolarLuminosity * eV_erg / E[0]; + if (StarClusterHeliumIonization) { + Q[1] = EnergyFractionHeI * Q[0]; + Q[2] = EnergyFractionHeII * Q[0]; + Q[0] *= 1.0 - EnergyFractionHeI - EnergyFractionHeII; + } else { + Q[1] = 0.0; + Q[2] = 0.0; + } + Q[3] = EnergyFractionLW * Q[0]; } else{ Mform = this->CalculateMassLoss(dtPhoton) / StarMassEjectionFraction; diff --git a/src/enzo/Star_IsARadiationSource.C b/src/enzo/Star_IsARadiationSource.C index f7b9e0ffa..c4f6ee6e5 100644 --- a/src/enzo/Star_IsARadiationSource.C +++ b/src/enzo/Star_IsARadiationSource.C @@ -48,8 +48,11 @@ bool Star::IsARadiationSource(FLOAT Time) FeedbackFlag == MBH_THERMAL || FeedbackFlag == MBH_JETS); - // Living, but mechanical stars never die - rules[1] = (FeedbackFlag == MECHANICAL)?(Time >= BirthTime && type > 0):(Time >= BirthTime && Time <= BirthTime+LifeTime && type > 0); + // Living + if (FeedbackFlag == MECHANICAL) // MechStars radiate ionizing radiation for 25 Myr + rules[1] = (Time >= BirthTime) && (Time <= BirthTime+LifeTime) && (type > 0); + else // other stars radiate for all time + rules[1] = (Time >= BirthTime) && (type > 0); // Non-zero BH accretion (usually accretion_rate[] here is NULL - Ji-hoon Kim Sep.2009) if ((type == BlackHole || type == MBH) && naccretions > 0) From 5c16fd61eaf11fab367c223bdcd070de392a5494 Mon Sep 17 00:00:00 2001 From: John Regan Date: Thu, 21 Jan 2021 12:23:44 +0000 Subject: [PATCH 080/115] intermediate commit - switching clusters --- src/enzo/ActiveParticleRoutines.C | 7 +- src/enzo/ActiveParticle_SmartStar.C | 368 +++++---- src/enzo/ActiveParticle_SmartStar.h | 12 +- src/enzo/ActiveParticle_SphereContained.C | 13 +- src/enzo/DetermineSEDParameters.C | 31 +- src/enzo/EvolvePhotons.C | 8 +- src/enzo/Grid_AccreteOntoSmartStarParticle.C | 15 +- src/enzo/Grid_AddH2DissociationFromSources.C | 9 +- .../Grid_ApplySmartStarParticleFeedback.C | 737 +++++++++--------- src/enzo/RadiativeTransferInitialize.C | 4 +- src/enzo/RadiativeTransferReadParameters.C | 2 +- src/enzo/TemperatureFieldToolsH2Shielding.C | 11 +- 12 files changed, 623 insertions(+), 594 deletions(-) diff --git a/src/enzo/ActiveParticleRoutines.C b/src/enzo/ActiveParticleRoutines.C index 9436d668d..ed87ee846 100644 --- a/src/enzo/ActiveParticleRoutines.C +++ b/src/enzo/ActiveParticleRoutines.C @@ -252,6 +252,7 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) } if(Mass > a->Mass) { + RadiationLifetime = -99.0; ; } else { @@ -263,6 +264,7 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) AccretionRateTime[i] = a->AccretionRateTime[i]; AccretionRate[i] = a->AccretionRate[i]; } + RadiationLifetime = a->RadiationLifetime; } Mass += a->Mass; NotEjectedMass += a->NotEjectedMass; @@ -528,7 +530,7 @@ void ActiveParticleType_SmartStar::AssignMassFromIMF() } this->Mass = PopIIILowerMassCutoff * POW(10.0, bin_number * dm); - + /* Adjust the lifetime (taken from the fit in Schaerer 2002) now we know the stellar mass. It was set to the lifetime of a star with M=PopIIILowerMassCutoff in pop3_maker.src as a placeholder. */ @@ -538,5 +540,6 @@ void ActiveParticleType_SmartStar::AssignMassFromIMF() // First in years, then convert to code units this->RadiationLifetime = POW(10.0, (9.785 - 3.759*logm + 1.413*logm*logm - 0.186*logm*logm*logm)) / (TimeUnits/yr_s); - + printf("%s: Mass assigned from IMF = %e Msolar\t Lifetime = %e\n", __FUNCTION__, this->Mass, + this->RadiationLifetime*TimeUnits/yr_s); } diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 2fb72a76a..bd904dd11 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -38,12 +38,11 @@ class SmartStarGrid : private grid { * SmartStarGrid *thisgrid = * static_cast(thisgrid_orig); */ float ActiveParticleType_SmartStar::EjectedMassThreshold = FLOAT_UNDEFINED; -int ActiveParticleType_SmartStar::RadiationParticle = INT_UNDEFINED; double ActiveParticleType_SmartStar::LuminosityPerSolarMass = FLOAT_UNDEFINED; int ActiveParticleType_SmartStar::RadiationSEDNumberOfBins = INT_UNDEFINED; float* ActiveParticleType_SmartStar::RadiationEnergyBins = NULL; float* ActiveParticleType_SmartStar::RadiationSED = NULL; -float ActiveParticleType_SmartStar::RadiationLifetime = FLOAT_UNDEFINED; +//float ActiveParticleType_SmartStar::RadiationLifetime = FLOAT_UNDEFINED; int ActiveParticleType_SmartStar::FeedbackDistRadius = INT_UNDEFINED; int ActiveParticleType_SmartStar::FeedbackDistTotalCells = INT_UNDEFINED; int ActiveParticleType_SmartStar::FeedbackDistCellStep = INT_UNDEFINED; @@ -57,11 +56,9 @@ int ActiveParticleType_SmartStar::InitializeParticleType() { EjectedMassThreshold = 1.0; - RadiationParticle = 1; RadiationSEDNumberOfBins = NUMRADIATIONBINS; RadiationEnergyBins = new float[RadiationSEDNumberOfBins]; RadiationSED = new float[RadiationSEDNumberOfBins]; - RadiationLifetime = 1e60; FeedbackDistRadius = StarFeedbackDistRadius; FeedbackDistCellStep = StarFeedbackDistCellStep; @@ -94,6 +91,7 @@ int ActiveParticleType_SmartStar::InitializeParticleType() ah.push_back(new Handler("AccretionRadius")); ah.push_back(new Handler("ParticleClass")); + ah.push_back(new Handler("RadiationLifetime")); ah.push_back(new Handler("NotEjectedMass")); ah.push_back(new Handler("MassToBeEjected")); ah.push_back(new Handler("eta_disk")); @@ -203,7 +201,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation #if JEANSREFINEMENT if (JeansRefinement) { CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : data.Temperature[index]; - int JeansFactor = 1; //RefineByJeansLengthSafetyFactor + int JeansFactor = 8; //RefineByJeansLengthSafetyFactor JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / POW(data.LengthUnits*dx*JeansFactor,2); @@ -344,6 +342,9 @@ int ActiveParticleType_SmartStar::EvaluateFormation if(KineticEnergy + ThermalEnergy + GravitationalEnergy >= 0.0) continue; #endif + + + printf("%s: Forming SS particle out of cellindex %d\n", __FUNCTION__, index); fflush(stdout); /* * Now we need to check the H2 fraction and the accretion rate now. * If the H2fraction > PopIIIH2CriticalFraction then we are ok to form a PopIII star @@ -379,6 +380,8 @@ int ActiveParticleType_SmartStar::EvaluateFormation } else if(accrate*3.154e7*ConverttoSolar/data.TimeUnits > 1e-2) { stellar_type = SMS; + printf("!!!!!!!!SMS Formed\t accrate = %e Msolar/yr", + accrate*3.154e7*ConverttoSolar/data.TimeUnits); } if(stellar_type < 0) @@ -400,11 +403,13 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->level = data.level; np->GridID = data.GridID; np->CurrentGrid = thisGrid; - np->pos[0] = thisGrid->CellLeftEdge[0][i] + 0.5*thisGrid->CellWidth[0][i]; np->pos[1] = thisGrid->CellLeftEdge[1][j] + 0.5*thisGrid->CellWidth[1][j]; np->pos[2] = thisGrid->CellLeftEdge[2][k] + 0.5*thisGrid->CellWidth[2][k]; + printf("pos = %f %f %f\n", np->pos[0], np->pos[1], np->pos[2]); + printf("GridLeftEdge = %f %f %f\n", thisGrid->CellLeftEdge[0][0], + thisGrid->CellLeftEdge[1][0], thisGrid->CellLeftEdge[2][0]); float *apvel = new float[MAX_DIMENSION]; /* Calculate AP velocity by taking average of * surrounding 125 cells @@ -431,9 +436,9 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->AccretionRate[0] = accrate; np->AccretionRateTime[0] = np->BirthTime; - np->RadiationLifetime=SmartStarLifetime[np->ParticleClass]*yr_s/data.TimeUnits; + np->RadiationLifetime= SmartStarLifetime[np->ParticleClass]*yr_s/data.TimeUnits; np->NotEjectedMass = 0.0; - + /* The mass of the particles formed depends on the resolution and is handled * in a call to `RemoveMassFromGridAfterFormation` which is called from * `AfterEvolveLevel`. np->Mass is initally set here but can get overwritten @@ -443,7 +448,6 @@ int ActiveParticleType_SmartStar::EvaluateFormation * happens in this case. */ np->Mass = 0.0; - //printf("%s: Total Mass in Accretion Region = %g Msolar (Threshold = %g)\n", __FUNCTION__, // TotalMass*ConverttoSolar, (double)MASSTHRESHOLD); } // i @@ -468,6 +472,10 @@ int ActiveParticleType_SmartStar::EvaluateFormation int ActiveParticleType_SmartStar::EvaluateFeedback(grid *thisgrid_orig, ActiveParticleFormationData &data) { + + /* Feedback not handled here */ + return SUCCESS; + SmartStarGrid *thisGrid = static_cast(thisgrid_orig); @@ -702,6 +710,7 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel if( (ThisParticle->ParticleClass == POPIII || ThisParticle->ParticleClass == SMS) && SmartStarStellarRadiativeFeedback == FALSE) continue; //No stellar radiative feedback + dx = LevelArray[ThisParticle->level]->GridData->GetCellWidth(0,0); MassConversion = (double) (dx*dx*dx * mfactor); //Converts to Solar Masses source = ThisParticle->RadiationSourceInitialize(); @@ -716,8 +725,12 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel } /* Call Function to return SED parameters */ if(ThisParticle->DetermineSEDParameters(Time, dx) == FAIL) - return FAIL; - source->LifeTime = RadiationLifetime; + return FAIL; + + printf("%s: Mass = %e\t RadiationLifetime = %e yrs\n", __FUNCTION__, PMass, + ThisParticle->RadiationLifetime*TimeUnits/yr_s); fflush(stdout); + + source->LifeTime = ThisParticle->RadiationLifetime; source->Luminosity = (ThisParticle->LuminosityPerSolarMass * LConv) * PMass; source->RampTime = ramptime; source->EnergyBins = RadiationSEDNumberOfBins; @@ -727,6 +740,11 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel source->Energy[j] = ThisParticle->RadiationEnergyBins[j]; source->SED[j] = ThisParticle->RadiationSED[j]; } + // printf("%s: source->Lifetime = %f years\n", __FUNCTION__, source->LifeTime*TimeUnits/yr_s); + // printf("%s: Energy = %f %f %f %f %f\n", __FUNCTION__, source->Energy[0], + // source->Energy[1], source->Energy[2], source->Energy[3], source->Energy[4]); + //printf("%s: SED = %f %f %f %f %f\n", __FUNCTION__, source->SED[0], + // source->SED[1], source->SED[2], source->SED[3], source->SED[4]); #if SSDEBUG if(ThisParticle->ParticleClass == SMS) { printf("%s: !!!!!!!!!!!!!!!!!!!!!!!!SRC Luminosity: L=%lg Lcode=%g M=%g Mcode=%g\n", __FUNCTION__, @@ -746,7 +764,9 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel GlobalRadiationSources->NextSource->PreviousSource = source; GlobalRadiationSources->NextSource = source; } + exit(-99); } + } // ENDIF CallEvolvePhotons #endif /* TRANSFER */ @@ -766,7 +786,13 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle ActiveParticleList& ParticleList, LevelHierarchyEntry *LevelArray[], int ThisLevel) { - + //Particle Lifetimes + float SmartStarLifetime[4]; + SmartStarLifetime[0] = 2e6; //in yrs + SmartStarLifetime[1] = 2e6; //in yrs + SmartStarLifetime[2] = 1e20; //in yrs + SmartStarLifetime[3] = 2e7; //in yrs + float StellarMasstoRemove = 0.0, CellDensityAfterFormation = 0.0; /* Skip accretion if we're not on the maximum refinement level. This should only ever happen right after creation and then @@ -823,12 +849,17 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle } FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc float *density = APGrid->BaryonField[DensNum]; - int cellindex_x = (SS->pos[0] - APGrid->GridLeftEdge[0])/dx, - cellindex_y = (SS->pos[1] - APGrid->GridLeftEdge[1])/dx, - cellindex_z = (SS->pos[2] - APGrid->GridLeftEdge[2])/dx; - int cellindex = APGrid->GetIndex(cellindex_x, cellindex_y, cellindex_y); - float DensityThreshold = ActiveParticleDensityThreshold*mh/DensityUnits; + int cellindex_x = (SS->pos[0] - APGrid->CellLeftEdge[0][0])/dx, + cellindex_y = (SS->pos[1] - APGrid->CellLeftEdge[1][0])/dx, + cellindex_z = (SS->pos[2] - APGrid->CellLeftEdge[2][0])/dx; + + printf("SS->Pos = %f %f %f\n", SS->pos[0], SS->pos[1], SS->pos[2]); + printf("GridLeftEdge = %f %f %f\n", APGrid->CellLeftEdge[0][0], APGrid->CellLeftEdge[1][0], + APGrid->CellLeftEdge[2][0]); + int cellindex = APGrid->GetIndex(cellindex_x, cellindex_y, cellindex_z); + float DensityThreshold = ActiveParticleDensityThreshold*mh/DensityUnits; + #if JEANSREFINEMENT bool JeansRefinement = false; for (int method = 0; method < MAX_FLAGGING_METHODS; method++) @@ -839,7 +870,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle float *Temperature = new float[size](); APGrid->ComputeTemperatureField(Temperature); float CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : Temperature[cellindex]; - int JeansFactor = 1; //RefineByJeansLengthSafetyFactor + int JeansFactor = 8; //RefineByJeansLengthSafetyFactor float JeansDensityUnitConversion = (Gamma*pi*kboltz) / (Mu*mh*GravConst); float JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / POW(LengthUnits*dx*JeansFactor,2); @@ -849,8 +880,14 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle #endif float ParticleDensity = density[cellindex] - DensityThreshold; - if(ParticleDensity < 0.0) - ENZO_FAIL("Particle Density is negative. Oh dear.\n"); + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + ENZO_FAIL("Particle Density is negative. Oh dear.\n"); + } + float newcelldensity = density[cellindex] - ParticleDensity; if(SMS == SS->ParticleClass) { @@ -899,144 +936,146 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle accrete. We step out by a cell width when searching. ***********************************************************************/ + printf("%s: Low resolution run.....\n", __FUNCTION__); + FLOAT Radius = 0.0; + int feedback_flag = -99999; + float MassEnclosed = 0; + float Metallicity2 = 0; + float Metallicity3 = 0; + float ColdGasMass = 0; + float AvgVelocity[MAX_DIMENSION]; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] = 0.0; + bool SphereTooSmall = true; + float ShellMass, ShellMetallicity2, ShellMetallicity3, ShellColdGasMass, + ShellVelocity[MAX_DIMENSION]; + while (SphereTooSmall) { + Radius += APGrid->CellWidth[0][0]; + bool IsSphereContained = SS->SphereContained(LevelArray, ThisLevel, Radius); + + if (IsSphereContained == false) + break; + ShellMass = 0; + ShellMetallicity2 = 0; + ShellMetallicity3 = 0; + ShellColdGasMass = 0; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + ShellVelocity[dim] = 0.0; + + bool MarkedSubgrids = false; + LevelHierarchyEntry *Temp = NULL; + HierarchyEntry *Temp2 = NULL; + + for (int l = ThisLevel; l < MAX_DEPTH_OF_HIERARCHY; l++) { + Temp = LevelArray[l]; + while (Temp != NULL) { + + /* Zero under subgrid field */ + + if (!MarkedSubgrids) { + Temp->GridData-> + ZeroSolutionUnderSubgrid(NULL, ZERO_UNDER_SUBGRID_FIELD); + Temp2 = Temp->GridHierarchyEntry->NextGridNextLevel; + while (Temp2 != NULL) { + Temp->GridData->ZeroSolutionUnderSubgrid(Temp2->GridData, + ZERO_UNDER_SUBGRID_FIELD); + Temp2 = Temp2->NextGridThisLevel; + } + } // ENDIF !MarkedSubgrids + /* Sum enclosed mass in this grid. Mass is in Msolar*/ + + Temp->GridData->GetEnclosedMassInShell(SS->pos, Radius-APGrid->CellWidth[0][0], Radius, + ShellMass, ShellMetallicity2, + ShellMetallicity3, + ShellColdGasMass, ShellVelocity, + -1); + + Temp = Temp->NextGridThisLevel; + + } // END: Grids + + } // END: level + MarkedSubgrids = true; + //float values[7]; + //values[0] = ShellMetallicity2; + //values[1] = ShellMetallicity3; + //values[2] = ShellMass; + //values[3] = ShellColdGasMass; + //for (int dim = 0; dim < MAX_DIMENSION; dim++) + // values[4+dim] = ShellVelocity[dim]; + + //LCAPERF_START("star_FindFeedbackSphere_Sum"); + //CommunicationAllSumValues(values, 7); + //LCAPERF_STOP("star_FindFeedbackSphere_Sum"); + + //ShellMetallicity2 = values[0]; + //ShellMetallicity3 = values[1]; + //ShellMass = values[2]; + //ShellColdGasMass = values[3]; + //for (int dim = 0; dim < MAX_DIMENSION; dim++) + // ShellVelocity[dim] = values[4+dim]; + + MassEnclosed += ShellMass; + ColdGasMass += ShellColdGasMass; + // Must first make mass-weighted, then add shell mass-weighted + // (already done in GetEnclosedMassInShell) velocity and + // metallicity. We divide out the mass after checking if mass is + // non-zero. + Metallicity2 = Metallicity2 * (MassEnclosed - ShellMass) + ShellMetallicity2; + Metallicity3 = Metallicity3 * (MassEnclosed - ShellMass) + ShellMetallicity3; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] = AvgVelocity[dim] * (MassEnclosed - ShellMass) + + ShellVelocity[dim]; + printf("MassEnclosed = %e Msolar\n", MassEnclosed); + if (MassEnclosed == 0) { + IsSphereContained = false; + return SUCCESS; + } + + Metallicity2 /= MassEnclosed; + Metallicity3 /= MassEnclosed; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] /= MassEnclosed; + + + /* Now remove mass based on star particle type */ + + if(POPIII == SS->ParticleClass) { + SS->AssignMassFromIMF(); - FLOAT Radius = 0.0; - int feedback_flag = -99999; - float MassEnclosed = 0; - float Metallicity2 = 0; - float Metallicity3 = 0; - float ColdGasMass = 0; - float AvgVelocity[MAX_DIMENSION]; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] = 0.0; - bool SphereTooSmall = true; - float ShellMass, ShellMetallicity2, ShellMetallicity3, ShellColdGasMass, - ShellVelocity[MAX_DIMENSION]; - while (SphereTooSmall) { - Radius += APGrid->CellWidth[0][0]; - bool IsSphereContained = SS->SphereContained(LevelArray, ThisLevel, Radius); - if (IsSphereContained == false) - break; - ShellMass = 0; - ShellMetallicity2 = 0; - ShellMetallicity3 = 0; - ShellColdGasMass = 0; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - ShellVelocity[dim] = 0.0; - - bool MarkedSubgrids = false; - LevelHierarchyEntry *Temp = NULL; - HierarchyEntry *Temp2 = NULL; - for (int l = ThisLevel; l < MAX_DEPTH_OF_HIERARCHY; l++) { - Temp = LevelArray[l]; - while (Temp != NULL) { - - /* Zero under subgrid field */ - - if (!MarkedSubgrids) { - Temp->GridData-> - ZeroSolutionUnderSubgrid(NULL, ZERO_UNDER_SUBGRID_FIELD); - Temp2 = Temp->GridHierarchyEntry->NextGridNextLevel; - while (Temp2 != NULL) { - Temp->GridData->ZeroSolutionUnderSubgrid(Temp2->GridData, - ZERO_UNDER_SUBGRID_FIELD); - Temp2 = Temp2->NextGridThisLevel; - } - } // ENDIF !MarkedSubgrids - - /* Sum enclosed mass in this grid */ - - Temp->GridData->GetEnclosedMassInShell(SS->pos, Radius-APGrid->CellWidth[0][0], Radius, - ShellMass, ShellMetallicity2, - ShellMetallicity3, - ShellColdGasMass, ShellVelocity, - -1); - - Temp = Temp->NextGridThisLevel; - - } // END: Grids - - } // END: level - - MarkedSubgrids = true; - float values[7]; - values[0] = ShellMetallicity2; - values[1] = ShellMetallicity3; - values[2] = ShellMass; - values[3] = ShellColdGasMass; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - values[4+dim] = ShellVelocity[dim]; - - LCAPERF_START("star_FindFeedbackSphere_Sum"); - CommunicationAllSumValues(values, 7); - LCAPERF_STOP("star_FindFeedbackSphere_Sum"); - - ShellMetallicity2 = values[0]; - ShellMetallicity3 = values[1]; - ShellMass = values[2]; - ShellColdGasMass = values[3]; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - ShellVelocity[dim] = values[4+dim]; - - MassEnclosed += ShellMass; - ColdGasMass += ShellColdGasMass; - // Must first make mass-weighted, then add shell mass-weighted - // (already done in GetEnclosedMassInShell) velocity and - // metallicity. We divide out the mass after checking if mass is - // non-zero. - Metallicity2 = Metallicity2 * (MassEnclosed - ShellMass) + ShellMetallicity2; - Metallicity3 = Metallicity3 * (MassEnclosed - ShellMass) + ShellMetallicity3; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] = AvgVelocity[dim] * (MassEnclosed - ShellMass) + - ShellVelocity[dim]; - - if (MassEnclosed == 0) { - IsSphereContained = false; - return SUCCESS; - } - - Metallicity2 /= MassEnclosed; - Metallicity3 /= MassEnclosed; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] /= MassEnclosed; - - - /* Now remove mass based on star particle type */ - - /* Convert CGS density to Msolar */ - double ConversiontoMsolar = 4*pi/3.0 * pow(Radius*LengthUnits, 3)/SolarMass; - if(POPIII == SS->ParticleClass) { - SS->AssignMassFromIMF(); - SphereTooSmall = MassEnclosed < (2*ParticleDensity*DensityUnits*ConversiontoMsolar); - // to make the total mass PopIIIStarMass - StellarMasstoRemove = ParticleDensity*DensityUnits*ConversiontoMsolar; // [Msolar] - } - else if(SMS == SS->ParticleClass) { - /* I think we need a heavy seed IMF here */ - SphereTooSmall = MassEnclosed < (2*ParticleDensity*DensityUnits*ConversiontoMsolar); - StellarMasstoRemove = ParticleDensity*DensityUnits*ConversiontoMsolar; //[Msolar] - } - else if(POPII == SS->ParticleClass) { - float AvgDensity = (float) - (double(SolarMass * MassEnclosed) / - double(4*pi/3.0 * pow(Radius*LengthUnits, 3))); /* cgs density */ - float DynamicalTime = sqrt((3.0 * pi) / (32.0 * GravConst * AvgDensity)) / - TimeUnits; - float ColdGasFraction = ColdGasMass / MassEnclosed; - StellarMasstoRemove = ColdGasFraction * StarClusterFormEfficiency * MassEnclosed; //[Msolar] - SphereTooSmall = DynamicalTime < tdyn_code; - - } - // Remove the stellar mass from the sphere and distribute the - // gas evenly in the sphere since this is what will happen once - // the I-front passes through it. + SphereTooSmall = MassEnclosed < (2*SS->Mass); + // to make the total mass PopIIIStarMass + StellarMasstoRemove = SS->Mass; // [Msolar] - CellDensityAfterFormation = (float) - (double(SolarMass * (MassEnclosed - StellarMasstoRemove)) / - double(4.0*pi/3.0 * POW(Radius*LengthUnits, 3)) / - DensityUnits); /* converted to code density */ - - } /* end while(SphereTooSmall) */ + } + else if(SMS == SS->ParticleClass) { + /* I think we need a heavy seed IMF here */ + SS->Mass = 1000.0; //hardcoding to 1000 Msolar + SS->RadiationLifetime = SmartStarLifetime[SS->ParticleClass]*yr_s/TimeUnits; + SphereTooSmall = MassEnclosed < (2*SS->Mass); + StellarMasstoRemove = SS->Mass; //[Msolar] + } + else if(POPII == SS->ParticleClass) { + float AvgDensity = (float) + (double(SolarMass * MassEnclosed) / + double(4*pi/3.0 * pow(Radius*LengthUnits, 3))); /* cgs density */ + float DynamicalTime = sqrt((3.0 * pi) / (32.0 * GravConst * AvgDensity)) / + TimeUnits; + float ColdGasFraction = ColdGasMass / MassEnclosed; + StellarMasstoRemove = ColdGasFraction * StarClusterFormEfficiency * MassEnclosed; //[Msolar] + SphereTooSmall = DynamicalTime < tdyn_code; + + } + // Remove the stellar mass from the sphere and distribute the + // gas evenly in the sphere since this is what will happen once + // the I-front passes through it. + + CellDensityAfterFormation = (float) + (double(SolarMass * (MassEnclosed - StellarMasstoRemove)) / + double(4.0*pi/3.0 * POW(Radius*LengthUnits, 3)) / + DensityUnits); /* converted to code density */ + + } /* end while(SphereTooSmall) */ #ifdef NOT_NECESSARY /* Don't allow the sphere to be too large (2x leeway) */ const float epsMass = 9.0; @@ -1055,7 +1094,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle } } #endif - + printf("%s: Update Grid Densities (i.e. remove mass)\n", __FUNCTION__); /* The Radius of influence is set by the sphere over which we had to * loop to find sufficient enclosed mass. */ @@ -1111,12 +1150,11 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle float fhz = fh * (1-metallicity); float fhez = (1-fh) * (1-metallicity); SS->BirthTime = APGrid->ReturnTime(); - double ConversiontoMsolar = 4*pi/3.0 * pow(InfluenceRadius*LengthUnits, 3)/SolarMass; - SS->Mass = StellarMasstoRemove/ConversiontoMsolar; //g/cm^3 - SS->Mass /= DensityUnits; //convert to code density + double cellvolume = APGrid->CellWidth[0][i]*APGrid->CellWidth[1][j]* + APGrid->CellWidth[2][k]; + SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/cellvolume; //code density SS->oldmass = SS->Mass; APGrid->BaryonField[DensNum][index] = CellDensityAfterFormation; - if (MultiSpecies) { APGrid->BaryonField[DeNum][index] = APGrid->BaryonField[DensNum][index] * ionizedFraction; APGrid->BaryonField[HINum][index] = APGrid->BaryonField[DensNum][index] * (1-ionizedFraction) * fhz; @@ -1230,7 +1268,6 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, } printf("Accreting: Particle Class %d\n", pclass); - exit(-99); grid* FeedbackZone = ConstructFeedbackZone(ParticleList[i], int(AccretionRadius/dx), dx, Grids, NumberOfGrids, ALL_FIELDS); grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); @@ -1427,19 +1464,22 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, double MassConversion = (double) (dx*dx*dx * double(MassUnits)); //convert to g MassConversion = MassConversion/SolarMass; float ctime = LevelArray[ThisLevel]->GridData->ReturnTime(); + FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc for (int i = 0; i < nParticles; i++) { + grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { ActiveParticleType_SmartStar* SS; SS = static_cast(ParticleList[i]); + #if SSDEBUG printf("%s: deltatime = %f years\t TIMEGAP = %0.2f years\n", __FUNCTION__, (ctime - SS->AccretionRateTime[SS->TimeIndex])*TimeUnits/yr_s, (float)TIMEGAP); #endif //We should update when the time between stored rates exceeds TIMEGAP - if(ctime - SS->AccretionRateTime[SS->TimeIndex] > (TIMEGAP*yr_s/TimeUnits)) { + if(ctime - SS->AccretionRateTime[SS->TimeIndex] > (TIMEGAP*APGrid->ReturnTimeStep())) { float omass = SS->oldmass; float cmass = ParticleList[i]->ReturnMass(); if(cmass - omass < 0.0) { //Can happen after a restart due to rounding @@ -1484,7 +1524,7 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, } else { float Age = Time - SS->BirthTime; - if(Age*TimeUnits/yr_s > 1e4) { /* Don't do this at very start */ + if(Age*TimeUnits/yr_s > 1e4 && SMS == SS->ParticleClass) { /* Don't do this at very start */ printf("%s: WARNING: ParticleClass switching from SMS to POPIII (deltatime = %f kyrs)\n", __FUNCTION__, deltatime*TimeUnits/(yr_s*1e3)); printf("%s: WARNING: Accretion Rate = %f Msolar/yr. Critical rate = %f Msolar/yr\n", __FUNCTION__, diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 98f9f6658..e2430bb4b 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -29,12 +29,12 @@ #include "FofLib.h" #define DEBUG 0 /* Every how many times will the accretion rate be updated */ -#define FREQUENCY 100 +//#define FREQUENCY 100 #define MAXACCRETIONRADIUS 128 /* Times the minimum cell width */ #define ACCRETIONRADIUS 4 #define NUMRADIATIONBINS 5 #define CRITICAL_ACCRETION_RATE 0.001 //Msolar/yr (Haemerlee et al (2018)) -#define TIMEGAP 90 //yrs +#define TIMEGAP 100 // * timestep #define POPIII_RESOLUTION 0.001 //pc #define SMS_RESOLUTION 0.1 //pc /* Prototypes */ @@ -182,12 +182,12 @@ class ActiveParticleType_SmartStar : public ActiveParticleType LevelHierarchyEntry *LevelArray[], int ThisLevel); static float EjectedMassThreshold; FLOAT AccretionRadius; // in units of CellWidth on the maximum refinement level - static int RadiationParticle; + static double LuminosityPerSolarMass; static int RadiationSEDNumberOfBins; static float* RadiationEnergyBins; static float* RadiationSED; - static float RadiationLifetime; + double RadiationLifetime; //float acc[3]; int ParticleClass; @@ -195,7 +195,6 @@ class ActiveParticleType_SmartStar : public ActiveParticleType float AccretionRateTime[NTIMES]; int TimeIndex; float oldmass; //To calculate accmass do accmass = mass - oldmass; oldmass = mass; - static int FeedbackDistTotalCells, FeedbackDistRadius, FeedbackDistCellStep; float NotEjectedMass, eta_disk, mass_in_accretion_sphere, MassToBeEjected; float beta_jet, epsilon_deltat; @@ -236,7 +235,7 @@ void ActiveParticleType_SmartStar::MergeSmartStars( /* Particles merge once they come within 3 accretion radii of one another */ FLOAT MergingRadius = LevelArray[ThisLevel]->GridData->GetCellWidth(0,0)*ACCRETIONRADIUS; - MergingRadius = MergingRadius*3.0; + //MergingRadius = MergingRadius*3.0; for (i=0; i<(*nParticles); i++) { tempPos = ParticleList[i]->ReturnPosition(); for (dim=0; dim<3; dim++) @@ -364,7 +363,6 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( RemoveMassFromGridAfterFormation(nParticles, ParticleList, LevelArray, ThisLevel); - //thisGrid->RemoveMassFromGridAfterFormation(np->pos, np->ParticleClass, np->AccretionRadius, // np->Mass, // index, DensityThreshold, ExtraDensity); diff --git a/src/enzo/ActiveParticle_SphereContained.C b/src/enzo/ActiveParticle_SphereContained.C index 4a01caccc..7c2d32316 100644 --- a/src/enzo/ActiveParticle_SphereContained.C +++ b/src/enzo/ActiveParticle_SphereContained.C @@ -37,7 +37,8 @@ int ActiveParticleType::SphereContained(LevelHierarchyEntry *LevelArray[], int l LevelHierarchyEntry *Temp; int i, dim, direction, cornersContained, Rank, result; bool inside; - int cornerDone[8], Dims[MAX_DIMENSION]; + Eint32 cornerDone[8]; + int Dims[MAX_DIMENSION]; FLOAT corners[MAX_DIMENSION][8]; FLOAT LeftEdge[MAX_DIMENSION], RightEdge[MAX_DIMENSION]; @@ -80,18 +81,10 @@ int ActiveParticleType::SphereContained(LevelHierarchyEntry *LevelArray[], int l } // ENDIF MyProcessorNumber == ProcessorNumber } // ENDFOR grids - /* Take the MPI_MAX of cornerDone flags, then sum them to see if - they equal 8. If so, the sphere is contained within grids on - this level. */ - -#ifdef USE_MPI - CommunicationAllReduceValues(cornerDone, 8, MPI_MAX); -#endif - cornersContained = 0; for (i = 0; i < 8; i++) cornersContained += cornerDone[i]; - + printf("cornersContained = %d\n", cornersContained); result = (cornersContained == 8); LCAPERF_STOP("star_SphereContained"); return result; diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index b90bbcfd5..c36db8ae4 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -171,10 +171,11 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) float x = log10((float)(_mass)); float x2 = x*x; + printf("%s: _mass = %f\n", __FUNCTION__, _mass); if(this->ParticleClass == POPIII) { float E[NUMRADIATIONBINS] = {2.0, 12.8, 28.0, 30.0, 58.0}; - float Q[NUMRADIATIONBINS] = {0.0, 0.0, 0.0, 0.0, 0.0}; + double Q[NUMRADIATIONBINS] = {0.0, 0.0, 0.0, 0.0, 0.0}; for(int bin = 0; bin < NUMRADIATIONBINS; bin++) { this->RadiationEnergyBins[bin] = E[bin]; @@ -190,8 +191,7 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) Q[4] = pow(10.0, 26.71 + 18.14*x - 3.58*x2); //HeII else Q[4] = 0.0; - - } else if (_mass > 5 && _mass <= 9) { + } else if (_mass > 5 && _mass <= 9) { Q[0] = 0.0; //IR Q[1] = pow(10.0, 44.03 + 4.59*x - 0.77*x2); //LW Q[2] = pow(10.0, 39.29 + 8.55*x); //HI @@ -206,14 +206,13 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) } - float QTotal = 0; - for (int bin = 0; bin < NUMRADIATIONBINS; bin++) { - this->RadiationSED[bin] = Q[bin]; - - } + double QTotal = 0; for (int bin = 0; bin < NUMRADIATIONBINS; bin++) QTotal += Q[bin]; for (int bin = 0; bin < NUMRADIATIONBINS; bin++) Q[bin] /= QTotal; - this->LuminosityPerSolarMass = QTotal/_mass; + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) { + this->RadiationSED[bin] = float(Q[bin]); + } + this->LuminosityPerSolarMass = QTotal/double(_mass); } else if(this->ParticleClass == POPII) { float EnergyFractionLW = 1.288; @@ -221,8 +220,8 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) float EnergyFractionHeII = 2.818e-4; float E[NUMRADIATIONBINS] = {2.0, 12.8, 21.62, 30.0, 60.0}; - float Q[NUMRADIATIONBINS] = {0.0, 0.0, 0.0, 0.0, 0.0}; - float Qbase = StarClusterIonizingLuminosity * _mass; + double Q[NUMRADIATIONBINS] = {0.0, 0.0, 0.0, 0.0, 0.0}; + double Qbase = StarClusterIonizingLuminosity * _mass; Q[0] = 0.0; //IR Q[1] = EnergyFractionLW * Qbase; //LW if (StarClusterHeliumIonization) { @@ -234,13 +233,13 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) Q[4] = 0.0; } - float QTotal = 0; - for (int bin = 0; bin < NUMRADIATIONBINS; bin++) { - this->RadiationSED[bin] = Q[bin]; - } + double QTotal = 0; for (int bin = 0; bin < NUMRADIATIONBINS; bin++) QTotal += Q[bin]; for (int bin = 0; bin < NUMRADIATIONBINS; bin++) Q[bin] /= QTotal; - this->LuminosityPerSolarMass = QTotal/_mass; + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) { + this->RadiationSED[bin] = float(Q[bin]); + } + this->LuminosityPerSolarMass = QTotal/double(_mass); } diff --git a/src/enzo/EvolvePhotons.C b/src/enzo/EvolvePhotons.C index 3d75b7d28..0173d8459 100644 --- a/src/enzo/EvolvePhotons.C +++ b/src/enzo/EvolvePhotons.C @@ -298,9 +298,11 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->InitializeTemperatureFieldForComptonHeating() == FAIL) { ENZO_FAIL("Error in InitializeTemperatureFieldForComptonHeating.\n"); - } + } + + printf("%s: RadiativeTransferH2ShieldType = %d\n", __FUNCTION__, RadiativeTransferH2ShieldType); /* Initialize Temperature Field for H2 shielding approximation */ - if(RadiativeTransferH2ShieldType == 1 || ProblemType == 50) { + if(RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) { for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= 0 ; lvl--) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->InitializeTemperatureFieldForH2Shield() == FAIL) { @@ -636,7 +638,7 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], if (Temp->GridData->FinalizeTemperatureFieldForComptonHeating() == FAIL) { ENZO_FAIL("Error in FinalizeTemperatureFieldForComptonHeating.\n"); } - if (RadiativeTransferH2ShieldType == 1 || ProblemType == 50) + if (RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) for (lvl = 0; lvl < MAX_DEPTH_OF_HIERARCHY-1; lvl++) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->FinalizeTemperatureFieldForH2Shield() == FAIL) { diff --git a/src/enzo/Grid_AccreteOntoSmartStarParticle.C b/src/enzo/Grid_AccreteOntoSmartStarParticle.C index 21b444f1c..772a8e5d5 100644 --- a/src/enzo/Grid_AccreteOntoSmartStarParticle.C +++ b/src/enzo/Grid_AccreteOntoSmartStarParticle.C @@ -24,9 +24,9 @@ #include "Hierarchy.h" #include "ActiveParticle.h" #include "ActiveParticle_SmartStar.h" -#define UPDATE_SS_VELOCITY 1 + #define NO_DEBUG_AP -#define ACCRETE_DEBUG 0 +#define ACCRETE_DEBUG 1 #define NO_ACCRETION 0 int GetUnits(float *DensityUnits, float *LengthUnits, @@ -133,14 +133,7 @@ int grid::AccreteOntoSmartStarParticle( printf("%s: AccretedMass = %e\n", __FUNCTION__, AccretedMass); #endif float *Vel = SS->vel; - /* - * I don't think we should update the velocity of the particle - * This breaks conservation of momentum but the momentum is in the subgrid. The - * velocity of the accreted gas is placed in the accretion disk and - * radiated back. The black hole itself probably doesn't move in nature. It - * should not move here either - */ -#if UPDATE_SS_VELOCITY + float NewVelocity[3] = { (Vel[0]+delta_vpart[0]), @@ -149,7 +142,7 @@ int grid::AccreteOntoSmartStarParticle( }; ThisParticle->SetVelocity(NewVelocity); -#endif + /* * This value is the actual accretion rate onto the SmartStar. It was initially * calculated according to some prescription (e.g. Bondi-Hoyle) and then diff --git a/src/enzo/Grid_AddH2DissociationFromSources.C b/src/enzo/Grid_AddH2DissociationFromSources.C index 7566be159..d8758815f 100644 --- a/src/enzo/Grid_AddH2DissociationFromSources.C +++ b/src/enzo/Grid_AddH2DissociationFromSources.C @@ -2,10 +2,11 @@ #define DEBUG 0 #define JEANS_LENGTH 1 -#define SHIELD 1 + /*********************************************************************** / / ADD H2 DISSOCIATION EMISSION FROM SHINING PARTICLES +/ H2 Shielding is on here always. / / written by: John Wise / date: March, 2006 @@ -184,9 +185,11 @@ int grid::AddH2DissociationFromSources(Star *AllStars) double colden = 0.0, shield = 1.0, b = 0.0, b5 = 0.0, XN = 0.0; double H2mass = mh*2.0, alpha = 1.1; double kph_hm = 0.0, kdiss_H2II = 0.0; +#if JEANS_LENGTH int TemperatureField = 0; /* Pre-compute some quantities to speed things up */ TemperatureField = this->GetTemperatureFieldNumberForH2Shield(); +#endif kdiss_r2 = (float) (LWLuminosity * H2ISigma / (4.0 * pi)); kph_hm = (float) (IRLuminosity * HMSigma / (4.0 * pi)); kdiss_H2II = (float) (H2IILuminosity * H2IISigma / (4.0 * pi)); @@ -353,9 +356,11 @@ int grid::AddH2DissociationFromSources(Star *AllStars) double colden = 0.0, shield = 1.0, b = 0.0, b5 = 0.0, XN = 0.0; double H2mass = mh*2.0, alpha = 1.1; double kph_hm = 0.0, kdiss_H2II = 0.0; +#if(JEANS_LENGTH) int TemperatureField = 0; /* Pre-compute some quantities to speed things up */ TemperatureField = this->GetTemperatureFieldNumberForH2Shield(); +#endif kdiss_r2 = (float) (LWLuminosity * H2ISigma / (4.0 * pi)); kph_hm = (float) (IRLuminosity * HMSigma / (4.0 * pi)); kdiss_H2II = (float) (H2IILuminosity * H2IISigma / (4.0 * pi)); @@ -379,7 +384,6 @@ int grid::AddH2DissociationFromSources(Star *AllStars) } /* Include Shielding */ //printf("%s: kdissH2I = %e for Grid %p\n", __FUNCTION__, BaryonField[kdissH2INum][index], this); -#if SHIELD #if(JEANS_LENGTH) l_char = JeansLength(BaryonField[TemperatureField][index], BaryonField[DensNum][index], DensityUnits)*RadiativeTransferOpticallyThinH2CharLength; //cm @@ -405,7 +409,6 @@ int grid::AddH2DissociationFromSources(Star *AllStars) shield = 0.965/pow(1+XN/b5, alpha) + (0.035/sqrt(1+XN))*exp(-8.5e-4*sqrt(1+XN)); } BaryonField[kdissH2INum][index] *= shield; -#endif } //end i loop } //end j loop } //end k loop diff --git a/src/enzo/Grid_ApplySmartStarParticleFeedback.C b/src/enzo/Grid_ApplySmartStarParticleFeedback.C index 2ad7c8c29..583028944 100644 --- a/src/enzo/Grid_ApplySmartStarParticleFeedback.C +++ b/src/enzo/Grid_ApplySmartStarParticleFeedback.C @@ -45,11 +45,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ return SUCCESS; if(SmartStarFeedback == FALSE) return SUCCESS; - if(SmartStarBHFeedback == FALSE) - return SUCCESS; - if (SmartStarBHJetFeedback == FALSE && SmartStarBHThermalFeedback == FALSE) { - return SUCCESS; - } + ActiveParticleType_SmartStar *SS = static_cast(* ThisParticle); const float PISNLowerMass = 140, PISNUpperMass = 260; @@ -198,7 +194,8 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ /*********************************************************************** MBH_THERMAL ************************************************************************/ - + if(SmartStarBHFeedback == FALSE) + return SUCCESS; // Similar to Supernova, but here we assume the followings: // EjectaDensity = 0.0 // EjectaMetalDensity = 0.0 @@ -260,411 +257,411 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ EjectaMetalDensity); } - if(SmartStarBHJetFeedback == TRUE) { - /*********************************************************************** + if(SmartStarBHJetFeedback == FALSE) + return SUCCESS; + /*********************************************************************** MBH_JETS - ************************************************************************/ - - // Inject bipolar jets along the direction of the angular momentum - // vector L of the MBH particle (angular momentum accreted thus far) - // or along the z-axis - Ji-hoon Kim, Nov.2009 - int i = 0, j = 0, k = 0; + ************************************************************************/ + + // Inject bipolar jets along the direction of the angular momentum + // vector L of the MBH particle (angular momentum accreted thus far) + // or along the z-axis - Ji-hoon Kim, Nov.2009 + int i = 0, j = 0, k = 0; #define MAX_SUPERCELL_NUMBER 1000 - int SUPERCELL = 1; //2 for supercell of 5 cells wide = 5^3 - int ind_cell_inside[MAX_SUPERCELL_NUMBER], ind_cell_edge[MAX_SUPERCELL_NUMBER]; - float nx_cell_edge[MAX_SUPERCELL_NUMBER], ny_cell_edge[MAX_SUPERCELL_NUMBER], - nz_cell_edge[MAX_SUPERCELL_NUMBER], anglefactor[MAX_SUPERCELL_NUMBER] = {0}; - int n_cell_inside = 0, n_cell_edge = 0, ibuff = NumberOfGhostZones; - int ii = 0, jj = 0, kk = 0, r_s = 0, ic = 0, sign = 0; - float m_cell_inside = 0.0, m_cell_edge = 0.0; - float L_x, L_y, L_z, L_s, nx_L = 0.0, ny_L = 0.0, nz_L = 0.0, costheta = cos(OPENING_ANGLE); - float SSMass = SS->ReturnMass(); - float totalenergybefore = 0.0, totalenergyafter = 0.0, totalenergyadded = 0.0; - float sumkeadded = 0.0; - - if (SmartStarBHJetFeedback == FALSE || SS->MassToBeEjected*MassUnits/SolarMass < 1e-10) { - return SUCCESS; - } - - /* i, j, k are the number of cells from the edge of the grid to the smartstar*/ - i = (int)((pos[0] - this->CellLeftEdge[0][0]) / dx); - j = (int)((pos[1] - this->CellLeftEdge[1][0]) / dx); - k = (int)((pos[2] - this->CellLeftEdge[2][0]) / dx); - - /* Note that we need to inject feedback only for the finest grid the SS belongs to */ - - if (i < ibuff || i > this->GridDimension[0]-ibuff-1 || - j < ibuff || j > this->GridDimension[1]-ibuff-1 || - k < ibuff || k > this->GridDimension[2]-ibuff-1 || - this == NULL || - SS->level < MaximumRefinementLevel) { - fprintf(stdout, "grid::AddFS: MBH_JETS - MBH doesn't belong to this grid.\n"); - return SUCCESS; - } - + int SUPERCELL = 1; //2 for supercell of 5 cells wide = 5^3 + int ind_cell_inside[MAX_SUPERCELL_NUMBER], ind_cell_edge[MAX_SUPERCELL_NUMBER]; + float nx_cell_edge[MAX_SUPERCELL_NUMBER], ny_cell_edge[MAX_SUPERCELL_NUMBER], + nz_cell_edge[MAX_SUPERCELL_NUMBER], anglefactor[MAX_SUPERCELL_NUMBER] = {0}; + int n_cell_inside = 0, n_cell_edge = 0, ibuff = NumberOfGhostZones; + int ii = 0, jj = 0, kk = 0, r_s = 0, ic = 0, sign = 0; + float m_cell_inside = 0.0, m_cell_edge = 0.0; + float L_x, L_y, L_z, L_s, nx_L = 0.0, ny_L = 0.0, nz_L = 0.0, costheta = cos(OPENING_ANGLE); + float SSMass = SS->ReturnMass(); + float totalenergybefore = 0.0, totalenergyafter = 0.0, totalenergyadded = 0.0; + float sumkeadded = 0.0; + + if (SmartStarBHJetFeedback == FALSE || SS->MassToBeEjected*MassUnits/SolarMass < 1e-10) { + return SUCCESS; + } + + /* i, j, k are the number of cells from the edge of the grid to the smartstar*/ + i = (int)((pos[0] - this->CellLeftEdge[0][0]) / dx); + j = (int)((pos[1] - this->CellLeftEdge[1][0]) / dx); + k = (int)((pos[2] - this->CellLeftEdge[2][0]) / dx); + + /* Note that we need to inject feedback only for the finest grid the SS belongs to */ + + if (i < ibuff || i > this->GridDimension[0]-ibuff-1 || + j < ibuff || j > this->GridDimension[1]-ibuff-1 || + k < ibuff || k > this->GridDimension[2]-ibuff-1 || + this == NULL || + SS->level < MaximumRefinementLevel) { + fprintf(stdout, "grid::AddFS: MBH_JETS - MBH doesn't belong to this grid.\n"); + return SUCCESS; + } + - /* find mdot */ - float mdot = SS->AccretionRate[SS->TimeIndex]; - float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses - float eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(SS->eta_disk*clight*sigma_thompson); // g/s - eddrate = eddrate*3.154e7/SolarMass; //in Msolar/yr - - float AccretionRate = mdot*MassUnits/(SolarMass*TimeUnits); //in Msolar/s - /* - * Now in the case where we are subgriding the accretion formalism - * re-calculate the actual accretion rate and check if we are in the correct band - */ - //AccretionRate *= SS->epsilon_deltat; - - /* Debug */ - printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\t Ratio = %f\n", __FUNCTION__, - eddrate, AccretionRate*3.154e7, AccretionRate*3.154e7/eddrate); - printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); - printf("%s: AccretionRate (*deltat) = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, - AccretionRate*3.154e7, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); - float MassEjected = SS->NotEjectedMass + SS->MassToBeEjected; //code mass - - - SS->NotEjectedMass = MassEjected; + /* find mdot */ + float mdot = SS->AccretionRate[SS->TimeIndex]; + float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses + float eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(SS->eta_disk*clight*sigma_thompson); // g/s + eddrate = eddrate*3.154e7/SolarMass; //in Msolar/yr + + float AccretionRate = mdot*MassUnits/(SolarMass*TimeUnits); //in Msolar/s + /* + * Now in the case where we are subgriding the accretion formalism + * re-calculate the actual accretion rate and check if we are in the correct band + */ + //AccretionRate *= SS->epsilon_deltat; + + /* Debug */ + printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\t Ratio = %f\n", __FUNCTION__, + eddrate, AccretionRate*3.154e7, AccretionRate*3.154e7/eddrate); + printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); + printf("%s: AccretionRate (*deltat) = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, + AccretionRate*3.154e7, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); + float MassEjected = SS->NotEjectedMass + SS->MassToBeEjected; //code mass + + + SS->NotEjectedMass = MassEjected; #if IMPOSETHRESHOLD #if SSFEED_DEBUG - printf("SSFEED_DEBUG: %s: Mass Accumulated thus far = %e Msolar (Threshold = %e Msolar)\n", - __FUNCTION__, SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); + printf("SSFEED_DEBUG: %s: Mass Accumulated thus far = %e Msolar (Threshold = %e Msolar)\n", + __FUNCTION__, SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); #endif - if (SS->NotEjectedMass*MassUnits/SolarMass <= SS->EjectedMassThreshold) { - fprintf(stdout, "grid::AddFS: MBH_JETS - accumulated mass (%f Msolar) not passed threshold (%f Msolar).\n", - SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); - return SUCCESS; - } + if (SS->NotEjectedMass*MassUnits/SolarMass <= SS->EjectedMassThreshold) { + fprintf(stdout, "grid::AddFS: MBH_JETS - accumulated mass (%f Msolar) not passed threshold (%f Msolar).\n", + SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); + return SUCCESS; + } #endif - - if(AccretionRate*3.154e7/eddrate < 1e-30 || AccretionRate*3.154e7/eddrate > 1.0) + + if(AccretionRate*3.154e7/eddrate < 1e-30 || AccretionRate*3.154e7/eddrate > 1.0) { printf("%s: AccrateionRateRatio = %f. We are in the right band to release jets\n", __FUNCTION__, AccretionRate*3.154e7/eddrate); } - else - { - printf("%s: AccrateionRateRatio = %f. No jets this time\n", __FUNCTION__, - AccretionRate*3.154e7/eddrate); - return SUCCESS; - } - /*end Debug*/ + else + { + printf("%s: AccrateionRateRatio = %f. No jets this time\n", __FUNCTION__, + AccretionRate*3.154e7/eddrate); + return SUCCESS; + } + /*end Debug*/ + - #if SSFEED_DEBUG - - printf("SSFEED_DEBUG: %s: Mass Accreted = %e Msolar\t Mass to be Ejected = %e Msolar\n", - __FUNCTION__, mdot*dt*MassUnits/SolarMass, MassEjected*MassUnits/SolarMass); + + printf("SSFEED_DEBUG: %s: Mass Accreted = %e Msolar\t Mass to be Ejected = %e Msolar\n", + __FUNCTION__, mdot*dt*MassUnits/SolarMass, MassEjected*MassUnits/SolarMass); #endif + + if (i < ibuff+SUPERCELL || i > this->GridDimension[0]-ibuff-SUPERCELL-1 || + j < ibuff+SUPERCELL || j > this->GridDimension[1]-ibuff-SUPERCELL-1 || + k < ibuff+SUPERCELL || k > this->GridDimension[2]-ibuff-SUPERCELL-1) { + fprintf(stdout, "grid::AddFS: MBH_JETS - supercell not contained; accumulated mass (%g MSolar).\n", + SS->NotEjectedMass*MassUnits/SolarMass); - if (i < ibuff+SUPERCELL || i > this->GridDimension[0]-ibuff-SUPERCELL-1 || - j < ibuff+SUPERCELL || j > this->GridDimension[1]-ibuff-SUPERCELL-1 || - k < ibuff+SUPERCELL || k > this->GridDimension[2]-ibuff-SUPERCELL-1) { - fprintf(stdout, "grid::AddFS: MBH_JETS - supercell not contained; accumulated mass (%g MSolar).\n", - SS->NotEjectedMass*MassUnits/SolarMass); - - // if the supercell issue hasn't allowed the jet injection for too long, - // issue a warning signal and output the current hierarchy at CheckForOutput - if (SS->NotEjectedMass*MassUnits/SolarMass > 2.0 * SS->EjectedMassThreshold) { - fprintf(stdout, "grid::AddFS: MBH_JETS - jets haven't been ejected for too long!\n"); - } - - // otherwise, just proceed and do it later - return SUCCESS; - } - printf("SSFEED_DEBUG: %s: Lets Eject!!!!!!!!!!!\n", __FUNCTION__); + // if the supercell issue hasn't allowed the jet injection for too long, + // issue a warning signal and output the current hierarchy at CheckForOutput + if (SS->NotEjectedMass*MassUnits/SolarMass > 2.0 * SS->EjectedMassThreshold) { + fprintf(stdout, "grid::AddFS: MBH_JETS - jets haven't been ejected for too long!\n"); + } + + // otherwise, just proceed and do it later + return SUCCESS; + } + printf("SSFEED_DEBUG: %s: Lets Eject!!!!!!!!!!!\n", __FUNCTION__); #if IMPOSETHRESHOLD - float MassKeptInReserve = max(MassEjected - THRESHOLDFRACTION*SolarMass/MassUnits, 0.0); - MassEjected = MassEjected - MassKeptInReserve; + float MassKeptInReserve = max(MassEjected - THRESHOLDFRACTION*SolarMass/MassUnits, 0.0); + MassEjected = MassEjected - MassKeptInReserve; #endif - printf("Cumulative Mass to be ejected in jet will be %f Msolar\n", MassEjected*MassUnits/SolarMass); - /* Find the directional vector n_L of angular momentum accreted thus far */ - if(SS->CalculateAccretedAngularMomentum() == FAIL) { - return FAIL; - } - L_x = SS->Accreted_angmom[0]; - L_y = SS->Accreted_angmom[1]; - L_z = SS->Accreted_angmom[2]; - L_s = sqrt(pow(L_x,2) + pow(L_y,2) + pow(L_z,2)); - nx_L = L_x/L_s; //normalized directional vector - ny_L = L_y/L_s; - nz_L = L_z/L_s; - L_s = sqrt(pow(nx_L,2) + pow(ny_L,2) + pow(nz_L,2)); - printf("%s: Angular momentum = %e %e %e\t L_s = %e\n", __FUNCTION__, - nx_L, ny_L, nz_L, L_s); - //nx_L = 0.0; - //ny_L = 0.0; - //nz_L = 1.0; - //L_s = sqrt(pow(nx_L,2) + pow(ny_L,2) + pow(nz_L,2)); - //printf("%s: Angular momentum = %e %e %e\t L_s = %e\n", __FUNCTION__, - // nx_L, ny_L, nz_L, L_s); + printf("Cumulative Mass to be ejected in jet will be %f Msolar\n", MassEjected*MassUnits/SolarMass); + /* Find the directional vector n_L of angular momentum accreted thus far */ + if(SS->CalculateAccretedAngularMomentum() == FAIL) { + return FAIL; + } + L_x = SS->Accreted_angmom[0]; + L_y = SS->Accreted_angmom[1]; + L_z = SS->Accreted_angmom[2]; + L_s = sqrt(pow(L_x,2) + pow(L_y,2) + pow(L_z,2)); + nx_L = L_x/L_s; //normalized directional vector + ny_L = L_y/L_s; + nz_L = L_z/L_s; + L_s = sqrt(pow(nx_L,2) + pow(ny_L,2) + pow(nz_L,2)); + printf("%s: Angular momentum = %e %e %e\t L_s = %e\n", __FUNCTION__, + nx_L, ny_L, nz_L, L_s); + //nx_L = 0.0; + //ny_L = 0.0; + //nz_L = 1.0; + //L_s = sqrt(pow(nx_L,2) + pow(ny_L,2) + pow(nz_L,2)); + //printf("%s: Angular momentum = %e %e %e\t L_s = %e\n", __FUNCTION__, + // nx_L, ny_L, nz_L, L_s); - /* Loop over the supercell around the MBH particle (5 * 5 * 5 = 125 cells, - but only the edges), and record the cells eligible for jet injection */ - int nsupercells = 0; - for (kk = -SUPERCELL; kk <= SUPERCELL; kk++) { - for (jj = -SUPERCELL; jj <= SUPERCELL; jj++) { - for (ii = -SUPERCELL; ii <= SUPERCELL; ii++) { - nsupercells++; - r_s = sqrt(pow(ii,2) + pow(jj,2) + pow(kk,2)); - if (fabs(ii) != SUPERCELL && fabs(jj) != SUPERCELL && fabs(kk) != SUPERCELL) { //if not on edges - // printf("%s: Inside: CosTheta = %f\t cellangle = %f (%f degrees)\n", __FUNCTION__, - // costheta, fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s), - // (360/pi)*acos(fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s))); - ind_cell_inside[n_cell_inside] = i+ii+(j+jj+(k+kk)*this->GridDimension[1])*this->GridDimension[0]; - m_cell_inside += this->BaryonField[DensNum][ind_cell_inside[n_cell_inside]] * - pow(dx, 3); - n_cell_inside++; + /* Loop over the supercell around the MBH particle (5 * 5 * 5 = 125 cells, + but only the edges), and record the cells eligible for jet injection */ + int nsupercells = 0; + for (kk = -SUPERCELL; kk <= SUPERCELL; kk++) { + for (jj = -SUPERCELL; jj <= SUPERCELL; jj++) { + for (ii = -SUPERCELL; ii <= SUPERCELL; ii++) { + nsupercells++; + r_s = sqrt(pow(ii,2) + pow(jj,2) + pow(kk,2)); + if (fabs(ii) != SUPERCELL && fabs(jj) != SUPERCELL && fabs(kk) != SUPERCELL) { //if not on edges + // printf("%s: Inside: CosTheta = %f\t cellangle = %f (%f degrees)\n", __FUNCTION__, + // costheta, fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s), + // (360/pi)*acos(fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s))); + ind_cell_inside[n_cell_inside] = i+ii+(j+jj+(k+kk)*this->GridDimension[1])*this->GridDimension[0]; + m_cell_inside += this->BaryonField[DensNum][ind_cell_inside[n_cell_inside]] * + pow(dx, 3); + n_cell_inside++; + + } else { //if on edges + if (fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s) > costheta) { + //printf("%s: Edge: CosTheta = %f\t cellangle = %f (%f degrees)\n", __FUNCTION__, + // costheta, fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s), + // (360/pi)*acos(fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s))); + anglefactor[n_cell_edge] = fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s); + ind_cell_edge[n_cell_edge] = i+ii+(j+jj+(k+kk)*this->GetGridDimension(1))*this->GetGridDimension(0); + nx_cell_edge[n_cell_edge] = ii / r_s; //directional vector + ny_cell_edge[n_cell_edge] = jj / r_s; + nz_cell_edge[n_cell_edge] = kk / r_s; + m_cell_edge += this->BaryonField[DensNum][ind_cell_edge[n_cell_edge]] * + pow(this->GetCellWidth(0, 0), 3); - } else { //if on edges - if (fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s) > costheta) { - //printf("%s: Edge: CosTheta = %f\t cellangle = %f (%f degrees)\n", __FUNCTION__, - // costheta, fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s), - // (360/pi)*acos(fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s))); - anglefactor[n_cell_edge] = fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s); - ind_cell_edge[n_cell_edge] = i+ii+(j+jj+(k+kk)*this->GetGridDimension(1))*this->GetGridDimension(0); - nx_cell_edge[n_cell_edge] = ii / r_s; //directional vector - ny_cell_edge[n_cell_edge] = jj / r_s; - nz_cell_edge[n_cell_edge] = kk / r_s; - m_cell_edge += this->BaryonField[DensNum][ind_cell_edge[n_cell_edge]] * - pow(this->GetCellWidth(0, 0), 3); - - totalenergybefore += this->BaryonField[TENum][ind_cell_edge[n_cell_edge]]; - n_cell_edge++; - - } - - } - - } // END ii-direction - } // END jj-direction - } // END kk-direction + totalenergybefore += this->BaryonField[TENum][ind_cell_edge[n_cell_edge]]; + n_cell_edge++; + + } + + } + + } // END ii-direction + } // END jj-direction + } // END kk-direction #if SSFEED_DEBUG - printf("%s: n_cell_inside = %d\n", __FUNCTION__, n_cell_inside); - printf("%s: n_cell_edge = %d\n", __FUNCTION__, n_cell_edge); - printf("%s: nsupercells = %d\n", __FUNCTION__, nsupercells); + printf("%s: n_cell_inside = %d\n", __FUNCTION__, n_cell_inside); + printf("%s: n_cell_edge = %d\n", __FUNCTION__, n_cell_edge); + printf("%s: nsupercells = %d\n", __FUNCTION__, nsupercells); #endif - /* Calculate the jet density - * This is the mass of the ejected mass + the mass at the cell edges - */ - - float rho_jet = (MassEjected) / - ((float)n_cell_edge * pow(this->GetCellWidth(0,0), 3)); //In code units + /* Calculate the jet density + * This is the mass of the ejected mass + the mass at the cell edges + */ + + float rho_jet = (MassEjected) / + ((float)n_cell_edge * pow(this->GetCellWidth(0,0), 3)); //In code units #if SSFEED_DEBUG - printf("%s: rho_jet (per cell) = %e cc", __FUNCTION__, rho_jet*DensityUnits/mh); + printf("%s: rho_jet (per cell) = %e cc", __FUNCTION__, rho_jet*DensityUnits/mh); #endif - /* Calculate MBHJetsVelocity using energy conservation below: - SmartStarFeedbackEnergyCoupling = The fraction of feedback energy that is - mechanically (for MBH_JETS) coupled to the gas. - SmartStarFeedbackRadiativeEfficiency - The radiative efficiency of a black hole. - - MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency * Mdot * c^2 - = 0.5 * MBHFeedbackMassEjectionFraction * Mdot * (MBHJetsVelocity)^2 - - Note that EjectaThermalEnergy is never used; MBHFeedbackEnergyCoupling - should now be calculated considering gravitational redshift (Kim et al. 2010) - - float MBHJetsVelocity = clight * sqrt( 2 * MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency - / MBHFeedbackMassEjectionFraction ) / VelocityUnits; - */ - - /* This is really a bit of a cod and it may be better to set the jet velocity as some fraction of the - * speed of light. */ - float MBHJetsVelocity = clight * SmartStarJetVelocity/VelocityUnits; //code velocity - - /* Ramp up over RAMPTIME yrs */ - float Age = this->ReturnTime() - SS->BirthTime; - Age = Age*TimeUnits/3.154e7; - if(Age < RAMPTIME) - { - printf("%s: Too early for jets. Age = %f yrs\n", __FUNCTION__, Age); - return SUCCESS; - MBHJetsVelocity = MBHJetsVelocity*Age/(float)RAMPTIME; - } - - float jetenergy = 0.5*MBHJetsVelocity*MBHJetsVelocity; + /* Calculate MBHJetsVelocity using energy conservation below: + SmartStarFeedbackEnergyCoupling = The fraction of feedback energy that is + mechanically (for MBH_JETS) coupled to the gas. + SmartStarFeedbackRadiativeEfficiency - The radiative efficiency of a black hole. + + MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency * Mdot * c^2 + = 0.5 * MBHFeedbackMassEjectionFraction * Mdot * (MBHJetsVelocity)^2 + + Note that EjectaThermalEnergy is never used; MBHFeedbackEnergyCoupling + should now be calculated considering gravitational redshift (Kim et al. 2010) + + float MBHJetsVelocity = clight * sqrt( 2 * MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency + / MBHFeedbackMassEjectionFraction ) / VelocityUnits; + */ + + /* This is really a bit of a cod and it may be better to set the jet velocity as some fraction of the + * speed of light. */ + float MBHJetsVelocity = clight * SmartStarJetVelocity/VelocityUnits; //code velocity + + /* Ramp up over RAMPTIME yrs */ + float Age = this->ReturnTime() - SS->BirthTime; + Age = Age*TimeUnits/3.154e7; + if(Age < RAMPTIME) + { + printf("%s: Too early for jets. Age = %f yrs\n", __FUNCTION__, Age); + return SUCCESS; + MBHJetsVelocity = MBHJetsVelocity*Age/(float)RAMPTIME; + } + + float jetenergy = 0.5*MBHJetsVelocity*MBHJetsVelocity; #if SSFEED_DEBUG - printf("%s: Age = %f yrs\n", __FUNCTION__, Age); - printf("%s: Jet Energy = %e (specific = %e)\n", __FUNCTION__, jetenergy*MassEjected, jetenergy); - printf("SSFEED_DEBUG: %s: MBHJetsVelocity = %e of clight (%f km/s)\n", __FUNCTION__, - MBHJetsVelocity * VelocityUnits/clight, - MBHJetsVelocity*VelocityUnits/1e5 ); - printf("SSFEED_DEBUG: %s: SmartStarJetVelocity = %e\n", __FUNCTION__, SmartStarJetVelocity); + printf("%s: Age = %f yrs\n", __FUNCTION__, Age); + printf("%s: Jet Energy = %e (specific = %e)\n", __FUNCTION__, jetenergy*MassEjected, jetenergy); + printf("SSFEED_DEBUG: %s: MBHJetsVelocity = %e of clight (%f km/s)\n", __FUNCTION__, + MBHJetsVelocity * VelocityUnits/clight, + MBHJetsVelocity*VelocityUnits/1e5 ); + printf("SSFEED_DEBUG: %s: SmartStarJetVelocity = %e\n", __FUNCTION__, SmartStarJetVelocity); #endif - if (MBHJetsVelocity * VelocityUnits > 0.99*clight) { - ENZO_VFAIL("grid::AddFS: MBHJetsVelocity is ultra-relativistic! (%g/ %g/ %g/ %g c)\n", - MBHFeedbackEnergyCoupling, MBHFeedbackRadiativeEfficiency, - MBHFeedbackMassEjectionFraction, MBHJetsVelocity * VelocityUnits / clight); - } - - /* Finally, add the jet feedback at the edges (outer part of the supercell) */ + if (MBHJetsVelocity * VelocityUnits > 0.99*clight) { + ENZO_VFAIL("grid::AddFS: MBHJetsVelocity is ultra-relativistic! (%g/ %g/ %g/ %g c)\n", + MBHFeedbackEnergyCoupling, MBHFeedbackRadiativeEfficiency, + MBHFeedbackMassEjectionFraction, MBHJetsVelocity * VelocityUnits / clight); + } - for (ic = 0; ic < n_cell_edge; ic++) { - - int index = ind_cell_edge[ic]; - float angle = anglefactor[ic]; - float cellnumberdensity = this->BaryonField[DensNum][index]*DensityUnits/mh; - - /* Update velocities and TE; note that we now have kinetic (jet) energy added, so - for DualEnergyFormalism = 0 you don't have to update any energy field */ - - sign = sign(nx_cell_edge[ic]*nx_L + ny_cell_edge[ic]*ny_L + nz_cell_edge[ic]*nz_L); + /* Finally, add the jet feedback at the edges (outer part of the supercell) */ - /* Calculate grid velocity: the actual veloctiy injected in supercell edges. - This is different from MBHJetsVelocity because it is the mass-weighted average - between MBHJetsVelocity and the original veloctiy in grid */ - float oldvel[3] = {this->BaryonField[Vel1Num][index], - this->BaryonField[Vel2Num][index], - this->BaryonField[Vel3Num][index]}; - float oldcellmass = this->BaryonField[DensNum][index] * pow(this->GetCellWidth(0,0), 3); - float energybefore = this->BaryonField[TENum][index]; - + for (ic = 0; ic < n_cell_edge; ic++) { + + int index = ind_cell_edge[ic]; + float angle = anglefactor[ic]; + float cellnumberdensity = this->BaryonField[DensNum][index]*DensityUnits/mh; + + /* Update velocities and TE; note that we now have kinetic (jet) energy added, so + for DualEnergyFormalism = 0 you don't have to update any energy field */ + + sign = sign(nx_cell_edge[ic]*nx_L + ny_cell_edge[ic]*ny_L + nz_cell_edge[ic]*nz_L); + + /* Calculate grid velocity: the actual veloctiy injected in supercell edges. + This is different from MBHJetsVelocity because it is the mass-weighted average + between MBHJetsVelocity and the original veloctiy in grid */ + float oldvel[3] = {this->BaryonField[Vel1Num][index], + this->BaryonField[Vel2Num][index], + this->BaryonField[Vel3Num][index]}; + float oldcellmass = this->BaryonField[DensNum][index] * pow(this->GetCellWidth(0,0), 3); + float energybefore = this->BaryonField[TENum][index]; + #if DENSITY_WEIGHTED - int dim = 0; - if (GENum >= 0 && DualEnergyFormalism) - for (dim = 0; dim < GridRank; dim++) - this->BaryonField[TENum][index] -= - 0.5 * this->BaryonField[Vel1Num+dim][index] * - this->BaryonField[Vel1Num+dim][index]; - - this->BaryonField[Vel1Num][index] = (this->BaryonField[DensNum][index] * this->BaryonField[Vel1Num][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * - sign * nx_L * MBHJetsVelocity) / - (this->BaryonField[DensNum][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); - this->BaryonField[Vel2Num][index] = (this->BaryonField[DensNum][index] * - this->BaryonField[Vel2Num][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * - sign * ny_L * MBHJetsVelocity) / - (this->BaryonField[DensNum][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); - this->BaryonField[Vel3Num][index] = (this->BaryonField[DensNum][index] * - this->BaryonField[Vel3Num][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * - sign * nz_L * MBHJetsVelocity) / - (this->BaryonField[DensNum][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); - - float newvel[3] = {this->BaryonField[Vel1Num][index], - this->BaryonField[Vel2Num][index], - this->BaryonField[Vel3Num][index]}; - float newvelmag = sqrt(newvel[0]*newvel[0] + newvel[1]*newvel[1] + newvel[2]*newvel[2]); - float energytoadd = 0.5*newvelmag*newvelmag; - - if (GENum >= 0 && DualEnergyFormalism) - for (dim = 0; dim < GridRank; dim++) - this->BaryonField[TENum][index] += - 0.5 * this->BaryonField[Vel1Num+dim][index] * - this->BaryonField[Vel1Num+dim][index]; - + int dim = 0; + if (GENum >= 0 && DualEnergyFormalism) + for (dim = 0; dim < GridRank; dim++) + this->BaryonField[TENum][index] -= + 0.5 * this->BaryonField[Vel1Num+dim][index] * + this->BaryonField[Vel1Num+dim][index]; + + this->BaryonField[Vel1Num][index] = (this->BaryonField[DensNum][index] * this->BaryonField[Vel1Num][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * + sign * nx_L * MBHJetsVelocity) / + (this->BaryonField[DensNum][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); + this->BaryonField[Vel2Num][index] = (this->BaryonField[DensNum][index] * + this->BaryonField[Vel2Num][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * + sign * ny_L * MBHJetsVelocity) / + (this->BaryonField[DensNum][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); + this->BaryonField[Vel3Num][index] = (this->BaryonField[DensNum][index] * + this->BaryonField[Vel3Num][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * + sign * nz_L * MBHJetsVelocity) / + (this->BaryonField[DensNum][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); + + float newvel[3] = {this->BaryonField[Vel1Num][index], + this->BaryonField[Vel2Num][index], + this->BaryonField[Vel3Num][index]}; + float newvelmag = sqrt(newvel[0]*newvel[0] + newvel[1]*newvel[1] + newvel[2]*newvel[2]); + float energytoadd = 0.5*newvelmag*newvelmag; + + if (GENum >= 0 && DualEnergyFormalism) + for (dim = 0; dim < GridRank; dim++) + this->BaryonField[TENum][index] += + 0.5 * this->BaryonField[Vel1Num+dim][index] * + this->BaryonField[Vel1Num+dim][index]; + #elif SINE_WAVE - this->BaryonField[Vel1Num][index] += sign * nx_L * MBHJetsVelocity * angle; - this->BaryonField[Vel2Num][index] += sign * ny_L * MBHJetsVelocity * angle; - this->BaryonField[Vel3Num][index] += sign * nz_L * MBHJetsVelocity * angle; - float v_ejecta[3] = { sign * nx_L * MBHJetsVelocity * angle, - sign * ny_L * MBHJetsVelocity * angle, - sign * nz_L * MBHJetsVelocity * angle}; - float v_ejectamag = sqrt(v_ejecta[0]*v_ejecta[0] + v_ejecta[1]*v_ejecta[1] + v_ejecta[2]*v_ejecta[2]); - float keadded = 0.5*(MassEjected/(float)n_cell_edge)*v_ejectamag*v_ejectamag; - - /* Update the new total energy. - * keadded is due to the new grid velocities. - * eint does not change - */ - if (GENum >= 0 && DualEnergyFormalism) - this->BaryonField[TENum][index] += keadded/MassEjected; - - + this->BaryonField[Vel1Num][index] += sign * nx_L * MBHJetsVelocity * angle; + this->BaryonField[Vel2Num][index] += sign * ny_L * MBHJetsVelocity * angle; + this->BaryonField[Vel3Num][index] += sign * nz_L * MBHJetsVelocity * angle; + float v_ejecta[3] = { sign * nx_L * MBHJetsVelocity * angle, + sign * ny_L * MBHJetsVelocity * angle, + sign * nz_L * MBHJetsVelocity * angle}; + float v_ejectamag = sqrt(v_ejecta[0]*v_ejecta[0] + v_ejecta[1]*v_ejecta[1] + v_ejecta[2]*v_ejecta[2]); + float keadded = 0.5*(MassEjected/(float)n_cell_edge)*v_ejectamag*v_ejectamag; + + /* Update the new total energy. + * keadded is due to the new grid velocities. + * eint does not change + */ + if (GENum >= 0 && DualEnergyFormalism) + this->BaryonField[TENum][index] += keadded/MassEjected; + + #else - this->BaryonField[Vel1Num][index] += sign * nx_L * MBHJetsVelocity; - this->BaryonField[Vel2Num][index] += sign * ny_L * MBHJetsVelocity; - this->BaryonField[Vel3Num][index] += sign * nz_L * MBHJetsVelocity; - float newvel[3] = {this->BaryonField[Vel1Num][index], - this->BaryonField[Vel2Num][index], - this->BaryonField[Vel3Num][index]}; - float oldvelmag = sqrt(oldvel[0]*oldvel[0] + oldvel[1]*oldvel[1] + oldvel[2]*oldvel[2]); - float newvelmag = sqrt(newvel[0]*newvel[0] + newvel[1]*newvel[1] + newvel[2]*newvel[2]); - float kebefore = 0.5*(oldcellmass)*oldvelmag*oldvelmag; - float keafter = 0.5*(oldcellmass + (MassEjected/(float)n_cell_edge))*newvelmag*newvelmag; - float v_ejecta[3] = { sign * nx_L * MBHJetsVelocity, - sign * ny_L * MBHJetsVelocity, - sign * nz_L * MBHJetsVelocity}; - float v_ejectamag = sqrt(v_ejecta[0]*v_ejecta[0] + v_ejecta[1]*v_ejecta[1] + v_ejecta[2]*v_ejecta[2]); - float keadded = 0.5*(MassEjected/(float)n_cell_edge)*v_ejectamag*v_ejectamag; - - /* Update the new total energy. - * keadded is due to the new grid velocities. - * eint does not change - */ - totalenergyadded += keadded; - //#if SSFEED_DEBUG - //printf("%s: SSFEED_DEBUG: Adding %e energy to TE. This increases TE by a factor of %e\n", - // __FUNCTION__, keadded/MassEjected, (energybefore + keadded/MassEjected)/energybefore); - //#endif - if (GENum >= 0 && DualEnergyFormalism) - this->BaryonField[TENum][index] += keadded/MassEjected; - - totalenergyafter += this->BaryonField[TENum][index]; - //#if SSFEED_DEBUG - // printf("EnergyConservation: Total Energy Added = %e\n", totalenergyadded); - //printf("EnergyConservation: Delta Grid Energy = %e (with mass = %e)\t Jet Energy = %e\n", - // totalenergyafter - totalenergybefore, (totalenergyafter - totalenergybefore)*MassEjected, - // jetenergy); - //#endif - totalenergyafter = 0; totalenergybefore = 0;totalenergyadded= 0; + this->BaryonField[Vel1Num][index] += sign * nx_L * MBHJetsVelocity; + this->BaryonField[Vel2Num][index] += sign * ny_L * MBHJetsVelocity; + this->BaryonField[Vel3Num][index] += sign * nz_L * MBHJetsVelocity; + float newvel[3] = {this->BaryonField[Vel1Num][index], + this->BaryonField[Vel2Num][index], + this->BaryonField[Vel3Num][index]}; + float oldvelmag = sqrt(oldvel[0]*oldvel[0] + oldvel[1]*oldvel[1] + oldvel[2]*oldvel[2]); + float newvelmag = sqrt(newvel[0]*newvel[0] + newvel[1]*newvel[1] + newvel[2]*newvel[2]); + float kebefore = 0.5*(oldcellmass)*oldvelmag*oldvelmag; + float keafter = 0.5*(oldcellmass + (MassEjected/(float)n_cell_edge))*newvelmag*newvelmag; + float v_ejecta[3] = { sign * nx_L * MBHJetsVelocity, + sign * ny_L * MBHJetsVelocity, + sign * nz_L * MBHJetsVelocity}; + float v_ejectamag = sqrt(v_ejecta[0]*v_ejecta[0] + v_ejecta[1]*v_ejecta[1] + v_ejecta[2]*v_ejecta[2]); + float keadded = 0.5*(MassEjected/(float)n_cell_edge)*v_ejectamag*v_ejectamag; + + /* Update the new total energy. + * keadded is due to the new grid velocities. + * eint does not change + */ + totalenergyadded += keadded; + //#if SSFEED_DEBUG + //printf("%s: SSFEED_DEBUG: Adding %e energy to TE. This increases TE by a factor of %e\n", + // __FUNCTION__, keadded/MassEjected, (energybefore + keadded/MassEjected)/energybefore); + //#endif + if (GENum >= 0 && DualEnergyFormalism) + this->BaryonField[TENum][index] += keadded/MassEjected; + + totalenergyafter += this->BaryonField[TENum][index]; + //#if SSFEED_DEBUG + // printf("EnergyConservation: Total Energy Added = %e\n", totalenergyadded); + //printf("EnergyConservation: Delta Grid Energy = %e (with mass = %e)\t Jet Energy = %e\n", + // totalenergyafter - totalenergybefore, (totalenergyafter - totalenergybefore)*MassEjected, + // jetenergy); + //#endif + totalenergyafter = 0; totalenergybefore = 0;totalenergyadded= 0; #endif - //return SUCCESS; //works - //printf("DeltaGrid = %e\n", this->BaryonField[TENum][index] - energybefore); - - /* Update density, species and colour fields */ - float OldDensity = this->BaryonField[DensNum][index]; - float increase = (OldDensity + rho_jet) / OldDensity; - this->BaryonField[DensNum][index] += rho_jet; - //printf("%s: Increase in Density due to Jet = %e\n", __FUNCTION__, increase); - if (MultiSpecies) { - this->BaryonField[DeNum][index] *= increase; - this->BaryonField[HINum][index] *= increase; - this->BaryonField[HIINum][index] *= increase; - this->BaryonField[HeINum][index] *= increase; - this->BaryonField[HeIINum][index] *= increase; - this->BaryonField[HeIIINum][index] *= increase; - } - if (MultiSpecies > 1) { - this->BaryonField[HMNum][index] *= increase; - this->BaryonField[H2INum][index] *= increase; - this->BaryonField[H2IINum][index] *= increase; - } - if (MultiSpecies > 2) { - this->BaryonField[DINum][index] *= increase; - this->BaryonField[DIINum][index] *= increase; - this->BaryonField[HIINum][index] *= increase; - this->BaryonField[HDINum][index] *= increase; - } - - + //return SUCCESS; //works + //printf("DeltaGrid = %e\n", this->BaryonField[TENum][index] - energybefore); + + /* Update density, species and colour fields */ + float OldDensity = this->BaryonField[DensNum][index]; + float increase = (OldDensity + rho_jet) / OldDensity; + this->BaryonField[DensNum][index] += rho_jet; + //printf("%s: Increase in Density due to Jet = %e\n", __FUNCTION__, increase); + if (MultiSpecies) { + this->BaryonField[DeNum][index] *= increase; + this->BaryonField[HINum][index] *= increase; + this->BaryonField[HIINum][index] *= increase; + this->BaryonField[HeINum][index] *= increase; + this->BaryonField[HeIINum][index] *= increase; + this->BaryonField[HeIIINum][index] *= increase; } + if (MultiSpecies > 1) { + this->BaryonField[HMNum][index] *= increase; + this->BaryonField[H2INum][index] *= increase; + this->BaryonField[H2IINum][index] *= increase; + } + if (MultiSpecies > 2) { + this->BaryonField[DINum][index] *= increase; + this->BaryonField[DIINum][index] *= increase; + this->BaryonField[HIINum][index] *= increase; + this->BaryonField[HDINum][index] *= increase; + } + + + } #if IMPOSETHRESHOLD - SS->NotEjectedMass = MassKeptInReserve; - printf("Mass left over for next jet = %f Msolar\n", SS->NotEjectedMass*MassUnits/SolarMass); - SS->EjectedMassThreshold = THRESHOLDFRACTION; - if(SS->EjectedMassThreshold < 1e-3) - SS->EjectedMassThreshold = 1e-3; - SS->NotEjectedMass = 0.0; + SS->NotEjectedMass = MassKeptInReserve; + printf("Mass left over for next jet = %f Msolar\n", SS->NotEjectedMass*MassUnits/SolarMass); + SS->EjectedMassThreshold = THRESHOLDFRACTION; + if(SS->EjectedMassThreshold < 1e-3) + SS->EjectedMassThreshold = 1e-3; + SS->NotEjectedMass = 0.0; #if SSFEED_DEBUG - printf("%s: New threshold Mass set to %e Msolar, total BH Mass = %e Msolar\n", __FUNCTION__, - SS->EjectedMassThreshold, SS->Mass*MassConversion/SolarMass); + printf("%s: New threshold Mass set to %e Msolar, total BH Mass = %e Msolar\n", __FUNCTION__, + SS->EjectedMassThreshold, SS->Mass*MassConversion/SolarMass); #endif #else - SS->NotEjectedMass = 0.0; + SS->NotEjectedMass = 0.0; #endif - - } - return SUCCESS; + + return SUCCESS; } diff --git a/src/enzo/RadiativeTransferInitialize.C b/src/enzo/RadiativeTransferInitialize.C index dae308f3c..0147f83aa 100644 --- a/src/enzo/RadiativeTransferInitialize.C +++ b/src/enzo/RadiativeTransferInitialize.C @@ -206,8 +206,9 @@ int RadiativeTransferInitialize(char *ParameterFile, TypesToAdd[FieldsToAdd++] = Metallicity; AddedMetallicity = true; } - if (StarClusterUseMetalField && + if (StarClusterUseMetalField && SmartStarFeedback > 0) { + printf("JR: Adding SS field"); TypesToAdd[FieldsToAdd++] = Metallicity; AddedMetallicity = true; } @@ -290,6 +291,7 @@ int RadiativeTransferInitialize(char *ParameterFile, "from %"ISYM" to %"ISYM"\n", OldNumberOfBaryonFields, OldNumberOfBaryonFields+FieldsToAdd); + printf("JR: OldNumberOfBaryonFields+FieldsToAdd = %d\n", OldNumberOfBaryonFields+FieldsToAdd); // Add an extra 1 because we will need it for flagging/marking cells. if (OldNumberOfBaryonFields+FieldsToAdd+1 > MAX_NUMBER_OF_BARYON_FIELDS) ENZO_FAIL("Exceeds MAX_NUMBER_OF_BARYON_FIELDS. " diff --git a/src/enzo/RadiativeTransferReadParameters.C b/src/enzo/RadiativeTransferReadParameters.C index 5d92a88be..7a792d931 100644 --- a/src/enzo/RadiativeTransferReadParameters.C +++ b/src/enzo/RadiativeTransferReadParameters.C @@ -78,7 +78,7 @@ int RadiativeTransferReadParameters(FILE *fptr) RadiativeTransferLoadBalance = FALSE; RadiativeTransferRayMaximumLength = 1.7320508; //sqrt(3.0) RadiativeTransferUseH2Shielding = TRUE; - RadiativeTransferH2ShieldType = 0; + RadiativeTransferH2ShieldType = 1; RadiativeTransferH2IIDiss = TRUE; RadiativeTransferHubbleTimeFraction = 0.1; diff --git a/src/enzo/TemperatureFieldToolsH2Shielding.C b/src/enzo/TemperatureFieldToolsH2Shielding.C index c1030dc64..2c2a1605a 100644 --- a/src/enzo/TemperatureFieldToolsH2Shielding.C +++ b/src/enzo/TemperatureFieldToolsH2Shielding.C @@ -30,8 +30,8 @@ int grid::InitializeTemperatureFieldForH2Shield() if (MyProcessorNumber != ProcessorNumber) return SUCCESS; - if (RadiativeTransferH2ShieldType != 1) - return SUCCESS; + //if (RadiativeTransferH2ShieldType != 1) + // return SUCCESS; int TemperatureField, size = 1; float *temperature; @@ -50,8 +50,7 @@ int grid::InitializeTemperatureFieldForH2Shield() for (int i = 0; i < size; i++) BaryonField[TemperatureField][i] = temperature[i]; - - delete [] temperature; + delete [] temperature; return SUCCESS; } @@ -62,8 +61,8 @@ int grid::FinalizeTemperatureFieldForH2Shield() if (MyProcessorNumber != ProcessorNumber) return SUCCESS; - if (RadiativeTransferH2ShieldType != 1) - return SUCCESS; + //if (RadiativeTransferH2ShieldType != 1) + // return SUCCESS; int TemperatureField; TemperatureField = this->GetTemperatureFieldNumberForH2Shield(); From ab4beb44700a0aba2d216eb19e78c8877be6a15c Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 5 Feb 2021 12:19:47 +0000 Subject: [PATCH 081/115] gamma version of low resolution smartstars --- src/enzo/ActiveParticleRoutines.C | 20 +- src/enzo/ActiveParticle_SmartStar.C | 259 ++++++++++++------ src/enzo/ActiveParticle_SmartStar.h | 62 +++-- src/enzo/DetermineSEDParameters.C | 2 +- src/enzo/EvolvePhotons.C | 1 - src/enzo/Grid_AccreteOntoSmartStarParticle.C | 3 +- .../Grid_ApplySmartStarParticleFeedback.C | 65 +++-- src/enzo/Grid_ApplySphericalFeedbackToGrid.C | 4 + .../Grid_CalculateSmartStarAccretionRate.C | 1 + src/enzo/ReadParameterFile.C | 1 + src/enzo/SetDefaultGlobalValues.C | 1 + src/enzo/StarParticleData.h | 1 + src/enzo/StarParticlePopIII_IMFInitialize.C | 46 +++- src/enzo/Star_AssignFinalMassFromIMF.C | 3 +- 14 files changed, 333 insertions(+), 136 deletions(-) diff --git a/src/enzo/ActiveParticleRoutines.C b/src/enzo/ActiveParticleRoutines.C index ed87ee846..48dd06fd1 100644 --- a/src/enzo/ActiveParticleRoutines.C +++ b/src/enzo/ActiveParticleRoutines.C @@ -242,7 +242,6 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) { int dim; double ratio1, ratio2; - ratio1 = Mass / (Mass + a->Mass); ratio2 = 1.0 - ratio1; Metallicity = ratio1 * Metallicity + ratio2 * a->Metallicity; @@ -251,8 +250,8 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) vel[dim] = ratio1 * vel[dim] + ratio2 * a->vel[dim]; } + if(Mass > a->Mass) { - RadiationLifetime = -99.0; ; } else { @@ -265,10 +264,16 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) AccretionRate[i] = a->AccretionRate[i]; } RadiationLifetime = a->RadiationLifetime; + StellarAge = a->StellarAge; } Mass += a->Mass; NotEjectedMass += a->NotEjectedMass; ParticleClass = max(ParticleClass, a->ParticleClass); + WillDelete = min(WillDelete, a->WillDelete); + /* We should update the Lifetime after a merger I think....*/ //TODO + //float logm = log10((float)(this->Mass); + //RadiationLifetime = POW(10.0, (9.785 - 3.759*logm + 1.413*logm*logm - + // 0.186*logm*logm*logm)) / (TimeUnits/yr_s); return; } @@ -507,12 +512,14 @@ void ActiveParticleType_SmartStar::AssignMassFromIMF() VelocityUnits, MassConversion; GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, CurrentGrid->Time); + unsigned_long_int random_int = mt_random(); const int max_random = (1<<16); float x = (float) (random_int%max_random) / (float) (max_random); float dm = log10(PopIIIUpperMassCutoff / PopIIILowerMassCutoff) / (float) (IMF_TABLE_ENTRIES-1); - + + printf("%s: random_int = %lld\n x = %f\n", __FUNCTION__, random_int, x); /* (binary) search for the mass bin corresponding to the random number */ @@ -534,12 +541,13 @@ void ActiveParticleType_SmartStar::AssignMassFromIMF() /* Adjust the lifetime (taken from the fit in Schaerer 2002) now we know the stellar mass. It was set to the lifetime of a star with M=PopIIILowerMassCutoff in pop3_maker.src as a placeholder. */ - float logm = log10((float)this->Mass); // First in years, then convert to code units this->RadiationLifetime = POW(10.0, (9.785 - 3.759*logm + 1.413*logm*logm - 0.186*logm*logm*logm)) / (TimeUnits/yr_s); - printf("%s: Mass assigned from IMF = %e Msolar\t Lifetime = %e\n", __FUNCTION__, this->Mass, - this->RadiationLifetime*TimeUnits/yr_s); + + printf("%s: Mass assigned from IMF = %e Msolar\t Lifetime = %1.5f Myr\n", __FUNCTION__, this->Mass, + this->RadiationLifetime*TimeUnits/Myr_s); + } diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index bd904dd11..0eabcf2cf 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -9,7 +9,7 @@ #include "ActiveParticle_SmartStar.h" #include "phys_constants.h" -#define SSDEBUG 1 +#define SSDEBUG 0 #define SSDEBUG_TOTALMASS 0 #define DYNAMIC_ACCRETION_RADIUS 0 @@ -24,7 +24,6 @@ #define NUMSSPARTICLETYPES 4 int DetermineSEDParameters(ActiveParticleType_SmartStar *SS,FLOAT Time, FLOAT dx); - /* We need to make sure that we can operate on the grid, so this dance is * necessary to make sure that grid is 'friend' to this particle type. */ @@ -42,7 +41,6 @@ double ActiveParticleType_SmartStar::LuminosityPerSolarMass = FLOAT_UNDEFINED; int ActiveParticleType_SmartStar::RadiationSEDNumberOfBins = INT_UNDEFINED; float* ActiveParticleType_SmartStar::RadiationEnergyBins = NULL; float* ActiveParticleType_SmartStar::RadiationSED = NULL; -//float ActiveParticleType_SmartStar::RadiationLifetime = FLOAT_UNDEFINED; int ActiveParticleType_SmartStar::FeedbackDistRadius = INT_UNDEFINED; int ActiveParticleType_SmartStar::FeedbackDistTotalCells = INT_UNDEFINED; int ActiveParticleType_SmartStar::FeedbackDistCellStep = INT_UNDEFINED; @@ -51,7 +49,7 @@ static void UpdateAccretionRadius(ActiveParticleType* ThisParticle, float newma FLOAT AccretionRadius, FLOAT dx, float avgtemp, float mass_units, float length_units); static float GetStellarRadius(float cmass, float accrate); -int StarParticlePopIII_IMFInitialize(void); +int SmartStarPopIII_IMFInitialize(void); int ActiveParticleType_SmartStar::InitializeParticleType() { @@ -92,6 +90,7 @@ int ActiveParticleType_SmartStar::InitializeParticleType() ah.push_back(new Handler("AccretionRadius")); ah.push_back(new Handler("ParticleClass")); ah.push_back(new Handler("RadiationLifetime")); + ah.push_back(new Handler("StellarAge")); ah.push_back(new Handler("NotEjectedMass")); ah.push_back(new Handler("MassToBeEjected")); ah.push_back(new Handler("eta_disk")); @@ -109,9 +108,10 @@ int ActiveParticleType_SmartStar::InitializeParticleType() //ah.push_back(new ArrayHandler("particle_acceleration_z", 2)); /* Initialize the IMF lookup table if requested and not defined */ + /* Generate a list of all sink particles in the simulation box */ if (PopIIIInitialMassFunction) - StarParticlePopIII_IMFInitialize(); + SmartStarPopIII_IMFInitialize(); printf("SmartStar Initialisation complete\n"); fflush(stdout); return SUCCESS; @@ -126,8 +126,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation SmartStarLifetime[1] = 2e6; //in yrs SmartStarLifetime[2] = 1e20; //in yrs SmartStarLifetime[3] = 2e7; //in yrs - - // No need to do the rest if we're not on the maximum refinement level. + // No need to do the rest if we're not on the maximum refinement level. if (data.level != MaximumRefinementLevel) return SUCCESS; @@ -179,6 +178,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation if (CellFlaggingMethod[method] == 6) JeansRefinement = true; } + #if SSDEBUG fprintf(stdout, "%s: Right half thinking of creating a SmartSink particle\n", __FUNCTION__); fflush(stdout); #endif @@ -201,7 +201,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation #if JEANSREFINEMENT if (JeansRefinement) { CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : data.Temperature[index]; - int JeansFactor = 8; //RefineByJeansLengthSafetyFactor + int JeansFactor = 1; //RefineByJeansLengthSafetyFactor JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / POW(data.LengthUnits*dx*JeansFactor,2); @@ -385,7 +385,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation } if(stellar_type < 0) - continue; + continue; ActiveParticleType_SmartStar *np = new ActiveParticleType_SmartStar(); data.NumberOfNewParticles++; @@ -407,9 +407,6 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->pos[1] = thisGrid->CellLeftEdge[1][j] + 0.5*thisGrid->CellWidth[1][j]; np->pos[2] = thisGrid->CellLeftEdge[2][k] + 0.5*thisGrid->CellWidth[2][k]; - printf("pos = %f %f %f\n", np->pos[0], np->pos[1], np->pos[2]); - printf("GridLeftEdge = %f %f %f\n", thisGrid->CellLeftEdge[0][0], - thisGrid->CellLeftEdge[1][0], thisGrid->CellLeftEdge[2][0]); float *apvel = new float[MAX_DIMENSION]; /* Calculate AP velocity by taking average of * surrounding 125 cells @@ -437,6 +434,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->AccretionRateTime[0] = np->BirthTime; np->RadiationLifetime= SmartStarLifetime[np->ParticleClass]*yr_s/data.TimeUnits; + np->StellarAge = 0.0; np->NotEjectedMass = 0.0; /* The mass of the particles formed depends on the resolution and is handled @@ -447,6 +445,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation * We set the initial mass to zero so that merging works ok i.e. nothing spurious * happens in this case. */ + np->Mass = 0.0; //printf("%s: Total Mass in Accretion Region = %g Msolar (Threshold = %g)\n", __FUNCTION__, // TotalMass*ConverttoSolar, (double)MASSTHRESHOLD); @@ -727,9 +726,6 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel if(ThisParticle->DetermineSEDParameters(Time, dx) == FAIL) return FAIL; - printf("%s: Mass = %e\t RadiationLifetime = %e yrs\n", __FUNCTION__, PMass, - ThisParticle->RadiationLifetime*TimeUnits/yr_s); fflush(stdout); - source->LifeTime = ThisParticle->RadiationLifetime; source->Luminosity = (ThisParticle->LuminosityPerSolarMass * LConv) * PMass; source->RampTime = ramptime; @@ -739,13 +735,21 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel for (j = 0; j < RadiationSEDNumberOfBins; j++) { source->Energy[j] = ThisParticle->RadiationEnergyBins[j]; source->SED[j] = ThisParticle->RadiationSED[j]; + } - // printf("%s: source->Lifetime = %f years\n", __FUNCTION__, source->LifeTime*TimeUnits/yr_s); - // printf("%s: Energy = %f %f %f %f %f\n", __FUNCTION__, source->Energy[0], - // source->Energy[1], source->Energy[2], source->Energy[3], source->Energy[4]); - //printf("%s: SED = %f %f %f %f %f\n", __FUNCTION__, source->SED[0], - // source->SED[1], source->SED[2], source->SED[3], source->SED[4]); + #if SSDEBUG + printf("%s: SS (%d) Energy Bins = %1.1f (%1.1f) %1.1f (%1.1f) %1.1f (%1.1f) " \ + "%1.1f (%1.1f) %1.1f (%1.1f)\n", __FUNCTION__, + ThisParticle->ParticleClass, ThisParticle->RadiationEnergyBins[0], + ThisParticle->RadiationSED[0], + ThisParticle->RadiationEnergyBins[1],ThisParticle->RadiationSED[1], + ThisParticle->RadiationEnergyBins[2],ThisParticle->RadiationSED[2], + ThisParticle->RadiationEnergyBins[3],ThisParticle->RadiationSED[3], + ThisParticle->RadiationEnergyBins[4],ThisParticle->RadiationSED[4]); + + + if(ThisParticle->ParticleClass == SMS) { printf("%s: !!!!!!!!!!!!!!!!!!!!!!!!SRC Luminosity: L=%lg Lcode=%g M=%g Mcode=%g\n", __FUNCTION__, ThisParticle->LuminosityPerSolarMass * ThisParticle->Mass * MassConversion, @@ -764,7 +768,6 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel GlobalRadiationSources->NextSource->PreviousSource = source; GlobalRadiationSources->NextSource = source; } - exit(-99); } } // ENDIF CallEvolvePhotons @@ -792,7 +795,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle SmartStarLifetime[1] = 2e6; //in yrs SmartStarLifetime[2] = 1e20; //in yrs SmartStarLifetime[3] = 2e7; //in yrs - + int SSparticles[nParticles] = {-1}; float StellarMasstoRemove = 0.0, CellDensityAfterFormation = 0.0; /* Skip accretion if we're not on the maximum refinement level. This should only ever happen right after creation and then @@ -810,12 +813,57 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle MassUnits = DensityUnits * POW(LengthUnits,3); float tdyn_code = StarClusterMinDynamicalTime/(TimeUnits/yr_s); + + /* + * Order particles in order of SMS, PopIII, PopII + * SMS first since they have the highest accretion rates and hence + * should be forming first + */ + int k = 0, num_new_sms_stars = 0, num_new_popiii_stars = 0, num_new_popii_stars = 0; for (int i = 0; i < nParticles; i++) { - grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); + grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); + if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { + ActiveParticleType_SmartStar* SS; + SS = static_cast(ParticleList[i]); + if(SS->ParticleClass == SMS && SS->TimeIndex == 0) { + SSparticles[k++] = i; + num_new_sms_stars++; + } + } + } + for (int i = 0; i < nParticles; i++) { + grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); + if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { + ActiveParticleType_SmartStar* SS; + SS = static_cast(ParticleList[i]); + if(SS->ParticleClass == POPIII && SS->TimeIndex == 0) { + SSparticles[k++] = i; + num_new_popiii_stars++; + } + } + } + for (int i = 0; i < nParticles; i++) { + grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); + if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { + ActiveParticleType_SmartStar* SS; + SS = static_cast(ParticleList[i]); + if(SS->ParticleClass == POPII && SS->TimeIndex == 0) { + SSparticles[k++] = i; + num_new_popii_stars++; + } + } + } + int num_new_stars = num_new_sms_stars + num_new_popiii_stars + num_new_popii_stars; + if(num_new_stars == 0) + return SUCCESS; + + for (int k = 0; k < num_new_stars; k++) { + int pindex = SSparticles[k]; + grid* APGrid = ParticleList[pindex]->ReturnCurrentGrid(); if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { ActiveParticleType_SmartStar* SS; - SS = static_cast(ParticleList[i]); + SS = static_cast(ParticleList[pindex]); /* * Only interested in newly formed particles @@ -853,13 +901,9 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle cellindex_y = (SS->pos[1] - APGrid->CellLeftEdge[1][0])/dx, cellindex_z = (SS->pos[2] - APGrid->CellLeftEdge[2][0])/dx; - - printf("SS->Pos = %f %f %f\n", SS->pos[0], SS->pos[1], SS->pos[2]); - printf("GridLeftEdge = %f %f %f\n", APGrid->CellLeftEdge[0][0], APGrid->CellLeftEdge[1][0], - APGrid->CellLeftEdge[2][0]); int cellindex = APGrid->GetIndex(cellindex_x, cellindex_y, cellindex_z); float DensityThreshold = ActiveParticleDensityThreshold*mh/DensityUnits; - + #if JEANSREFINEMENT bool JeansRefinement = false; for (int method = 0; method < MAX_FLAGGING_METHODS; method++) @@ -870,7 +914,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle float *Temperature = new float[size](); APGrid->ComputeTemperatureField(Temperature); float CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : Temperature[cellindex]; - int JeansFactor = 8; //RefineByJeansLengthSafetyFactor + int JeansFactor = 1; //RefineByJeansLengthSafetyFactor float JeansDensityUnitConversion = (Gamma*pi*kboltz) / (Mu*mh*GravConst); float JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / POW(LengthUnits*dx*JeansFactor,2); @@ -880,14 +924,6 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle #endif float ParticleDensity = density[cellindex] - DensityThreshold; - if(ParticleDensity < 0.0) { - printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); - printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); - printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); - printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); - ENZO_FAIL("Particle Density is negative. Oh dear.\n"); - } - float newcelldensity = density[cellindex] - ParticleDensity; if(SMS == SS->ParticleClass) { @@ -896,7 +932,15 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle SS->BirthTime = APGrid->ReturnTime(); SS->Mass = ParticleDensity; SS->oldmass = SS->Mass; - return SUCCESS; + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + ENZO_FAIL("Particle Density is negative. Oh dear.\n"); + } + printf("SMS: cellindex %d updated - next.\n\n", cellindex); + continue; } } @@ -906,7 +950,15 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle SS->BirthTime = APGrid->ReturnTime(); SS->Mass = ParticleDensity; SS->oldmass = SS->Mass; - return SUCCESS; + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + ENZO_FAIL("Particle Density is negative. Oh dear.\n"); + } + printf("POPIII: cellindex %d updated - next.\n\n", cellindex); + continue; } } else if(POPII == SS->ParticleClass) { @@ -919,7 +971,15 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle SS->BirthTime = APGrid->ReturnTime(); SS->Mass = StarClusterFormEfficiency*density[cellindex]; SS->oldmass = SS->Mass; - return SUCCESS; + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + ENZO_FAIL("Particle Density is negative. Oh dear.\n"); + } + printf("POPII: cellindex %d updated - next.\n\n", cellindex); + continue; } } @@ -937,6 +997,17 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle ***********************************************************************/ printf("%s: Low resolution run.....\n", __FUNCTION__); + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + /* Mark particle for deletion */ + SS->WillDelete = true; + printf("Too late. Star is destroyed by surrounding SF. Particle %d deleted.\n", pindex); + + continue; + } FLOAT Radius = 0.0; int feedback_flag = -99999; float MassEnclosed = 0; @@ -996,25 +1067,6 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle } // END: level MarkedSubgrids = true; - //float values[7]; - //values[0] = ShellMetallicity2; - //values[1] = ShellMetallicity3; - //values[2] = ShellMass; - //values[3] = ShellColdGasMass; - //for (int dim = 0; dim < MAX_DIMENSION; dim++) - // values[4+dim] = ShellVelocity[dim]; - - //LCAPERF_START("star_FindFeedbackSphere_Sum"); - //CommunicationAllSumValues(values, 7); - //LCAPERF_STOP("star_FindFeedbackSphere_Sum"); - - //ShellMetallicity2 = values[0]; - //ShellMetallicity3 = values[1]; - //ShellMass = values[2]; - //ShellColdGasMass = values[3]; - //for (int dim = 0; dim < MAX_DIMENSION; dim++) - // ShellVelocity[dim] = values[4+dim]; - MassEnclosed += ShellMass; ColdGasMass += ShellColdGasMass; // Must first make mass-weighted, then add shell mass-weighted @@ -1026,7 +1078,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle for (int dim = 0; dim < MAX_DIMENSION; dim++) AvgVelocity[dim] = AvgVelocity[dim] * (MassEnclosed - ShellMass) + ShellVelocity[dim]; - printf("MassEnclosed = %e Msolar\n", MassEnclosed); + printf("MassEnclosed = %e Msolar\n", MassEnclosed); fflush(stdout); if (MassEnclosed == 0) { IsSphereContained = false; return SUCCESS; @@ -1042,16 +1094,18 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle if(POPIII == SS->ParticleClass) { SS->AssignMassFromIMF(); - + SS->StellarAge = SS->RadiationLifetime; SphereTooSmall = MassEnclosed < (2*SS->Mass); // to make the total mass PopIIIStarMass StellarMasstoRemove = SS->Mass; // [Msolar] - + printf("%s: Mass = %e Msolar\t StellarAge = %e Myr\n", __FUNCTION__, + SS->Mass, SS->StellarAge*TimeUnits/Myr_s); } else if(SMS == SS->ParticleClass) { /* I think we need a heavy seed IMF here */ SS->Mass = 1000.0; //hardcoding to 1000 Msolar SS->RadiationLifetime = SmartStarLifetime[SS->ParticleClass]*yr_s/TimeUnits; + SS->StellarAge = SS->RadiationLifetime; SphereTooSmall = MassEnclosed < (2*SS->Mass); StellarMasstoRemove = SS->Mass; //[Msolar] } @@ -1098,7 +1152,10 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle /* The Radius of influence is set by the sphere over which we had to * loop to find sufficient enclosed mass. */ - float InfluenceRadius = Radius; + SS->InfluenceRadius = Radius; + printf("%s: Particle Mass = %1.1f Msolar\n", __FUNCTION__, SS->Mass); + printf("%s: Particle Class = %d\n", __FUNCTION__, SS->ParticleClass); + printf("%s: Remove mass from sphere of radius %lf pc\n", __FUNCTION__, Radius*LengthUnits/pc_cm); /* Update cell information */ int index = 0; FLOAT delx = 0.0, dely = 0.0, delz = 0.0, radius2 = 0.0, DomainWidth[MAX_DIMENSION]; @@ -1138,7 +1195,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle delx = min(delx, DomainWidth[0]-delx); radius2 = delx*delx + dely*dely + delz*delz; - if (radius2 <= InfluenceRadius*InfluenceRadius) { + if (radius2 <= SS->InfluenceRadius*SS->InfluenceRadius) { radius2 = max(radius2, 0.0625*APGrid->CellWidth[0][i]*APGrid->CellWidth[0][i]); // (0.25*dx)^2 @@ -1182,11 +1239,13 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle } // END j-direction } // END k-direction - + } /*This Processor */ - } /* End loop over APs */ - return SUCCESS; + + } /* End loop over APs */ + + return SUCCESS; } int ActiveParticleType_SmartStar::Accrete(int nParticles, ActiveParticleList& ParticleList, @@ -1223,9 +1282,19 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, float SubtractedMass, SubtractedMomentum[3] = {}; NumberOfGrids = GenerateGridArray(LevelArray, ThisLevel, &Grids); + float ctime = LevelArray[ThisLevel]->GridData->ReturnTime(); + /* + * TimeDelay if we want to delay the time between + * turning on accretion following a supernova. + * In testing I didn't observe any difference. + * Hence, the TimeDelay is set to a short period + * of 100,000 years which accounts for end of snowplough + * period + */ + float TimeDelay = 1e5*yr_s/TimeUnits; //set to 100 kyr for (i = 0; i < nParticles; i++) { - + /* * Accretion is only allowed if it makes sense: @@ -1240,6 +1309,8 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, AccretionRadius = static_cast(ParticleList[i])->AccretionRadius; int pclass = static_cast(ParticleList[i])->ParticleClass; FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc + int Stellar_Age = static_cast(ParticleList[i])->StellarAge; + float p_age = ctime - static_cast(ParticleList[i])->BirthTime; if(pclass == POPIII) { /* * We only accrete onto POPIII stars if our maximum @@ -1258,8 +1329,14 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, } else if(pclass == BH) { - /* We always accrete onto BHs */ - ; + /* We always accrete onto BHs. The only restriction is that + * we can optionally employ a time delay following a SNe explosion to + * avoid spurious accretion. + */ + + if(p_age < Stellar_Age + TimeDelay) + continue; + } else if(pclass == POPII) { /* We never accrete onto POPII stars */ @@ -1267,14 +1344,13 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, } - printf("Accreting: Particle Class %d\n", pclass); grid* FeedbackZone = ConstructFeedbackZone(ParticleList[i], int(AccretionRadius/dx), dx, Grids, NumberOfGrids, ALL_FIELDS); grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); if (MyProcessorNumber == FeedbackZone->ReturnProcessorNumber()) { float AccretionRate = 0; - + if (FeedbackZone->AccreteOntoSmartStarParticle(ParticleList[i], AccretionRadius, &AccretionRate) == FAIL) return FAIL; @@ -1374,12 +1450,17 @@ int ActiveParticleType_SmartStar::SmartStarParticleFeedback(int nParticles, if (FeedbackZone->ApplySmartStarParticleFeedback(&ParticleList[i]) == FAIL) return FAIL; } - + /* If a PISN just went off then we can safely delete the particle. */ + if(ParticleList[i]->ShouldDelete() == true) { + printf("%s: Delete SS %d following PISN\n", __FUNCTION__, + static_cast(ParticleList[i])->ReturnID()); + fflush(stdout); + ParticleList.erase(i); + } DistributeFeedbackZone(FeedbackZone, Grids, NumberOfGrids, ALL_FIELDS); delete FeedbackZone; } - delete [] Grids; return SUCCESS; } @@ -1466,24 +1547,25 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, float ctime = LevelArray[ThisLevel]->GridData->ReturnTime(); FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc for (int i = 0; i < nParticles; i++) { - grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); - - if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { + if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { ActiveParticleType_SmartStar* SS; SS = static_cast(ParticleList[i]); - -#if SSDEBUG + #if SSDEBUG printf("%s: deltatime = %f years\t TIMEGAP = %0.2f years\n", __FUNCTION__, (ctime - SS->AccretionRateTime[SS->TimeIndex])*TimeUnits/yr_s, (float)TIMEGAP); #endif + //We should update when the time between stored rates exceeds TIMEGAP - if(ctime - SS->AccretionRateTime[SS->TimeIndex] > (TIMEGAP*APGrid->ReturnTimeStep())) { + if( (ctime - SS->AccretionRateTime[SS->TimeIndex] > (TIMEGAP*APGrid->ReturnTimeStep())) + || (SS->TimeIndex == 0)) { float omass = SS->oldmass; float cmass = ParticleList[i]->ReturnMass(); - if(cmass - omass < 0.0) { //Can happen after a restart due to rounding - break; + if(cmass - omass < -1e-10) { //Can happen after a restart due to rounding + printf("Updating masses....\n"); + printf("cmass = %e\t omass = %e\n", cmass, omass); + cmass = omass; } SS->TimeIndex++; @@ -1499,19 +1581,21 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, float deltatime = ctime - otime; float accrate = (cmass - omass)/deltatime; - + float Age = ctime - SS->BirthTime; SS->AccretionRate[timeindex] = accrate*dx*dx*dx; SS->AccretionRateTime[timeindex] = ctime; SS->oldmass = cmass; SS->TimeIndex = timeindex; - fprintf(stdout, "old_mass = %e Msolar\t cmass = %e Msolar\n", omass*MassConversion, - cmass*MassConversion); - fprintf(stdout, "accrate = %e Msolar/yr\t accratetime = %e yrs \t deltatime = %f yrs\t index = %d\t Particle Mass = %e Msolar\t Class = %d\n", + fprintf(stdout, "old_mass = %e Msolar\t cmass = (%e code) %e Msolar\n", omass*MassConversion, + cmass, cmass*MassConversion); + fprintf(stdout, "accrate = %e Msolar/yr\t accratetime = %e yrs \t deltatime = %f yrs\t index = %d\t Particle Mass = %e Msolar\t Age = %1.3f\t Myr Lifetime = %1.2f Myr\t Class = %d\n", (SS->AccretionRate[timeindex]*MassUnits/TimeUnits)*yr_s/SolarMass, (SS->AccretionRateTime[timeindex]*TimeUnits)/yr_s, deltatime*TimeUnits/yr_s, SS->TimeIndex, SS->ReturnMass()*MassConversion, + Age*TimeUnits/Myr_s, + SS->RadiationLifetime*TimeUnits/Myr_s, SS->ParticleClass); if(SS->ParticleClass < BH) { /* @@ -1540,6 +1624,7 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, #if SSDEBUG printf("Done in %s\n", __FUNCTION__); #endif + return SUCCESS; } diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index e2430bb4b..4b0bf5759 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -66,6 +66,8 @@ class ActiveParticleType_SmartStar : public ActiveParticleType // Constructors ActiveParticleType_SmartStar(void) : ActiveParticleType() { AccretionRadius = -1; + RadiationLifetime = 0.0; + StellarAge = 0.0; ParticleClass = 0; NotEjectedMass = 0; MassToBeEjected = 0; @@ -89,12 +91,14 @@ class ActiveParticleType_SmartStar : public ActiveParticleType ActiveParticleType_SmartStar(ActiveParticleType_SmartStar* part) : ActiveParticleType(static_cast(part)) { AccretionRadius = part->AccretionRadius; + RadiationLifetime = part->RadiationLifetime; + StellarAge = part->StellarAge; ParticleClass = part->ParticleClass; for(int i = 0; i < 3; i++) { Accreted_angmom[i] = 0.0; } - TimeIndex = part->TimeIndex; + oldmass = part->oldmass; for(int i = 0; i < NTIMES; i++) { AccretionRateTime[i] = part->AccretionRateTime[i]; @@ -106,6 +110,7 @@ class ActiveParticleType_SmartStar : public ActiveParticleType epsilon_deltat = part->epsilon_deltat; beta_jet = part->beta_jet; mass_in_accretion_sphere = part->mass_in_accretion_sphere; + InfluenceRadius = part->InfluenceRadius; }; ActiveParticleType* clone() { return static_cast( @@ -150,6 +155,7 @@ class ActiveParticleType_SmartStar : public ActiveParticleType static int CreateParticle(grid *thisgrid_orig, ActiveParticleFormationData &supp_data, int particle_index); static int InitializeParticleType(); + void SmartMerge(ActiveParticleType_SmartStar *a); void AssignMassFromIMF(); int CalculateAccretedAngularMomentum(); @@ -187,10 +193,10 @@ class ActiveParticleType_SmartStar : public ActiveParticleType static int RadiationSEDNumberOfBins; static float* RadiationEnergyBins; static float* RadiationSED; - double RadiationLifetime; + double RadiationLifetime, StellarAge; //float acc[3]; int ParticleClass; - + float AccretionRate[NTIMES]; float AccretionRateTime[NTIMES]; int TimeIndex; @@ -232,7 +238,7 @@ void ActiveParticleType_SmartStar::MergeSmartStars( FLOAT ParticleCoordinates[3*(*nParticles)]; fflush(stdout); - /* Particles merge once they come within 3 accretion radii of one another */ + /* Particles merge once they come within 1 accretion radii of one another */ FLOAT MergingRadius = LevelArray[ThisLevel]->GridData->GetCellWidth(0,0)*ACCRETIONRADIUS; //MergingRadius = MergingRadius*3.0; @@ -262,7 +268,7 @@ void ActiveParticleType_SmartStar::MergeSmartStars( MergedParticles[i]->ReturnCurrentGrid()->ReturnProcessorNumber() ) == FAIL) { - ENZO_FAIL("MergeSmartStars: DisableParticle failed!\n"); + ENZO_FAIL("MergeSmartStars: DisableAParticle failed!\n"); } } } @@ -336,10 +342,10 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( { /* SmartStar particles live on the maximum refinement level. If we are on a lower level, this does not concern us */ - + if (ThisLevel == MaximumRefinementLevel) { - + /* Generate a list of all sink particles in the simulation box */ int i = 0, nParticles = 0, NumberOfMergedParticles = 0; ActiveParticleList ParticleList; @@ -363,13 +369,23 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( RemoveMassFromGridAfterFormation(nParticles, ParticleList, LevelArray, ThisLevel); - //thisGrid->RemoveMassFromGridAfterFormation(np->pos, np->ParticleClass, np->AccretionRadius, - // np->Mass, - // index, DensityThreshold, ExtraDensity); + /* Clean any particles marked for deletion */ + for (i = 0; iShouldDelete() == true) { + printf("%s: Delete SS %d following RemoveMassFromGridAfterFormation\n", __FUNCTION__, + static_cast(ParticleList[i])->ReturnID()); + fflush(stdout); + ParticleList.erase(i); + } + } + /* TEST THIS IS CORRECT*/ + ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, + ParticleList); + //if (AssignActiveParticlesToGrids(ParticleList, nParticles, + // LevelArray) == FAIL) + // return FAIL; - /* Do Merging */ - ActiveParticleList MergedParticles; /* Generate new merged list of sink particles */ @@ -397,11 +413,12 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( ParticleList.clear(); - //if (debug) - // printf("Number of particles after merging: %"ISYM"\n",NumberOfMergedParticles); + if (debug) + printf("Number of particles after merging: %"ISYM"\n",NumberOfMergedParticles); /* Assign local particles to grids */ - + /* Do Merging */ + ParticleList.reserve(NumberOfMergedParticles); // need to use a bit of redirection because C++ pointer arrays have @@ -415,17 +432,17 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( if (AssignActiveParticlesToGrids(ParticleList, NumberOfMergedParticles, LevelArray) == FAIL) return FAIL; - + ParticleList.clear(); MergedParticles.clear(); - + /* Regenerate the global active particle list */ ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, ParticleList); /* Do accretion */ - + if (Accrete(nParticles, ParticleList, accradius, dx, LevelArray, ThisLevel) == FAIL) ENZO_FAIL("SmartStar Particle accretion failed. \n"); @@ -437,11 +454,16 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( if (SmartStarParticleFeedback(nParticles, ParticleList, dx, LevelArray, ThisLevel) == FAIL) ENZO_FAIL("SmartStar Particle Feedback failed. \n"); + //ParticleList.clear(); + /* Regenerate the global active particle list */ + + ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, + ParticleList); + /* This applies all of the updates made above */ - if (AssignActiveParticlesToGrids(ParticleList, NumberOfMergedParticles, + if (AssignActiveParticlesToGrids(ParticleList, nParticles, LevelArray) == FAIL) return FAIL; - ParticleList.clear(); } diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index c36db8ae4..72916abba 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -171,7 +171,7 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) float x = log10((float)(_mass)); float x2 = x*x; - printf("%s: _mass = %f\n", __FUNCTION__, _mass); + if(this->ParticleClass == POPIII) { float E[NUMRADIATIONBINS] = {2.0, 12.8, 28.0, 30.0, 58.0}; diff --git a/src/enzo/EvolvePhotons.C b/src/enzo/EvolvePhotons.C index 0173d8459..2eea30234 100644 --- a/src/enzo/EvolvePhotons.C +++ b/src/enzo/EvolvePhotons.C @@ -300,7 +300,6 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], ENZO_FAIL("Error in InitializeTemperatureFieldForComptonHeating.\n"); } - printf("%s: RadiativeTransferH2ShieldType = %d\n", __FUNCTION__, RadiativeTransferH2ShieldType); /* Initialize Temperature Field for H2 shielding approximation */ if(RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) { for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= 0 ; lvl--) diff --git a/src/enzo/Grid_AccreteOntoSmartStarParticle.C b/src/enzo/Grid_AccreteOntoSmartStarParticle.C index 772a8e5d5..547d911d5 100644 --- a/src/enzo/Grid_AccreteOntoSmartStarParticle.C +++ b/src/enzo/Grid_AccreteOntoSmartStarParticle.C @@ -26,7 +26,7 @@ #include "ActiveParticle_SmartStar.h" #define NO_DEBUG_AP -#define ACCRETE_DEBUG 1 +#define ACCRETE_DEBUG 0 #define NO_ACCRETION 0 int GetUnits(float *DensityUnits, float *LengthUnits, @@ -42,6 +42,7 @@ int grid::AccreteOntoSmartStarParticle( return SUCCESS; ActiveParticleType_SmartStar* SS; SS = static_cast(ThisParticle); + /* Check whether the cube that circumscribes the accretion zone intersects * with this grid */ FLOAT xsink = ThisParticle->ReturnPosition()[0]; diff --git a/src/enzo/Grid_ApplySmartStarParticleFeedback.C b/src/enzo/Grid_ApplySmartStarParticleFeedback.C index 583028944..abb66a931 100644 --- a/src/enzo/Grid_ApplySmartStarParticleFeedback.C +++ b/src/enzo/Grid_ApplySmartStarParticleFeedback.C @@ -7,6 +7,12 @@ / date: December, 2017 / / note: Based on methods originally implemented by Stephen Skory +/ +/ description: the functions here apply the impact of i) supernova +/ explosions, ii) the feedback from black hole thermal energy and +/ iii) the feedback from black hole jets. +/ +/ Radiative feedback is not dealt with here. See ActiveParticle_SmartStar.C instead. ************************************************************************/ #include "preincludes.h" @@ -105,16 +111,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ DIINum, HDINum) == FAIL) { ENZO_FAIL("Error in grid->IdentifySpeciesFields."); } - if(SS->AccretionRate[SS->TimeIndex] <= 0.0) { - float mdot = SS->AccretionRate[SS->TimeIndex]; //CodeMass/CodeTime - - float accrate = mdot*MassUnits/(SolarMass*TimeUnits)*3.154e7; //in Msolar/s - printf("%s: AccretionRate = %e Msolar/yr %e (code)\n", __FUNCTION__, - accrate, SS->AccretionRate[SS->TimeIndex]); - printf("%s: Returning until accretion rate is updated\n", __FUNCTION__); - return SUCCESS; - } - + /*********************************************************************** SUPERNOVAE ************************************************************************/ @@ -129,9 +126,21 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ if(SS->ParticleClass == POPIII) { float Age = Time - SS->BirthTime; - - if(SS->RadiationLifetime < Age) {/* Star needs to go supernovae and change type */ + if(Age > SS->RadiationLifetime) {/* Star needs to go supernovae and change type */ + + + /* We now need to convert this particle into a Black Hole if appropriate + * 20 Msolar - 40.1 Msolar -> Type II supernova with BH remnant + * 40.1 Msolar - 140 Msolar -> DCBH + * 140 Msolar - 260 Msolar -> PISN -> No remnant (delete particle) + * 260+ Msolar - DCBH + */ + + printf("%s:Star going Supernova!\n", __FUNCTION__); + printf("%s: Age = %1.2f Myr\t RadiationLifetime = %1.2f kyr\n", __FUNCTION__, + Age*TimeUnits/Myr_s, SS->RadiationLifetime*TimeUnits/Myr_s); double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ + printf("%s: StellarMass = %lf\n", __FUNCTION__, StellarMass); double SNEnergy, HeliumCoreMass, Delta_SF, MetalMass; FLOAT Radius = PopIIISupernovaRadius * pc_cm / LengthUnits; float StarLevelCellWidth = this->CellWidth[0][0]; @@ -145,6 +154,14 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ SNEnergy = (5.0 + 1.304 * (HeliumCoreMass - 64)) * 1e51; EjectaMetalDensity = HeliumCoreMass * SolarMass / EjectaVolume / DensityUnits; + SS->WillDelete = true; + printf("%s: PISN detected. Particle set for deletion.\n", __FUNCTION__); + EjectaThermalEnergy = SNEnergy / (StellarMass * SolarMass) / VelocityUnits / + VelocityUnits; + + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + EjectaMetalDensity); + printf("%s: PISN Feedback completed. Delete particle\n", __FUNCTION__); } // Type II SNe else if (StellarMass >= TypeIILowerMass && StellarMass <= TypeIIUpperMass) { @@ -159,16 +176,29 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ frac * (SNExplosionEnergy[bin+1] - SNExplosionEnergy[bin])); MetalMass = (SNExplosionMetals[bin] + frac * (SNExplosionMetals[bin+1] - SNExplosionMetals[bin])); + + } + SS->ParticleClass = BH; + SS->RadiationLifetime = 1e20; + printf("%s: Post-SNe: ParticleClass now %d\t Lifetime = %f Myr\n", __FUNCTION__, + SS->ParticleClass, SS->RadiationLifetime*TimeUnits/Myr_s); EjectaMetalDensity = MetalMass * SolarMass / EjectaVolume / DensityUnits; - } - EjectaThermalEnergy = SNEnergy / (StellarMass * SolarMass) / VelocityUnits / - VelocityUnits; + EjectaThermalEnergy = SNEnergy / (StellarMass * SolarMass) / VelocityUnits / + VelocityUnits; - this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, EjectaMetalDensity); - + } + else {//DCBH + SS->ParticleClass = BH; + SS->RadiationLifetime = 1e20; + printf("%s: DCBH Created: ParticleClass now %d\t Lifetime = %f Myr\n", __FUNCTION__, + SS->ParticleClass, SS->RadiationLifetime*TimeUnits/Myr_s); + + } } + return SUCCESS; } if(SS->ParticleClass == POPII) @@ -190,6 +220,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ (VelocityUnits * VelocityUnits); this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, EjectaMetalDensity); + return SUCCESS; } /*********************************************************************** MBH_THERMAL diff --git a/src/enzo/Grid_ApplySphericalFeedbackToGrid.C b/src/enzo/Grid_ApplySphericalFeedbackToGrid.C index 6fbad3f5a..ea9655e58 100644 --- a/src/enzo/Grid_ApplySphericalFeedbackToGrid.C +++ b/src/enzo/Grid_ApplySphericalFeedbackToGrid.C @@ -63,6 +63,9 @@ int grid::ApplySphericalFeedbackToGrid(ActiveParticleType** ThisParticle, MetallicityField = (MetalNum > 0) ? TRUE : FALSE; ActiveParticleType_SmartStar *SS = static_cast(* ThisParticle); FLOAT radius = SS->InfluenceRadius; + if(radius == 0.0) + radius = 4*this->CellWidth[0][0]; + printf("%s: radius = %e\n", __FUNCTION__, radius); float MetalRadius = 1.0; FLOAT MetalRadius2 = radius * radius * MetalRadius * MetalRadius; float dx = float(this->CellWidth[0][0]); @@ -78,6 +81,7 @@ int grid::ApplySphericalFeedbackToGrid(ActiveParticleType** ThisParticle, FLOAT radius2 = POW(CellLeftEdge[0][i] + 0.5*dx - pos[0],2.0) + POW(CellLeftEdge[1][j] + 0.5*dx - pos[1],2.0) + POW(CellLeftEdge[2][k] + 0.5*dx - pos[2],2.0); + if (radius2 < outerRadius2) { float r1 = sqrt(radius2) / radius; float norm = 0.98; diff --git a/src/enzo/Grid_CalculateSmartStarAccretionRate.C b/src/enzo/Grid_CalculateSmartStarAccretionRate.C index 1b7cd9007..e117f5f6f 100644 --- a/src/enzo/Grid_CalculateSmartStarAccretionRate.C +++ b/src/enzo/Grid_CalculateSmartStarAccretionRate.C @@ -31,6 +31,7 @@ #define SMALL_NUMBER 1e-6 #define ACCRETION_LIMIT 1e-1 #define C_VISC 2.1e6 +#define DEBUG_AP 0 float bondi_alpha(float x); int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, diff --git a/src/enzo/ReadParameterFile.C b/src/enzo/ReadParameterFile.C index f99d22650..0f0e4e400 100644 --- a/src/enzo/ReadParameterFile.C +++ b/src/enzo/ReadParameterFile.C @@ -1453,6 +1453,7 @@ int ReadParameterFile(FILE *fptr, TopGridData &MetaData, float *Initialdt) if (MyProcessorNumber == ROOT_PROCESSOR) { fprintf(stdout, "Enabling particle type %s\n", active_particle_types[i]); } + ActiveParticlesIMFSeed = MetaData.CycleNumber; EnableActiveParticleType(active_particle_types[i]); delete [] active_particle_types[i]; } diff --git a/src/enzo/SetDefaultGlobalValues.C b/src/enzo/SetDefaultGlobalValues.C index 16cb2927d..2d82879a8 100644 --- a/src/enzo/SetDefaultGlobalValues.C +++ b/src/enzo/SetDefaultGlobalValues.C @@ -1030,6 +1030,7 @@ int SetDefaultGlobalValues(TopGridData &MetaData) SmartStarBHJetFeedback = FALSE; SmartStarBHThermalFeedback = FALSE; SmartStarStellarRadiativeFeedback = FALSE; + ActiveParticlesIMFSeed = -1; //SmartStar Feedback parameters - should be as minimal as possible SmartStarFeedbackEnergyCoupling = 0.016666; diff --git a/src/enzo/StarParticleData.h b/src/enzo/StarParticleData.h index b616c532d..5f310569e 100644 --- a/src/enzo/StarParticleData.h +++ b/src/enzo/StarParticleData.h @@ -142,6 +142,7 @@ SPEXTERN double AccretingParticleLuminosity; SPEXTERN float minStarLifetime; SPEXTERN FLOAT LastSupernovaTime; SPEXTERN float *IMFData; +SPEXTERN int ActiveParticlesIMFSeed; /* for star particle minimum mass ramp */ SPEXTERN int StarMakerMinimumMassRamp; diff --git a/src/enzo/StarParticlePopIII_IMFInitialize.C b/src/enzo/StarParticlePopIII_IMFInitialize.C index 89d75e7b2..fbe097cfc 100644 --- a/src/enzo/StarParticlePopIII_IMFInitialize.C +++ b/src/enzo/StarParticlePopIII_IMFInitialize.C @@ -23,7 +23,7 @@ #include "Hierarchy.h" #include "TopGridData.h" #include "LevelHierarchy.h" - +#include "AnalysisBaseClass.h" void mt_init(unsigned_int seed); unsigned_long_int mt_random(void); @@ -58,7 +58,7 @@ int StarParticlePopIII_IMFInitialize(void) /* Initialize the random number generator. Call it 1+NumberOfCalls to get the generator back to the same state as it was before the restart (if any). */ - + if (PopIIIInitialMassFunctionSeed == INT_UNDEFINED) mt_init(time(NULL)); //+100*MyProcessorNumber); else @@ -70,3 +70,45 @@ int StarParticlePopIII_IMFInitialize(void) return SUCCESS; } + + +int SmartStarPopIII_IMFInitialize(void) +{ + + const float CutoffExponent = 1.6; + + if (IMFData != NULL) + return SUCCESS; + + IMFData = new float[IMF_TABLE_ENTRIES]; + + int i; + float m, m0, dm, total_fn; + + dm = log10(PopIIIUpperMassCutoff / PopIIILowerMassCutoff) / + (float) (IMF_TABLE_ENTRIES-1); + m0 = log10(PopIIILowerMassCutoff); + total_fn = 0; + for (i = 0; i < IMF_TABLE_ENTRIES; i++) { + m = POW(10.0, m0 + i*dm); + total_fn += POW(m, PopIIIInitialMassFunctionSlope) * + exp(-POW((PopIIIStarMass / m), CutoffExponent)); + IMFData[i] = total_fn; + } // ENDFOR i + + // Normalize + for (i = 0; i < IMF_TABLE_ENTRIES; i++) + IMFData[i] /= IMFData[IMF_TABLE_ENTRIES-1]; + + /* + * Initialize the random number generator. + * The mt generator is seeded with the + * cycle number of the dataset used to start the run. + * So starting from the same dataset will give the same random + * seeds (up to parallelism constraints) but otherwise there + * will be stochastic variations. + */ + mt_init(ActiveParticlesIMFSeed+MyProcessorNumber); + return SUCCESS; + +} diff --git a/src/enzo/Star_AssignFinalMassFromIMF.C b/src/enzo/Star_AssignFinalMassFromIMF.C index 1d0e49585..71d65ca77 100644 --- a/src/enzo/Star_AssignFinalMassFromIMF.C +++ b/src/enzo/Star_AssignFinalMassFromIMF.C @@ -70,7 +70,8 @@ int Star::AssignFinalMassFromIMF(float TimeUnits) // x, this->FinalMass, this->LifeTime * TimeUnits / Myr_s); PopIIIInitialMassFunctionCalls++; - + printf("%s: PopIIIInitialMassFunctionCalls(%p) = %d\n", __FUNCTION__, + &PopIIIInitialMassFunctionCalls, PopIIIInitialMassFunctionCalls); return SUCCESS; } From d2c09c8c9cf005d463ba21f29dce74e2a61545ff Mon Sep 17 00:00:00 2001 From: John Regan Date: Tue, 9 Mar 2021 20:58:59 +0000 Subject: [PATCH 082/115] PopII support added to SS --- src/enzo/ActiveParticleRoutines.C | 27 +- src/enzo/ActiveParticle_SmartStar.C | 173 ++- src/enzo/ActiveParticle_SmartStar.h | 37 +- src/enzo/Grid_AccreteOntoSmartStarParticle.C | 124 +- .../Grid_ApplySmartStarParticleFeedback.C | 1065 +++++++++-------- src/enzo/Grid_ApplySphericalFeedbackToGrid.C | 6 +- .../Grid_CalculateSmartStarAccretionRate.C | 2 +- src/enzo/Grid_RemoveMassFromGrid.C | 2 +- src/enzo/ReadParameterFile.C | 1 - src/enzo/SetDefaultGlobalValues.C | 3 +- src/enzo/WriteParameterFile.C | 1 - src/enzo/global_data.h | 1 - 12 files changed, 792 insertions(+), 650 deletions(-) diff --git a/src/enzo/ActiveParticleRoutines.C b/src/enzo/ActiveParticleRoutines.C index 48dd06fd1..5749ff666 100644 --- a/src/enzo/ActiveParticleRoutines.C +++ b/src/enzo/ActiveParticleRoutines.C @@ -266,14 +266,29 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) RadiationLifetime = a->RadiationLifetime; StellarAge = a->StellarAge; } - Mass += a->Mass; NotEjectedMass += a->NotEjectedMass; - ParticleClass = max(ParticleClass, a->ParticleClass); + + /* + * SMS + PopIII -> SMS + * BH + SMS -> BH + * BH + PopIII -> BH + * POPII + POPII -> POPII + * POPII + SMS -> POPII (assume SMS becomes part of cluster) + * POPII + POPIII -> POPII (assume POPIII becomes part of cluster) + * a) POPII + BH -> POPII (if POPII mass > BH mass) + * b) POPII + BH -> BH (if BH mass > POPII mass) + */ + if(ParticleClass < 3 && a->ParticleClass < 3) + ParticleClass = max(ParticleClass, a->ParticleClass); + else if (ParticleClass == 4 || a->ParticleClass == 4) + { + if(Mass > a->Mass) + ParticleClass = a->ParticleClass; + else + a->ParticleClass = ParticleClass; + } WillDelete = min(WillDelete, a->WillDelete); - /* We should update the Lifetime after a merger I think....*/ //TODO - //float logm = log10((float)(this->Mass); - //RadiationLifetime = POW(10.0, (9.785 - 3.759*logm + 1.413*logm*logm - - // 0.186*logm*logm*logm)) / (TimeUnits/yr_s); + Mass += a->Mass; return; } diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 0eabcf2cf..97c6d6a27 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -120,12 +120,6 @@ int ActiveParticleType_SmartStar::InitializeParticleType() int ActiveParticleType_SmartStar::EvaluateFormation (grid *thisgrid_orig, ActiveParticleFormationData &data) { - //Particle Lifetimes - float SmartStarLifetime[4]; - SmartStarLifetime[0] = 2e6; //in yrs - SmartStarLifetime[1] = 2e6; //in yrs - SmartStarLifetime[2] = 1e20; //in yrs - SmartStarLifetime[3] = 2e7; //in yrs // No need to do the rest if we're not on the maximum refinement level. if (data.level != MaximumRefinementLevel) return SUCCESS; @@ -433,7 +427,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->AccretionRate[0] = accrate; np->AccretionRateTime[0] = np->BirthTime; - np->RadiationLifetime= SmartStarLifetime[np->ParticleClass]*yr_s/data.TimeUnits; + np->RadiationLifetime= 0.0; np->StellarAge = 0.0; np->NotEjectedMass = 0.0; @@ -789,12 +783,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle ActiveParticleList& ParticleList, LevelHierarchyEntry *LevelArray[], int ThisLevel) { - //Particle Lifetimes - float SmartStarLifetime[4]; - SmartStarLifetime[0] = 2e6; //in yrs - SmartStarLifetime[1] = 2e6; //in yrs - SmartStarLifetime[2] = 1e20; //in yrs - SmartStarLifetime[3] = 2e7; //in yrs + int SSparticles[nParticles] = {-1}; float StellarMasstoRemove = 0.0, CellDensityAfterFormation = 0.0; /* Skip accretion if we're not on the maximum refinement level. @@ -875,7 +864,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, TimeUnits = 1, VelocityUnits = 1, PressureUnits = 0, GEUnits = 0, VelUnits = 0; - double MassUnits = 1, CellVolume = 1; + double MassUnits = 1, CellVolume = dx*dx*dx; if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, Time) == FAIL) { ENZO_FAIL("Error in GetUnits."); @@ -931,7 +920,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle density[cellindex] = newcelldensity; SS->BirthTime = APGrid->ReturnTime(); SS->Mass = ParticleDensity; - SS->oldmass = SS->Mass; + SS->oldmass = 0.0; if(ParticleDensity < 0.0) { printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); @@ -949,7 +938,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle density[cellindex] = newcelldensity; SS->BirthTime = APGrid->ReturnTime(); SS->Mass = ParticleDensity; - SS->oldmass = SS->Mass; + SS->oldmass = 0.0; if(ParticleDensity < 0.0) { printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); @@ -970,7 +959,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle density[cellindex] = (1 - StarClusterFormEfficiency)*density[cellindex]; SS->BirthTime = APGrid->ReturnTime(); SS->Mass = StarClusterFormEfficiency*density[cellindex]; - SS->oldmass = SS->Mass; + SS->oldmass = 0.0; if(ParticleDensity < 0.0) { printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); @@ -1004,8 +993,9 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); /* Mark particle for deletion */ SS->WillDelete = true; + ParticleList[pindex]->DisableParticle(LevelArray, MyProcessorNumber); printf("Too late. Star is destroyed by surrounding SF. Particle %d deleted.\n", pindex); - + continue; } FLOAT Radius = 0.0; @@ -1090,24 +1080,37 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle AvgVelocity[dim] /= MassEnclosed; - /* Now remove mass based on star particle type */ + /* Now remove mass based on star particle type + * Note that while SS->Mass gets set here with the + * mass of the particle in solar masses it is reset + * below in code density units. + */ if(POPIII == SS->ParticleClass) { SS->AssignMassFromIMF(); - SS->StellarAge = SS->RadiationLifetime; + SS->StellarAge = SS->RadiationLifetime; SphereTooSmall = MassEnclosed < (2*SS->Mass); // to make the total mass PopIIIStarMass StellarMasstoRemove = SS->Mass; // [Msolar] printf("%s: Mass = %e Msolar\t StellarAge = %e Myr\n", __FUNCTION__, SS->Mass, SS->StellarAge*TimeUnits/Myr_s); + SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/CellVolume; //code density + SS->oldmass = 0.0; } else if(SMS == SS->ParticleClass) { - /* I think we need a heavy seed IMF here */ - SS->Mass = 1000.0; //hardcoding to 1000 Msolar - SS->RadiationLifetime = SmartStarLifetime[SS->ParticleClass]*yr_s/TimeUnits; + /* + * We take here a fiducial SMS mass of 10,000 Msolar + * since in this low resolution case accretion is + * not permitted. + * The lifetime is set to be 1.5 Myr (see Woods et al. 2020) + */ + SS->Mass = 10000.0; //hardcoding to 10000 Msolar + SS->RadiationLifetime = 1.5e6*yr_s/TimeUnits; //Woods et al. 2020 SS->StellarAge = SS->RadiationLifetime; SphereTooSmall = MassEnclosed < (2*SS->Mass); StellarMasstoRemove = SS->Mass; //[Msolar] + SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/CellVolume; //code density + SS->oldmass = 0.0; } else if(POPII == SS->ParticleClass) { float AvgDensity = (float) @@ -1118,7 +1121,9 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle float ColdGasFraction = ColdGasMass / MassEnclosed; StellarMasstoRemove = ColdGasFraction * StarClusterFormEfficiency * MassEnclosed; //[Msolar] SphereTooSmall = DynamicalTime < tdyn_code; - + SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/CellVolume; //code density + SS->oldmass = 0.0; + SS->RadiationLifetime = 2e7*yr_s/TimeUnits; /* 20 Myr lifetime */ } // Remove the stellar mass from the sphere and distribute the // gas evenly in the sphere since this is what will happen once @@ -1209,8 +1214,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle SS->BirthTime = APGrid->ReturnTime(); double cellvolume = APGrid->CellWidth[0][i]*APGrid->CellWidth[1][j]* APGrid->CellWidth[2][k]; - SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/cellvolume; //code density - SS->oldmass = SS->Mass; + APGrid->BaryonField[DensNum][index] = CellDensityAfterFormation; if (MultiSpecies) { APGrid->BaryonField[DeNum][index] = APGrid->BaryonField[DensNum][index] * ionizedFraction; @@ -1309,7 +1313,7 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, AccretionRadius = static_cast(ParticleList[i])->AccretionRadius; int pclass = static_cast(ParticleList[i])->ParticleClass; FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc - int Stellar_Age = static_cast(ParticleList[i])->StellarAge; + float Stellar_Age = static_cast(ParticleList[i])->StellarAge; float p_age = ctime - static_cast(ParticleList[i])->BirthTime; if(pclass == POPIII) { /* @@ -1333,8 +1337,7 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, * we can optionally employ a time delay following a SNe explosion to * avoid spurious accretion. */ - - if(p_age < Stellar_Age + TimeDelay) + if(p_age < Stellar_Age + TimeDelay) continue; } @@ -1343,7 +1346,7 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, continue; } - + grid* FeedbackZone = ConstructFeedbackZone(ParticleList[i], int(AccretionRadius/dx), dx, Grids, NumberOfGrids, ALL_FIELDS); grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); @@ -1449,19 +1452,28 @@ int ActiveParticleType_SmartStar::SmartStarParticleFeedback(int nParticles, if (MyProcessorNumber == FeedbackZone->ReturnProcessorNumber()) { if (FeedbackZone->ApplySmartStarParticleFeedback(&ParticleList[i]) == FAIL) return FAIL; - } - /* If a PISN just went off then we can safely delete the particle. */ - if(ParticleList[i]->ShouldDelete() == true) { - printf("%s: Delete SS %d following PISN\n", __FUNCTION__, - static_cast(ParticleList[i])->ReturnID()); - fflush(stdout); - ParticleList.erase(i); + + + /* If a PISN just went off then we can safely delete the particle. */ + if(ParticleList[i]->ShouldDelete() == true) { + printf("%s: Delete SS %d following PISN\n", __FUNCTION__, + static_cast(ParticleList[i])->ReturnID()); + fflush(stdout); + ParticleList[i]->DisableParticle(LevelArray, + FeedbackZone->ReturnProcessorNumber()); + printf("%s: SS %d deleted\n", __FUNCTION__, + static_cast(ParticleList[i])->ReturnID()); + fflush(stdout); + } } DistributeFeedbackZone(FeedbackZone, Grids, NumberOfGrids, ALL_FIELDS); delete FeedbackZone; + } + delete [] Grids; + return SUCCESS; } @@ -1588,38 +1600,41 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, SS->TimeIndex = timeindex; fprintf(stdout, "old_mass = %e Msolar\t cmass = (%e code) %e Msolar\n", omass*MassConversion, cmass, cmass*MassConversion); - fprintf(stdout, "accrate = %e Msolar/yr\t accratetime = %e yrs \t deltatime = %f yrs\t index = %d\t Particle Mass = %e Msolar\t Age = %1.3f\t Myr Lifetime = %1.2f Myr\t Class = %d\n", + fprintf(stdout, "accrate = %e Msolar/yr\t deltatime = %3.3f Myrs\t index = %d\t Particle Mass = %1.1f Msolar\t Age = %1.3f Myr\t Lifetime = %1.2f Myr\t Class = %d\n", (SS->AccretionRate[timeindex]*MassUnits/TimeUnits)*yr_s/SolarMass, - (SS->AccretionRateTime[timeindex]*TimeUnits)/yr_s, - deltatime*TimeUnits/yr_s, + deltatime*TimeUnits/Myr_s, SS->TimeIndex, SS->ReturnMass()*MassConversion, Age*TimeUnits/Myr_s, SS->RadiationLifetime*TimeUnits/Myr_s, SS->ParticleClass); - if(SS->ParticleClass < BH) { - /* - * Using the time-averaged accretion rates determine if the SMS is accreting fast enough or - * if it is falling onto the main sequence. - */ - if((SS->AccretionRate[SS->TimeIndex]*MassUnits/TimeUnits)*yr_s/SolarMass - > CRITICAL_ACCRETION_RATE) { - SS->ParticleClass = SMS; - } - else { - float Age = Time - SS->BirthTime; - if(Age*TimeUnits/yr_s > 1e4 && SMS == SS->ParticleClass) { /* Don't do this at very start */ - printf("%s: WARNING: ParticleClass switching from SMS to POPIII (deltatime = %f kyrs)\n", __FUNCTION__, - deltatime*TimeUnits/(yr_s*1e3)); - printf("%s: WARNING: Accretion Rate = %f Msolar/yr. Critical rate = %f Msolar/yr\n", __FUNCTION__, - (SS->AccretionRate[SS->TimeIndex]*MassUnits/TimeUnits)*yr_s/SolarMass, - CRITICAL_ACCRETION_RATE); - SS->ParticleClass = POPIII; - } + if(SS->ParticleClass > SMS) + continue; + else { + if(dx_pc < SMS_RESOLUTION) { + /* + * Using the time-averaged accretion rates determine if the SMS is accreting fast enough or + * if it is falling onto the main sequence. + */ + if((SS->AccretionRate[SS->TimeIndex]*MassUnits/TimeUnits)*yr_s/SolarMass + > CRITICAL_ACCRETION_RATE) { + SS->ParticleClass = SMS; + } + else { + float Age = Time - SS->BirthTime; + if(Age*TimeUnits/yr_s > 1e4 && SMS == SS->ParticleClass) { /* Don't do this at very start */ + printf("%s: WARNING: ParticleClass switching from SMS to POPIII (deltatime = %f kyrs)\n", __FUNCTION__, + deltatime*TimeUnits/(yr_s*1e3)); + printf("%s: WARNING: Accretion Rate = %f Msolar/yr. Critical rate = %f Msolar/yr\n", __FUNCTION__, + (SS->AccretionRate[SS->TimeIndex]*MassUnits/TimeUnits)*yr_s/SolarMass, + CRITICAL_ACCRETION_RATE); + SS->ParticleClass = POPIII; + } + } } } - } - } + } + } } #if SSDEBUG printf("Done in %s\n", __FUNCTION__); @@ -1628,6 +1643,42 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, return SUCCESS; } +/* + * Update stellar lifetimes at each step to account for accretion and mergers + */ +int ActiveParticleType_SmartStar::UpdateRadiationLifetimes(int nParticles, + ActiveParticleList& ParticleList, + FLOAT dx, + LevelHierarchyEntry *LevelArray[], + int ThisLevel) +{ + FLOAT Time = LevelArray[ThisLevel]->GridData->ReturnTime(); + float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, + VelocityUnits; + double MassUnits; + GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, + &TimeUnits, &VelocityUnits, Time); + MassUnits = DensityUnits * POW(LengthUnits,3); + double MassConversion = (double) (dx*dx*dx * double(MassUnits)); //convert to g + MassConversion = MassConversion/SolarMass; + for (int i = 0; i < nParticles; i++) { + grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); + if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { + ActiveParticleType_SmartStar* SS; + SS = static_cast(ParticleList[i]); + if(POPIII == SS->ParticleClass) { + double StellarMass = SS->Mass*MassConversion; //Msolar + float logm = log10((float)StellarMass); + // First in years, then convert to code units + SS->RadiationLifetime = POW(10.0, (9.785 - 3.759*logm + 1.413*logm*logm - + 0.186*logm*logm*logm)) / (TimeUnits/yr_s); + SS->StellarAge = SS->RadiationLifetime; //update stellar age too + } + } + } + + return SUCCESS; +} /* Find the stellar radius of the sink particle using the SAM from Smith et al. (2011) */ static float GetStellarRadius(float cmass, float accrate) diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 4b0bf5759..ea5f065de 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -183,6 +183,11 @@ class ActiveParticleType_SmartStar : public ActiveParticleType FLOAT dx, LevelHierarchyEntry *LevelArray[], int ThisLevel); + static int UpdateRadiationLifetimes(int nParticles, + ActiveParticleList& ParticleList, + FLOAT dx, + LevelHierarchyEntry *LevelArray[], int ThisLevel); + static int RemoveMassFromGridAfterFormation(int nParticles, ActiveParticleList& ParticleList, LevelHierarchyEntry *LevelArray[], int ThisLevel); @@ -241,7 +246,7 @@ void ActiveParticleType_SmartStar::MergeSmartStars( /* Particles merge once they come within 1 accretion radii of one another */ FLOAT MergingRadius = LevelArray[ThisLevel]->GridData->GetCellWidth(0,0)*ACCRETIONRADIUS; - //MergingRadius = MergingRadius*3.0; + for (i=0; i<(*nParticles); i++) { tempPos = ParticleList[i]->ReturnPosition(); for (dim=0; dim<3; dim++) @@ -368,7 +373,7 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( /* Remove mass from grid from newly formed particles */ RemoveMassFromGridAfterFormation(nParticles, ParticleList, LevelArray, ThisLevel); - + /* Clean any particles marked for deletion */ for (i = 0; iShouldDelete() == true) { @@ -376,6 +381,8 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( static_cast(ParticleList[i])->ReturnID()); fflush(stdout); ParticleList.erase(i); + i = -1; + nParticles--; } } /* TEST THIS IS CORRECT*/ @@ -384,7 +391,8 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( //if (AssignActiveParticlesToGrids(ParticleList, nParticles, // LevelArray) == FAIL) // return FAIL; - + if (debug) + printf("Number of particles before merging: %"ISYM"\n",nParticles); /* Do Merging */ ActiveParticleList MergedParticles; @@ -450,16 +458,29 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( if(UpdateAccretionRateStats(nParticles, ParticleList, dx, LevelArray, ThisLevel) == FAIL) ENZO_FAIL("Failed to update accretion rate stats. \n"); + if(UpdateRadiationLifetimes(nParticles, ParticleList, dx, LevelArray, ThisLevel) == FAIL) + ENZO_FAIL("Failed to update radiation lifetimes. \n"); + /* Apply feedback */ if (SmartStarParticleFeedback(nParticles, ParticleList, dx, LevelArray, ThisLevel) == FAIL) ENZO_FAIL("SmartStar Particle Feedback failed. \n"); - //ParticleList.clear(); - /* Regenerate the global active particle list */ - + + /* Clean any particles marked for deletion. + * After each deletion I need to reloop and check it again. + */ + for (i = 0; iShouldDelete() == true) { + printf("%s: Delete SS %d following Feedback\n", __FUNCTION__, + static_cast(ParticleList[i])->ReturnID()); + fflush(stdout); + ParticleList.erase(i); + i = -1; //reset counter + nParticles--; + } + } ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, - ParticleList); - + ParticleList); /* This applies all of the updates made above */ if (AssignActiveParticlesToGrids(ParticleList, nParticles, LevelArray) == FAIL) diff --git a/src/enzo/Grid_AccreteOntoSmartStarParticle.C b/src/enzo/Grid_AccreteOntoSmartStarParticle.C index 547d911d5..720a58f98 100644 --- a/src/enzo/Grid_AccreteOntoSmartStarParticle.C +++ b/src/enzo/Grid_AccreteOntoSmartStarParticle.C @@ -84,19 +84,10 @@ int grid::AccreteOntoSmartStarParticle( FLOAT KernelRadius = 0.0, SumOfWeights = 0.0; /*Required for weighting cells for accretion */ *AccretionRate = CalculateSmartStarAccretionRate(ThisParticle, AccretionRadius, &KernelRadius, &SumOfWeights); - #if NO_ACCRETION *AccretionRate = 0.0; #endif - /* - * 1. Calculate the accretion rate - * 2a. Calculate how much goes into the black hole: Mdot_BH = AccRate*(1 - eta_disk) ~ 0.9*AccRate - * 2b. Calculate how much goes into the Jet: Mdot_Jet = Mdot_BH*beta_jet ~ 90*AccRate (for Beta_Jet = 100) - * 3. Remove the MDot_BH from the grid and also take opportunity to calculate total mass available - * within the accretion sphere. - * 4. The Thermal energy (or radiation) is composed of eta_disk*AccRate ~ 0.1*AccRate - */ - + float MaxAccretionRate = huge_number; /* * If we want to cap the accretion rate at the Eddington rate the most sensible thing @@ -150,67 +141,82 @@ int grid::AccreteOntoSmartStarParticle( * a kernel weighting applied to extract gas from the grid. */ *AccretionRate = AccretedMass/this->dtFixed; //in units of density/time - + + + /* + * The next bit applies to BHs only. + * 1. Calculate the accretion rate (done above) + * 2a. Calculate how much goes into the black hole: Mdot_BH = AccRate*(1 - eta_disk) ~ 0.9*AccRate + * 2b. Calculate how much goes into the Jet: Mdot_Jet = Mdot_BH*beta_jet ~ 90*AccRate (for Beta_Jet = 100) + * 3. Remove the MDot_BH from the grid and also take opportunity to calculate total mass available + * within the accretion sphere. + * 4. The Thermal energy (or radiation) is composed of eta_disk*AccRate ~ 0.1*AccRate + * which can be found by computing eta_disk/(1 - eta_disk)*Mdot_BH + */ + /* * Using the actual accretion rate we can update how much of the gas makes it onto the * smart star and of the mass that is available for feedback how much, if any, ends * up in Jets. */ - if(BH == SS->ParticleClass && SmartStarBHJetFeedback) { + if((BH == SS->ParticleClass) && SmartStarBHFeedback) { *AccretionRate *= (1.0 - SS->eta_disk); - /* - * Now this is the complicated/clever bit. - * The MassEjected will not be a fraction of the accreted mass but a fraction of the available mass - * from the surrounding cells. The mass in the surrounding cells is mass_in_accretion_sphere - * beta_jet = Jet Mass Loading - * eta_jet = Jet efficiency (comes from GRMHD simulations) - * epsilon_deltat = subgrids the timestep and effectively restricts jet emission - * to some small part of the timestep which we do not resolve. - * Mdot_Jet = beta_jet * (1 - eta_disk) * mdot * epsilon_deltat - * MassEjected = Mdot_Jet * dt - */ - float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses - float eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(SS->eta_disk*clight*sigma_thompson); // g/s - eddrate = eddrate*3.154e7/SolarMass; //in Msolar/yr - float accrate_msolar = (*AccretionRate)*3.154e7*MassConversion/(SolarMass*TimeUnits); //Msolar/yr - /* eta_jet comes from the fit given in Sadowski et al. (2016) */ - float eta_jet = 1.3*POW(SmartStarSpin, 2.0); - SS->beta_jet = (1.0/SmartStarJetVelocity)*(1.0/SmartStarJetVelocity)*2.0*eta_jet; - float mdot_total = SS->mass_in_accretion_sphere/this->dtFixed; //This is the total mass available for accretion inside accretion sphere - float accretion_ratio = mdot_total/(*AccretionRate); - SS->epsilon_deltat = min(1.0, accretion_ratio*(1.0/(1.0 - SS->eta_disk))*(1.0/(1.0 + SS->beta_jet))); - SS->MassToBeEjected = 0.0; + + if(SmartStarBHJetFeedback) { + /* + * Now this is the complicated/clever bit. + * The MassEjected will not be a fraction of the accreted mass but a fraction of the available mass + * from the surrounding cells. The mass in the surrounding cells is mass_in_accretion_sphere + * beta_jet = Jet Mass Loading + * eta_jet = Jet efficiency (comes from GRMHD simulations) + * epsilon_deltat = subgrids the timestep and effectively restricts jet emission + * to some small part of the timestep which we do not resolve. + * Mdot_Jet = beta_jet * (1 - eta_disk) * mdot * epsilon_deltat + * MassEjected = Mdot_Jet * dt + */ + float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses + float eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(SS->eta_disk*clight*sigma_thompson); // g/s + eddrate = eddrate*3.154e7/SolarMass; //in Msolar/yr + float accrate_msolar = (*AccretionRate)*3.154e7*MassConversion/(SolarMass*TimeUnits); //Msolar/yr + /* eta_jet comes from the fit given in Sadowski et al. (2016) */ + float eta_jet = 1.3*POW(SmartStarSpin, 2.0); + SS->beta_jet = (1.0/SmartStarJetVelocity)*(1.0/SmartStarJetVelocity)*2.0*eta_jet; + float mdot_total = SS->mass_in_accretion_sphere/this->dtFixed; //This is the total mass available for accretion inside accretion sphere + float accretion_ratio = mdot_total/(*AccretionRate); + SS->epsilon_deltat = min(1.0, accretion_ratio*(1.0/(1.0 - SS->eta_disk))*(1.0/(1.0 + SS->beta_jet))); + SS->MassToBeEjected = 0.0; #if ACCRETE_DEBUG - printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\t Ratio = %f\n", __FUNCTION__, - eddrate, accrate_msolar, accrate_msolar/eddrate); + printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\t Ratio = %f\n", __FUNCTION__, + eddrate, accrate_msolar, accrate_msolar/eddrate); #endif - if(accrate_msolar > eddrate) { - - *AccretionRate *= SS->epsilon_deltat; - SS->MassToBeEjected = SS->beta_jet*(*AccretionRate)*this->dtFixed*dx*dx*dx; //Code Mass - *AccretionRate *= (1 - eta_jet); + if(accrate_msolar > eddrate) { + + *AccretionRate *= SS->epsilon_deltat; + SS->MassToBeEjected = SS->beta_jet*(*AccretionRate)*this->dtFixed*dx*dx*dx; //Code Mass + *AccretionRate *= (1 - eta_jet); #if ACCRETE_DEBUG - printf("%s: eta_disk = %f\n", __FUNCTION__, SS->eta_disk); - printf("%s: eta_jet = %f\t beta_jet = %f\t ParticleClass = %d\n", __FUNCTION__, eta_jet, SS->beta_jet,SS->ParticleClass ); - printf("%s: Mass in surrounding sphere = %e Msolar\n", __FUNCTION__, SS->mass_in_accretion_sphere*MassConversion/SolarMass); - printf("%s: Macc = %e Msolar\t Mjet = %e Msolar\n", __FUNCTION__, - (*AccretionRate)*this->dtFixed*MassConversion/SolarMass, - SS->MassToBeEjected*MassUnits/SolarMass); - printf("%s: accretion_ratio = %f\n", __FUNCTION__, accretion_ratio); - printf("%s: epsilon_deltat = %e\n", __FUNCTION__, SS->epsilon_deltat); - printf("%s: Mass to be ejected = %f Msolar (%e code)\n", __FUNCTION__, SS->MassToBeEjected*MassUnits/SolarMass, SS->MassToBeEjected); - printf("%s: Updated Accretion rate = %e Msolar/yr\n", __FUNCTION__, - (*AccretionRate)*3.154e7*MassConversion/(SolarMass*TimeUnits)); - printf("%s: No update would be = %e Msolar/yr\n", __FUNCTION__, - (*AccretionRate/SS->epsilon_deltat)*3.154e7*MassConversion/(SolarMass*TimeUnits)); + printf("%s: eta_disk = %f\n", __FUNCTION__, SS->eta_disk); + printf("%s: eta_jet = %f\t beta_jet = %f\t ParticleClass = %d\n", __FUNCTION__, eta_jet, SS->beta_jet,SS->ParticleClass ); + printf("%s: Mass in surrounding sphere = %e Msolar\n", __FUNCTION__, SS->mass_in_accretion_sphere*MassConversion/SolarMass); + printf("%s: Macc = %e Msolar\t Mjet = %e Msolar\n", __FUNCTION__, + (*AccretionRate)*this->dtFixed*MassConversion/SolarMass, + SS->MassToBeEjected*MassUnits/SolarMass); + printf("%s: accretion_ratio = %f\n", __FUNCTION__, accretion_ratio); + printf("%s: epsilon_deltat = %e\n", __FUNCTION__, SS->epsilon_deltat); + printf("%s: Mass to be ejected = %f Msolar (%e code)\n", __FUNCTION__, SS->MassToBeEjected*MassUnits/SolarMass, SS->MassToBeEjected); + printf("%s: Updated Accretion rate = %e Msolar/yr\n", __FUNCTION__, + (*AccretionRate)*3.154e7*MassConversion/(SolarMass*TimeUnits)); + printf("%s: No update would be = %e Msolar/yr\n", __FUNCTION__, + (*AccretionRate/SS->epsilon_deltat)*3.154e7*MassConversion/(SolarMass*TimeUnits)); #endif - } - else { + } + else { #if ACCRETE_DEBUG - printf("%s: AccrateionRateRatio = %f. No jets this time\n", __FUNCTION__, - accrate_msolar/eddrate); + printf("%s: AccrateionRateRatio = %f. No jets this time\n", __FUNCTION__, + accrate_msolar/eddrate); #endif - ; + ; + } } } diff --git a/src/enzo/Grid_ApplySmartStarParticleFeedback.C b/src/enzo/Grid_ApplySmartStarParticleFeedback.C index abb66a931..5b2cf9332 100644 --- a/src/enzo/Grid_ApplySmartStarParticleFeedback.C +++ b/src/enzo/Grid_ApplySmartStarParticleFeedback.C @@ -34,7 +34,7 @@ #define SSFEED_DEBUG 1 #define MAX_TEMPERATURE 1e8 -#define RAMPTIME 4000.0 //1e4 +#define RAMPTIME 100000.0 //yrs #define DENSITY_WEIGHTED 1 #define SINE_WAVE 0 #define IMPOSETHRESHOLD 1 @@ -123,48 +123,62 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ float ionizedFraction = 0.999; // Assume supernova is ionized FLOAT Time = this->ReturnTime(); - if(SS->ParticleClass == POPIII) - { - float Age = Time - SS->BirthTime; - if(Age > SS->RadiationLifetime) {/* Star needs to go supernovae and change type */ - - - /* We now need to convert this particle into a Black Hole if appropriate - * 20 Msolar - 40.1 Msolar -> Type II supernova with BH remnant - * 40.1 Msolar - 140 Msolar -> DCBH - * 140 Msolar - 260 Msolar -> PISN -> No remnant (delete particle) - * 260+ Msolar - DCBH - */ + float Age = Time - SS->BirthTime; + /* + * SMS don't go supernova they just directly collapse into BHs (of the same mass) + */ + if(SS->ParticleClass == SMS) { + + if(Age > SS->RadiationLifetime) {/* SMS converts directly into DCBH */ + SS->ParticleClass = BH; + SS->StellarAge = SS->RadiationLifetime; //Record last stellar age + SS->RadiationLifetime = 1e20; + printf("%s: DCBH Created: ParticleClass now %d\t Stellar Age = %f Myr\t " \ + "Lifetime = %f Myr\n", __FUNCTION__, + SS->ParticleClass, SS->StellarAge*TimeUnits/Myr_s, + SS->RadiationLifetime*TimeUnits/Myr_s); + } + return SUCCESS; + } /* POPIII Supernova */ + else if(SS->ParticleClass == POPIII) { + + if(Age > SS->RadiationLifetime) {/* Star needs to go supernovae and change type */ + + /* We now need to convert this particle into a Black Hole if appropriate + * 20 Msolar - 40.1 Msolar -> Type II supernova with BH remnant + * 40.1 Msolar - 140 Msolar -> DCBH + * 140 Msolar - 260 Msolar -> PISN -> No remnant (delete particle) + * 260+ Msolar - DCBH + */ + + printf("%s:Star going Supernova!\n", __FUNCTION__); + printf("%s: Age = %1.2f Myr\t RadiationLifetime = %1.2f Myr\n", __FUNCTION__, + Age*TimeUnits/Myr_s, SS->RadiationLifetime*TimeUnits/Myr_s); + double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ + printf("%s: StellarMass = %lf\n", __FUNCTION__, StellarMass); + double SNEnergy, HeliumCoreMass, Delta_SF, MetalMass; + FLOAT Radius = PopIIISupernovaRadius * pc_cm / LengthUnits; + FLOAT StarLevelCellWidth = this->CellWidth[0][0]; + Radius = max(Radius, 3.5*StarLevelCellWidth); + FLOAT EjectaVolume = 4.0/3.0 * pi * pow(Radius*LengthUnits, 3); + FLOAT EjectaDensity = StellarMass * SolarMass / EjectaVolume / DensityUnits; + FLOAT EjectaMetalDensity = 0.0, EjectaThermalEnergy = 0.0; + // pair-instability SNe + if (StellarMass >= PISNLowerMass && StellarMass <= PISNUpperMass) { + HeliumCoreMass = (13./24.) * (StellarMass - 20); + SNEnergy = (5.0 + 1.304 * (HeliumCoreMass - 64)) * 1e51; + EjectaMetalDensity = HeliumCoreMass * SolarMass / EjectaVolume / + DensityUnits; + SS->WillDelete = true; + printf("%s: PISN detected. Particle set for deletion.\n", __FUNCTION__); + EjectaThermalEnergy = SNEnergy / (StellarMass * SolarMass) / VelocityUnits / + VelocityUnits; - printf("%s:Star going Supernova!\n", __FUNCTION__); - printf("%s: Age = %1.2f Myr\t RadiationLifetime = %1.2f kyr\n", __FUNCTION__, - Age*TimeUnits/Myr_s, SS->RadiationLifetime*TimeUnits/Myr_s); - double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ - printf("%s: StellarMass = %lf\n", __FUNCTION__, StellarMass); - double SNEnergy, HeliumCoreMass, Delta_SF, MetalMass; - FLOAT Radius = PopIIISupernovaRadius * pc_cm / LengthUnits; - float StarLevelCellWidth = this->CellWidth[0][0]; - Radius = max(Radius, 3.5*StarLevelCellWidth); - float EjectaVolume = 4.0/3.0 * pi * pow(Radius*LengthUnits, 3); - float EjectaDensity = StellarMass * SolarMass / EjectaVolume / DensityUnits; - float EjectaMetalDensity = 0.0, EjectaThermalEnergy = 0.0; - // pair-instability SNe - if (StellarMass >= PISNLowerMass && StellarMass <= PISNUpperMass) { - HeliumCoreMass = (13./24.) * (StellarMass - 20); - SNEnergy = (5.0 + 1.304 * (HeliumCoreMass - 64)) * 1e51; - EjectaMetalDensity = HeliumCoreMass * SolarMass / EjectaVolume / - DensityUnits; - SS->WillDelete = true; - printf("%s: PISN detected. Particle set for deletion.\n", __FUNCTION__); - EjectaThermalEnergy = SNEnergy / (StellarMass * SolarMass) / VelocityUnits / - VelocityUnits; - - this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, - EjectaMetalDensity); - printf("%s: PISN Feedback completed. Delete particle\n", __FUNCTION__); - } - // Type II SNe - else if (StellarMass >= TypeIILowerMass && StellarMass <= TypeIIUpperMass) { + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + EjectaMetalDensity); + printf("%s: PISN Feedback completed. Delete particle\n", __FUNCTION__); + } + else if (StellarMass >= TypeIILowerMass && StellarMass <= TypeIIUpperMass) { if (StellarMass < 20.0) { // Normal Type II SNEnergy = 1e51; MetalMass = 0.1077 + 0.3383 * (StellarMass - 11.0); // Fit to Nomoto+06 @@ -176,10 +190,10 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ frac * (SNExplosionEnergy[bin+1] - SNExplosionEnergy[bin])); MetalMass = (SNExplosionMetals[bin] + frac * (SNExplosionMetals[bin+1] - SNExplosionMetals[bin])); - } SS->ParticleClass = BH; + SS->StellarAge = SS->RadiationLifetime; //Record last stellar age SS->RadiationLifetime = 1e20; printf("%s: Post-SNe: ParticleClass now %d\t Lifetime = %f Myr\n", __FUNCTION__, SS->ParticleClass, SS->RadiationLifetime*TimeUnits/Myr_s); @@ -192,507 +206,548 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ } else {//DCBH SS->ParticleClass = BH; + SS->StellarAge = SS->RadiationLifetime; //Record last stellar age SS->RadiationLifetime = 1e20; - printf("%s: DCBH Created: ParticleClass now %d\t Lifetime = %f Myr\n", __FUNCTION__, - SS->ParticleClass, SS->RadiationLifetime*TimeUnits/Myr_s); + printf("%s: DCBH Created: ParticleClass now %d\t Stellar Age = %f Myr\t "\ + "Lifetime = %f Myr\n", __FUNCTION__, + SS->ParticleClass, SS->StellarAge*TimeUnits/Myr_s, + SS->RadiationLifetime*TimeUnits/Myr_s); } } return SUCCESS; } - - if(SS->ParticleClass == POPII) + else if(SS->ParticleClass == POPII) { - float Age = Time - SS->BirthTime; - float StarLevelCellWidth = this->CellWidth[0][0]; - FLOAT Radius = StarClusterSNRadius * pc_cm / LengthUnits; - if (Radius < 2*StarLevelCellWidth) { - Radius = 2*StarLevelCellWidth; - } - float dtForThisStar = this->ReturnTimeStep(); - double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ - double Delta_SF = StarMassEjectionFraction * StellarMass * dtForThisStar * - TimeUnits / (16.0*Myr_s); - float EjectaVolume = 4.0/3.0 * pi * pow(Radius*LengthUnits, 3); - float EjectaDensity = Delta_SF * SolarMass / EjectaVolume / DensityUnits; - float EjectaMetalDensity = EjectaDensity * StarMetalYield; - float EjectaThermalEnergy = StarClusterSNEnergy / SolarMass / - (VelocityUnits * VelocityUnits); - this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + + /* + * POPII star clusters are setup to give constant SNe feedback + * to the grid. + * Clusters begin giving out feedback after StarClusterSNeStart + * They stop producing feedback after StarClusterSNeEnd + * After each supernova event mass is deducted from the cluster + * Clusters therefore only decrease in mass after birth. + */ + const float StarClusterSNeStart = 4.0; // Myr after cluster is born + const float StarClusterSNeEnd = 20.0; // Myr (lifetime of a 8 SolarMass star) + + float AgeInMyr = Age * TimeUnits / Myr_s; + if((AgeInMyr > StarClusterSNeStart) && (AgeInMyr < StarClusterSNeEnd)) { + + printf("%s: POPII Continuous Supernova\n", __FUNCTION__); + FLOAT StarLevelCellWidth = this->CellWidth[0][0]; + FLOAT Radius = StarClusterSNRadius * pc_cm / LengthUnits; + if (Radius < 2*StarLevelCellWidth) { + Radius = 2*StarLevelCellWidth; + } + FLOAT BubbleVolume = (4.0 * pi / 3.0) * Radius * Radius * Radius; /* code volume */ + float dtForThisStar = this->ReturnTimeStep(); + double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ + double Delta_SF = StarMassEjectionFraction * StellarMass * dtForThisStar * + TimeUnits / (16.0*Myr_s); /* Msolar */ + printf("%s: dtForThisStar = %e Myr\n", __FUNCTION__, dtForThisStar * TimeUnits/Myr_s); + printf("%s: OK I'm going to eject %e Msolar as Energy\n", __FUNCTION__, Delta_SF); + + FLOAT EjectaVolume = 4.0/3.0 * pi * pow(Radius*LengthUnits, 3); /* cm^3 */ + FLOAT EjectaDensity = Delta_SF * SolarMass / EjectaVolume / DensityUnits; /* code density */ + FLOAT EjectaMetalDensity = EjectaDensity * StarMetalYield; /* code density */ + FLOAT EjectaThermalEnergy = StarClusterSNEnergy / SolarMass / + (VelocityUnits * VelocityUnits); + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, EjectaMetalDensity); + /* Remove mass from star following supernova feedback */ + double old_mass = SS->Mass; + SS->Mass -= Delta_SF * SolarMass / MassConversion; /*Convert to code density */ + float frac = old_mass / SS->Mass; + float *Vel = SS->vel; + float NewVelocity[3] = + { + (Vel[0]*frac), + (Vel[1]*frac), + (Vel[2]*frac) + }; + SS->SetVelocity(NewVelocity); + printf("%s: Mass changed from %e Msolar to %e Msolar\n", __FUNCTION__, + old_mass*MassConversion/SolarMass, SS->Mass*MassConversion/SolarMass); + } return SUCCESS; } - /*********************************************************************** + else if(SS->ParticleClass == BH) + { + /*********************************************************************** MBH_THERMAL - ************************************************************************/ - if(SmartStarBHFeedback == FALSE) - return SUCCESS; - // Similar to Supernova, but here we assume the followings: - // EjectaDensity = 0.0 - // EjectaMetalDensity = 0.0 - float EjectaDensity = 0.0, EjectaMetalDensity = 0.0; - // The unit of EjectaThermalEnergy = ergs/cm^3, not ergs/g - if (SmartStarBHThermalFeedback == TRUE) { - float epsilon = SS->eta_disk; - - /* find mdot */ - float mdot = SS->AccretionRate[SS->TimeIndex]; //CodeMass/CodeTime - float accrate = mdot*MassUnits/(SolarMass*TimeUnits)*3.154e7; //in Msolar/yr - float mdot_cgs = mdot*MassUnits/TimeUnits; //g/s - //printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); - printf("%s: AccretionRate = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, - accrate, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); - /*end Debug*/ - - float EjectaVolumeCGS = 4.0/3.0 * PI * pow(SS->AccretionRadius*LengthUnits, 3); - float EjectaVolume = 4.0/3.0 * PI * pow(SS->AccretionRadius, 3); - - float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses - float eddrate = 4*M_PI*GravConst*BHMass*mh/(SS->eta_disk*clight*sigma_thompson); // Msolar/s - eddrate = eddrate*3.154e7; //in Msolar/yr - printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\n", __FUNCTION__, - eddrate, accrate); - if(SmartStarSuperEddingtonAdjustment == TRUE) { - if(accrate > eddrate) { - printf("%s: We are accreting at super-Eddington rates. Modifying radiative efficiency\n", __FUNCTION__); - float mue = 1.22, a = 0.7; - float Ledd = 4*M_PI*GravConst*BHMass*SolarMass*mh*mue*clight/sigma_thompson; //cgs - float medddot = 16.0*Ledd/(clight*clight); //cgs - /* Apply Madau fit to calculate Luminosity */ - float LSuperEdd = Ledd*MadauFit(a, accrate*SolarMass/3.154e7, medddot); //cgs - epsilon = LSuperEdd/(mdot_cgs*clight*clight); - printf("%s: Using the Madau fit raditive efficiency calculated as %e\n", __FUNCTION__, epsilon); - } - } - /* When injected energy is uniform throughout the volume; - * The unit of EjectaThermalEnergy is CodeMass*CodeVelocity^2 - * EjectaThermalEnergy is added to each cell normalised by the - * totalEjectaVolume. Hence the units of EjectaThermalEnergy are EnergyUnits/VolumeUnits - * We calculate the SmartStarDiskEnergyCoupling as (v_wind/(2*c)). To do this we - * must fix v_wind. For v_wind we choose 0.1 c (C.-A. Faucher-Giguere, E. Quataert Arxiv:1204.2547) - */ - float SmartStarDiskEnergyCoupling = 0.05; - float EjectaThermalEnergy = SmartStarDiskEnergyCoupling * epsilon * dt * - mdot*clight*clight/(VelocityUnits*VelocityUnits*EjectaVolume); - - /* Ramp up over RAMPTIME yrs */ - float Age = this->ReturnTime() - SS->BirthTime; - Age = Age*TimeUnits/3.154e7 - SmartStarSMSLifetime; - if(Age < RAMPTIME) - { - printf("BH Age = %f yrs, ramp = %f\n", Age, Age/(float)RAMPTIME); - EjectaThermalEnergy *= Age/(float)RAMPTIME; + ************************************************************************/ + if(SmartStarBHFeedback == FALSE) + return SUCCESS; + // Similar to Supernova, but here we assume the followings: + // EjectaDensity = 0.0 + // EjectaMetalDensity = 0.0 + float EjectaDensity = 0.0, EjectaMetalDensity = 0.0; + // The unit of EjectaThermalEnergy = ergs/cm^3, not ergs/g + if (SmartStarBHThermalFeedback == TRUE) { + printf("%s: eta_disk = %f\n", __FUNCTION__, SS->eta_disk); + float epsilon = SS->eta_disk/(1 - SS->eta_disk); + + /* find mdot */ + float mdot = SS->AccretionRate[SS->TimeIndex]; //CodeMass/CodeTime + float accrate = mdot*MassUnits/(SolarMass*TimeUnits)*3.154e7; //in Msolar/yr + float mdot_cgs = mdot*MassUnits/TimeUnits; //g/s + //printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); + printf("%s: AccretionRate = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, + accrate, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); + + + float EjectaVolumeCGS = 4.0/3.0 * PI * pow(SS->AccretionRadius*LengthUnits, 3); + float EjectaVolume = 4.0/3.0 * PI * pow(SS->AccretionRadius, 3); + + float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses + float eddrate = 4*M_PI*GravConst*BHMass*mh/(SS->eta_disk*clight*sigma_thompson); // Msolar/s + eddrate = eddrate*3.154e7; //in Msolar/yr + printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\n", __FUNCTION__, + eddrate, accrate); + if(SmartStarSuperEddingtonAdjustment == TRUE) { + if(accrate > eddrate) { + printf("%s: We are accreting at super-Eddington rates. Modifying radiative efficiency\n", __FUNCTION__); + float mue = 1.22, a = 0.7; + float Ledd = 4*M_PI*GravConst*BHMass*SolarMass*mh*mue*clight/sigma_thompson; //cgs + float medddot = 16.0*Ledd/(clight*clight); //cgs + /* Apply Madau fit to calculate Luminosity */ + float LSuperEdd = Ledd*MadauFit(a, accrate*SolarMass/3.154e7, medddot); //cgs + epsilon = LSuperEdd/(mdot_cgs*clight*clight); + printf("%s: Using the Madau fit raditive efficiency calculated as %e\n", __FUNCTION__, epsilon); + } + } + /* When injected energy is uniform throughout the volume; + * The unit of EjectaThermalEnergy is CodeMass*CodeVelocity^2 + * EjectaThermalEnergy is added to each cell normalised by the + * totalEjectaVolume. Hence the units of EjectaThermalEnergy are EnergyUnits/VolumeUnits + * We calculate the SmartStarDiskEnergyCoupling as (v_wind/(2*c)). To do this we + * must fix v_wind. For v_wind we choose 0.1 c (C.-A. Faucher-Giguere, E. Quataert Arxiv:1204.2547) + */ + float SmartStarDiskEnergyCoupling = 0.05; + float EjectaThermalEnergy = SmartStarDiskEnergyCoupling * epsilon * dt * + mdot*clight*clight/(VelocityUnits*VelocityUnits*EjectaVolume); + + /* Ramp up over RAMPTIME yrs */ + float Age = Time - SS->BirthTime; + float BH_Age = (Age - SS->StellarAge)*TimeUnits/yr_s; + if(BH_Age < RAMPTIME) + { + printf("BH Age = %e yrs, ramp = %e\n", BH_Age, BH_Age/(float)RAMPTIME); + EjectaThermalEnergy *= BH_Age/(float)RAMPTIME; + } + EjectaDensity = 0.0; + EjectaMetalDensity = 0.0; + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + EjectaMetalDensity); + } - - this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, - EjectaMetalDensity); - - } - if(SmartStarBHJetFeedback == FALSE) - return SUCCESS; - /*********************************************************************** - MBH_JETS - ************************************************************************/ - // Inject bipolar jets along the direction of the angular momentum - // vector L of the MBH particle (angular momentum accreted thus far) - // or along the z-axis - Ji-hoon Kim, Nov.2009 - int i = 0, j = 0, k = 0; + /*********************************************************************** + MBH_JETS + ************************************************************************/ + if(SmartStarBHJetFeedback == TRUE) { + + // Inject bipolar jets along the direction of the angular momentum + // vector L of the MBH particle (angular momentum accreted thus far) + // or along the z-axis - Ji-hoon Kim, Nov.2009 + int i = 0, j = 0, k = 0; #define MAX_SUPERCELL_NUMBER 1000 - int SUPERCELL = 1; //2 for supercell of 5 cells wide = 5^3 - int ind_cell_inside[MAX_SUPERCELL_NUMBER], ind_cell_edge[MAX_SUPERCELL_NUMBER]; - float nx_cell_edge[MAX_SUPERCELL_NUMBER], ny_cell_edge[MAX_SUPERCELL_NUMBER], - nz_cell_edge[MAX_SUPERCELL_NUMBER], anglefactor[MAX_SUPERCELL_NUMBER] = {0}; - int n_cell_inside = 0, n_cell_edge = 0, ibuff = NumberOfGhostZones; - int ii = 0, jj = 0, kk = 0, r_s = 0, ic = 0, sign = 0; - float m_cell_inside = 0.0, m_cell_edge = 0.0; - float L_x, L_y, L_z, L_s, nx_L = 0.0, ny_L = 0.0, nz_L = 0.0, costheta = cos(OPENING_ANGLE); - float SSMass = SS->ReturnMass(); - float totalenergybefore = 0.0, totalenergyafter = 0.0, totalenergyadded = 0.0; - float sumkeadded = 0.0; - - if (SmartStarBHJetFeedback == FALSE || SS->MassToBeEjected*MassUnits/SolarMass < 1e-10) { - return SUCCESS; - } - - /* i, j, k are the number of cells from the edge of the grid to the smartstar*/ - i = (int)((pos[0] - this->CellLeftEdge[0][0]) / dx); - j = (int)((pos[1] - this->CellLeftEdge[1][0]) / dx); - k = (int)((pos[2] - this->CellLeftEdge[2][0]) / dx); - - /* Note that we need to inject feedback only for the finest grid the SS belongs to */ - - if (i < ibuff || i > this->GridDimension[0]-ibuff-1 || - j < ibuff || j > this->GridDimension[1]-ibuff-1 || - k < ibuff || k > this->GridDimension[2]-ibuff-1 || - this == NULL || - SS->level < MaximumRefinementLevel) { - fprintf(stdout, "grid::AddFS: MBH_JETS - MBH doesn't belong to this grid.\n"); - return SUCCESS; - } - - - /* find mdot */ - float mdot = SS->AccretionRate[SS->TimeIndex]; - float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses - float eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(SS->eta_disk*clight*sigma_thompson); // g/s - eddrate = eddrate*3.154e7/SolarMass; //in Msolar/yr - - float AccretionRate = mdot*MassUnits/(SolarMass*TimeUnits); //in Msolar/s - /* - * Now in the case where we are subgriding the accretion formalism - * re-calculate the actual accretion rate and check if we are in the correct band - */ - //AccretionRate *= SS->epsilon_deltat; - - /* Debug */ - printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\t Ratio = %f\n", __FUNCTION__, - eddrate, AccretionRate*3.154e7, AccretionRate*3.154e7/eddrate); - printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); - printf("%s: AccretionRate (*deltat) = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, - AccretionRate*3.154e7, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); - float MassEjected = SS->NotEjectedMass + SS->MassToBeEjected; //code mass - - - SS->NotEjectedMass = MassEjected; + int SUPERCELL = 1; //2 for supercell of 5 cells wide = 5^3 + int ind_cell_inside[MAX_SUPERCELL_NUMBER], ind_cell_edge[MAX_SUPERCELL_NUMBER]; + float nx_cell_edge[MAX_SUPERCELL_NUMBER], ny_cell_edge[MAX_SUPERCELL_NUMBER], + nz_cell_edge[MAX_SUPERCELL_NUMBER], anglefactor[MAX_SUPERCELL_NUMBER] = {0}; + int n_cell_inside = 0, n_cell_edge = 0, ibuff = NumberOfGhostZones; + int ii = 0, jj = 0, kk = 0, r_s = 0, ic = 0, sign = 0; + float m_cell_inside = 0.0, m_cell_edge = 0.0; + float L_x, L_y, L_z, L_s, nx_L = 0.0, ny_L = 0.0, nz_L = 0.0, costheta = cos(OPENING_ANGLE); + float SSMass = SS->ReturnMass(); + float totalenergybefore = 0.0, totalenergyafter = 0.0, totalenergyadded = 0.0; + float sumkeadded = 0.0; + + if (SmartStarBHJetFeedback == FALSE || SS->MassToBeEjected*MassUnits/SolarMass < 1e-10) { + return SUCCESS; + } + + /* i, j, k are the number of cells from the edge of the grid to the smartstar*/ + i = (int)((pos[0] - this->CellLeftEdge[0][0]) / dx); + j = (int)((pos[1] - this->CellLeftEdge[1][0]) / dx); + k = (int)((pos[2] - this->CellLeftEdge[2][0]) / dx); + + /* Note that we need to inject feedback only for the finest grid the SS belongs to */ + + if (i < ibuff || i > this->GridDimension[0]-ibuff-1 || + j < ibuff || j > this->GridDimension[1]-ibuff-1 || + k < ibuff || k > this->GridDimension[2]-ibuff-1 || + this == NULL || + SS->level < MaximumRefinementLevel) { + fprintf(stdout, "grid::AddFS: MBH_JETS - MBH doesn't belong to this grid.\n"); + return SUCCESS; + } + + + /* find mdot */ + float mdot = SS->AccretionRate[SS->TimeIndex]; + float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses + float eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(SS->eta_disk*clight*sigma_thompson); // g/s + eddrate = eddrate*3.154e7/SolarMass; //in Msolar/yr + + float AccretionRate = mdot*MassUnits/(SolarMass*TimeUnits); //in Msolar/s + /* + * Now in the case where we are subgriding the accretion formalism + * re-calculate the actual accretion rate and check if we are in the correct band + */ + //AccretionRate *= SS->epsilon_deltat; + + /* Debug */ + printf("%s: Eddrate = %e Msolar/yr AccRate = %e Msolar/yr\t Ratio = %f\n", __FUNCTION__, + eddrate, AccretionRate*3.154e7, AccretionRate*3.154e7/eddrate); + printf("%s: dx = %e\t MassConversion = %e\n", __FUNCTION__, dx, MassConversion); + printf("%s: AccretionRate (*deltat) = %e Msolar/yr %e (code) TimeIndex = %d\n", __FUNCTION__, + AccretionRate*3.154e7, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); + float MassEjected = SS->NotEjectedMass + SS->MassToBeEjected; //code mass + + + SS->NotEjectedMass = MassEjected; #if IMPOSETHRESHOLD #if SSFEED_DEBUG - printf("SSFEED_DEBUG: %s: Mass Accumulated thus far = %e Msolar (Threshold = %e Msolar)\n", - __FUNCTION__, SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); + printf("SSFEED_DEBUG: %s: Mass Accumulated thus far = %e Msolar (Threshold = %e Msolar)\n", + __FUNCTION__, SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); #endif - if (SS->NotEjectedMass*MassUnits/SolarMass <= SS->EjectedMassThreshold) { - fprintf(stdout, "grid::AddFS: MBH_JETS - accumulated mass (%f Msolar) not passed threshold (%f Msolar).\n", - SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); - return SUCCESS; - } + if (SS->NotEjectedMass*MassUnits/SolarMass <= SS->EjectedMassThreshold) { + fprintf(stdout, "grid::AddFS: MBH_JETS - accumulated mass (%f Msolar) not passed threshold (%f Msolar).\n", + SS->NotEjectedMass*MassUnits/SolarMass, SS->EjectedMassThreshold); + return SUCCESS; + } #endif - - if(AccretionRate*3.154e7/eddrate < 1e-30 || AccretionRate*3.154e7/eddrate > 1.0) - { - printf("%s: AccrateionRateRatio = %f. We are in the right band to release jets\n", __FUNCTION__, - AccretionRate*3.154e7/eddrate); - } - else - { - printf("%s: AccrateionRateRatio = %f. No jets this time\n", __FUNCTION__, - AccretionRate*3.154e7/eddrate); - return SUCCESS; - } - /*end Debug*/ - - + + if(AccretionRate*3.154e7/eddrate < 1e-30 || AccretionRate*3.154e7/eddrate > 1.0) + { + printf("%s: AccrateionRateRatio = %f. We are in the right band to release jets\n", __FUNCTION__, + AccretionRate*3.154e7/eddrate); + } + else + { + printf("%s: AccrateionRateRatio = %f. No jets this time\n", __FUNCTION__, + AccretionRate*3.154e7/eddrate); + return SUCCESS; + } + /*end Debug*/ + + #if SSFEED_DEBUG - - printf("SSFEED_DEBUG: %s: Mass Accreted = %e Msolar\t Mass to be Ejected = %e Msolar\n", - __FUNCTION__, mdot*dt*MassUnits/SolarMass, MassEjected*MassUnits/SolarMass); -#endif - - if (i < ibuff+SUPERCELL || i > this->GridDimension[0]-ibuff-SUPERCELL-1 || - j < ibuff+SUPERCELL || j > this->GridDimension[1]-ibuff-SUPERCELL-1 || - k < ibuff+SUPERCELL || k > this->GridDimension[2]-ibuff-SUPERCELL-1) { - fprintf(stdout, "grid::AddFS: MBH_JETS - supercell not contained; accumulated mass (%g MSolar).\n", - SS->NotEjectedMass*MassUnits/SolarMass); - - // if the supercell issue hasn't allowed the jet injection for too long, - // issue a warning signal and output the current hierarchy at CheckForOutput - if (SS->NotEjectedMass*MassUnits/SolarMass > 2.0 * SS->EjectedMassThreshold) { - fprintf(stdout, "grid::AddFS: MBH_JETS - jets haven't been ejected for too long!\n"); - } - - // otherwise, just proceed and do it later - return SUCCESS; - } - printf("SSFEED_DEBUG: %s: Lets Eject!!!!!!!!!!!\n", __FUNCTION__); -#if IMPOSETHRESHOLD - float MassKeptInReserve = max(MassEjected - THRESHOLDFRACTION*SolarMass/MassUnits, 0.0); - MassEjected = MassEjected - MassKeptInReserve; + + printf("SSFEED_DEBUG: %s: Mass Accreted = %e Msolar\t Mass to be Ejected = %e Msolar\n", + __FUNCTION__, mdot*dt*MassUnits/SolarMass, MassEjected*MassUnits/SolarMass); #endif - printf("Cumulative Mass to be ejected in jet will be %f Msolar\n", MassEjected*MassUnits/SolarMass); - /* Find the directional vector n_L of angular momentum accreted thus far */ - if(SS->CalculateAccretedAngularMomentum() == FAIL) { - return FAIL; - } - L_x = SS->Accreted_angmom[0]; - L_y = SS->Accreted_angmom[1]; - L_z = SS->Accreted_angmom[2]; - L_s = sqrt(pow(L_x,2) + pow(L_y,2) + pow(L_z,2)); - nx_L = L_x/L_s; //normalized directional vector - ny_L = L_y/L_s; - nz_L = L_z/L_s; - L_s = sqrt(pow(nx_L,2) + pow(ny_L,2) + pow(nz_L,2)); - printf("%s: Angular momentum = %e %e %e\t L_s = %e\n", __FUNCTION__, - nx_L, ny_L, nz_L, L_s); - //nx_L = 0.0; - //ny_L = 0.0; - //nz_L = 1.0; - //L_s = sqrt(pow(nx_L,2) + pow(ny_L,2) + pow(nz_L,2)); - //printf("%s: Angular momentum = %e %e %e\t L_s = %e\n", __FUNCTION__, - // nx_L, ny_L, nz_L, L_s); - - /* Loop over the supercell around the MBH particle (5 * 5 * 5 = 125 cells, - but only the edges), and record the cells eligible for jet injection */ - int nsupercells = 0; - for (kk = -SUPERCELL; kk <= SUPERCELL; kk++) { - for (jj = -SUPERCELL; jj <= SUPERCELL; jj++) { - for (ii = -SUPERCELL; ii <= SUPERCELL; ii++) { - nsupercells++; - r_s = sqrt(pow(ii,2) + pow(jj,2) + pow(kk,2)); - if (fabs(ii) != SUPERCELL && fabs(jj) != SUPERCELL && fabs(kk) != SUPERCELL) { //if not on edges - // printf("%s: Inside: CosTheta = %f\t cellangle = %f (%f degrees)\n", __FUNCTION__, - // costheta, fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s), - // (360/pi)*acos(fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s))); - ind_cell_inside[n_cell_inside] = i+ii+(j+jj+(k+kk)*this->GridDimension[1])*this->GridDimension[0]; - m_cell_inside += this->BaryonField[DensNum][ind_cell_inside[n_cell_inside]] * - pow(dx, 3); - n_cell_inside++; + + if (i < ibuff+SUPERCELL || i > this->GridDimension[0]-ibuff-SUPERCELL-1 || + j < ibuff+SUPERCELL || j > this->GridDimension[1]-ibuff-SUPERCELL-1 || + k < ibuff+SUPERCELL || k > this->GridDimension[2]-ibuff-SUPERCELL-1) { + fprintf(stdout, "grid::AddFS: MBH_JETS - supercell not contained; accumulated mass (%g MSolar).\n", + SS->NotEjectedMass*MassUnits/SolarMass); - } else { //if on edges - if (fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s) > costheta) { - //printf("%s: Edge: CosTheta = %f\t cellangle = %f (%f degrees)\n", __FUNCTION__, - // costheta, fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s), - // (360/pi)*acos(fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s))); - anglefactor[n_cell_edge] = fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s); - ind_cell_edge[n_cell_edge] = i+ii+(j+jj+(k+kk)*this->GetGridDimension(1))*this->GetGridDimension(0); - nx_cell_edge[n_cell_edge] = ii / r_s; //directional vector - ny_cell_edge[n_cell_edge] = jj / r_s; - nz_cell_edge[n_cell_edge] = kk / r_s; - m_cell_edge += this->BaryonField[DensNum][ind_cell_edge[n_cell_edge]] * - pow(this->GetCellWidth(0, 0), 3); - - totalenergybefore += this->BaryonField[TENum][ind_cell_edge[n_cell_edge]]; - n_cell_edge++; - + // if the supercell issue hasn't allowed the jet injection for too long, + // issue a warning signal and output the current hierarchy at CheckForOutput + if (SS->NotEjectedMass*MassUnits/SolarMass > 2.0 * SS->EjectedMassThreshold) { + fprintf(stdout, "grid::AddFS: MBH_JETS - jets haven't been ejected for too long!\n"); } - } + // otherwise, just proceed and do it later + return SUCCESS; + } + printf("SSFEED_DEBUG: %s: Lets Eject!!!!!!!!!!!\n", __FUNCTION__); +#if IMPOSETHRESHOLD + float MassKeptInReserve = max(MassEjected - THRESHOLDFRACTION*SolarMass/MassUnits, 0.0); + MassEjected = MassEjected - MassKeptInReserve; +#endif + printf("Cumulative Mass to be ejected in jet will be %f Msolar\n", MassEjected*MassUnits/SolarMass); + /* Find the directional vector n_L of angular momentum accreted thus far */ + if(SS->CalculateAccretedAngularMomentum() == FAIL) { + return FAIL; + } + L_x = SS->Accreted_angmom[0]; + L_y = SS->Accreted_angmom[1]; + L_z = SS->Accreted_angmom[2]; + L_s = sqrt(pow(L_x,2) + pow(L_y,2) + pow(L_z,2)); + nx_L = L_x/L_s; //normalized directional vector + ny_L = L_y/L_s; + nz_L = L_z/L_s; + L_s = sqrt(pow(nx_L,2) + pow(ny_L,2) + pow(nz_L,2)); + printf("%s: Angular momentum = %e %e %e\t L_s = %e\n", __FUNCTION__, + nx_L, ny_L, nz_L, L_s); + //nx_L = 0.0; + //ny_L = 0.0; + //nz_L = 1.0; + //L_s = sqrt(pow(nx_L,2) + pow(ny_L,2) + pow(nz_L,2)); + //printf("%s: Angular momentum = %e %e %e\t L_s = %e\n", __FUNCTION__, + // nx_L, ny_L, nz_L, L_s); - } // END ii-direction - } // END jj-direction - } // END kk-direction + /* Loop over the supercell around the MBH particle (5 * 5 * 5 = 125 cells, + but only the edges), and record the cells eligible for jet injection */ + int nsupercells = 0; + for (kk = -SUPERCELL; kk <= SUPERCELL; kk++) { + for (jj = -SUPERCELL; jj <= SUPERCELL; jj++) { + for (ii = -SUPERCELL; ii <= SUPERCELL; ii++) { + nsupercells++; + r_s = sqrt(pow(ii,2) + pow(jj,2) + pow(kk,2)); + if (fabs(ii) != SUPERCELL && fabs(jj) != SUPERCELL && fabs(kk) != SUPERCELL) { //if not on edges + // printf("%s: Inside: CosTheta = %f\t cellangle = %f (%f degrees)\n", __FUNCTION__, + // costheta, fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s), + // (360/pi)*acos(fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s))); + ind_cell_inside[n_cell_inside] = i+ii+(j+jj+(k+kk)*this->GridDimension[1])*this->GridDimension[0]; + m_cell_inside += this->BaryonField[DensNum][ind_cell_inside[n_cell_inside]] * + pow(dx, 3); + n_cell_inside++; + + } else { //if on edges + if (fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s) > costheta) { + //printf("%s: Edge: CosTheta = %f\t cellangle = %f (%f degrees)\n", __FUNCTION__, + // costheta, fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s), + // (360/pi)*acos(fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s))); + anglefactor[n_cell_edge] = fabs((ii*nx_L + jj*ny_L + kk*nz_L)/r_s); + ind_cell_edge[n_cell_edge] = i+ii+(j+jj+(k+kk)*this->GetGridDimension(1))*this->GetGridDimension(0); + nx_cell_edge[n_cell_edge] = ii / r_s; //directional vector + ny_cell_edge[n_cell_edge] = jj / r_s; + nz_cell_edge[n_cell_edge] = kk / r_s; + m_cell_edge += this->BaryonField[DensNum][ind_cell_edge[n_cell_edge]] * + pow(this->GetCellWidth(0, 0), 3); + + totalenergybefore += this->BaryonField[TENum][ind_cell_edge[n_cell_edge]]; + n_cell_edge++; + + } + + } + + } // END ii-direction + } // END jj-direction + } // END kk-direction #if SSFEED_DEBUG - printf("%s: n_cell_inside = %d\n", __FUNCTION__, n_cell_inside); - printf("%s: n_cell_edge = %d\n", __FUNCTION__, n_cell_edge); - printf("%s: nsupercells = %d\n", __FUNCTION__, nsupercells); + printf("%s: n_cell_inside = %d\n", __FUNCTION__, n_cell_inside); + printf("%s: n_cell_edge = %d\n", __FUNCTION__, n_cell_edge); + printf("%s: nsupercells = %d\n", __FUNCTION__, nsupercells); #endif - /* Calculate the jet density - * This is the mass of the ejected mass + the mass at the cell edges - */ - - float rho_jet = (MassEjected) / - ((float)n_cell_edge * pow(this->GetCellWidth(0,0), 3)); //In code units + /* Calculate the jet density + * This is the mass of the ejected mass + the mass at the cell edges + */ + + float rho_jet = (MassEjected) / + ((float)n_cell_edge * pow(this->GetCellWidth(0,0), 3)); //In code units #if SSFEED_DEBUG - printf("%s: rho_jet (per cell) = %e cc", __FUNCTION__, rho_jet*DensityUnits/mh); + printf("%s: rho_jet (per cell) = %e cc", __FUNCTION__, rho_jet*DensityUnits/mh); #endif - - /* Calculate MBHJetsVelocity using energy conservation below: - SmartStarFeedbackEnergyCoupling = The fraction of feedback energy that is - mechanically (for MBH_JETS) coupled to the gas. - SmartStarFeedbackRadiativeEfficiency - The radiative efficiency of a black hole. - - MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency * Mdot * c^2 - = 0.5 * MBHFeedbackMassEjectionFraction * Mdot * (MBHJetsVelocity)^2 - - Note that EjectaThermalEnergy is never used; MBHFeedbackEnergyCoupling - should now be calculated considering gravitational redshift (Kim et al. 2010) - - float MBHJetsVelocity = clight * sqrt( 2 * MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency - / MBHFeedbackMassEjectionFraction ) / VelocityUnits; - */ - - /* This is really a bit of a cod and it may be better to set the jet velocity as some fraction of the - * speed of light. */ - float MBHJetsVelocity = clight * SmartStarJetVelocity/VelocityUnits; //code velocity - - /* Ramp up over RAMPTIME yrs */ - float Age = this->ReturnTime() - SS->BirthTime; - Age = Age*TimeUnits/3.154e7; - if(Age < RAMPTIME) - { - printf("%s: Too early for jets. Age = %f yrs\n", __FUNCTION__, Age); - return SUCCESS; - MBHJetsVelocity = MBHJetsVelocity*Age/(float)RAMPTIME; - } - - float jetenergy = 0.5*MBHJetsVelocity*MBHJetsVelocity; + + /* Calculate MBHJetsVelocity using energy conservation below: + SmartStarFeedbackEnergyCoupling = The fraction of feedback energy that is + mechanically (for MBH_JETS) coupled to the gas. + SmartStarFeedbackRadiativeEfficiency - The radiative efficiency of a black hole. + + MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency * Mdot * c^2 + = 0.5 * MBHFeedbackMassEjectionFraction * Mdot * (MBHJetsVelocity)^2 + + Note that EjectaThermalEnergy is never used; MBHFeedbackEnergyCoupling + should now be calculated considering gravitational redshift (Kim et al. 2010) + + float MBHJetsVelocity = clight * sqrt( 2 * MBHFeedbackEnergyCoupling * MBHFeedbackRadiativeEfficiency + / MBHFeedbackMassEjectionFraction ) / VelocityUnits; + */ + + /* This is really a bit of a cod and it may be better to set the jet velocity as some fraction of the + * speed of light. */ + float MBHJetsVelocity = clight * SmartStarJetVelocity/VelocityUnits; //code velocity + + /* Ramp up over RAMPTIME yrs */ + float Age = this->ReturnTime() - SS->BirthTime; + Age = Age*TimeUnits/3.154e7; + if(Age < RAMPTIME) + { + printf("%s: Too early for jets. Age = %f yrs\n", __FUNCTION__, Age); + return SUCCESS; + MBHJetsVelocity = MBHJetsVelocity*Age/(float)RAMPTIME; + } + + float jetenergy = 0.5*MBHJetsVelocity*MBHJetsVelocity; #if SSFEED_DEBUG - printf("%s: Age = %f yrs\n", __FUNCTION__, Age); - printf("%s: Jet Energy = %e (specific = %e)\n", __FUNCTION__, jetenergy*MassEjected, jetenergy); - printf("SSFEED_DEBUG: %s: MBHJetsVelocity = %e of clight (%f km/s)\n", __FUNCTION__, - MBHJetsVelocity * VelocityUnits/clight, - MBHJetsVelocity*VelocityUnits/1e5 ); - printf("SSFEED_DEBUG: %s: SmartStarJetVelocity = %e\n", __FUNCTION__, SmartStarJetVelocity); + printf("%s: Age = %f yrs\n", __FUNCTION__, Age); + printf("%s: Jet Energy = %e (specific = %e)\n", __FUNCTION__, jetenergy*MassEjected, jetenergy); + printf("SSFEED_DEBUG: %s: MBHJetsVelocity = %e of clight (%f km/s)\n", __FUNCTION__, + MBHJetsVelocity * VelocityUnits/clight, + MBHJetsVelocity*VelocityUnits/1e5 ); + printf("SSFEED_DEBUG: %s: SmartStarJetVelocity = %e\n", __FUNCTION__, SmartStarJetVelocity); #endif - if (MBHJetsVelocity * VelocityUnits > 0.99*clight) { - ENZO_VFAIL("grid::AddFS: MBHJetsVelocity is ultra-relativistic! (%g/ %g/ %g/ %g c)\n", - MBHFeedbackEnergyCoupling, MBHFeedbackRadiativeEfficiency, - MBHFeedbackMassEjectionFraction, MBHJetsVelocity * VelocityUnits / clight); - } - - /* Finally, add the jet feedback at the edges (outer part of the supercell) */ - - for (ic = 0; ic < n_cell_edge; ic++) { - - int index = ind_cell_edge[ic]; - float angle = anglefactor[ic]; - float cellnumberdensity = this->BaryonField[DensNum][index]*DensityUnits/mh; - - /* Update velocities and TE; note that we now have kinetic (jet) energy added, so - for DualEnergyFormalism = 0 you don't have to update any energy field */ - - sign = sign(nx_cell_edge[ic]*nx_L + ny_cell_edge[ic]*ny_L + nz_cell_edge[ic]*nz_L); - - /* Calculate grid velocity: the actual veloctiy injected in supercell edges. - This is different from MBHJetsVelocity because it is the mass-weighted average - between MBHJetsVelocity and the original veloctiy in grid */ - float oldvel[3] = {this->BaryonField[Vel1Num][index], - this->BaryonField[Vel2Num][index], - this->BaryonField[Vel3Num][index]}; - float oldcellmass = this->BaryonField[DensNum][index] * pow(this->GetCellWidth(0,0), 3); - float energybefore = this->BaryonField[TENum][index]; - - + if (MBHJetsVelocity * VelocityUnits > 0.99*clight) { + ENZO_VFAIL("grid::AddFS: MBHJetsVelocity is ultra-relativistic! (%g/ %g/ %g/ %g c)\n", + MBHFeedbackEnergyCoupling, MBHFeedbackRadiativeEfficiency, + MBHFeedbackMassEjectionFraction, MBHJetsVelocity * VelocityUnits / clight); + } + + /* Finally, add the jet feedback at the edges (outer part of the supercell) */ + + for (ic = 0; ic < n_cell_edge; ic++) { + + int index = ind_cell_edge[ic]; + float angle = anglefactor[ic]; + float cellnumberdensity = this->BaryonField[DensNum][index]*DensityUnits/mh; + + /* Update velocities and TE; note that we now have kinetic (jet) energy added, so + for DualEnergyFormalism = 0 you don't have to update any energy field */ + + sign = sign(nx_cell_edge[ic]*nx_L + ny_cell_edge[ic]*ny_L + nz_cell_edge[ic]*nz_L); + + /* Calculate grid velocity: the actual veloctiy injected in supercell edges. + This is different from MBHJetsVelocity because it is the mass-weighted average + between MBHJetsVelocity and the original veloctiy in grid */ + float oldvel[3] = {this->BaryonField[Vel1Num][index], + this->BaryonField[Vel2Num][index], + this->BaryonField[Vel3Num][index]}; + float oldcellmass = this->BaryonField[DensNum][index] * pow(this->GetCellWidth(0,0), 3); + float energybefore = this->BaryonField[TENum][index]; + + #if DENSITY_WEIGHTED - - int dim = 0; - if (GENum >= 0 && DualEnergyFormalism) - for (dim = 0; dim < GridRank; dim++) - this->BaryonField[TENum][index] -= - 0.5 * this->BaryonField[Vel1Num+dim][index] * - this->BaryonField[Vel1Num+dim][index]; - - this->BaryonField[Vel1Num][index] = (this->BaryonField[DensNum][index] * this->BaryonField[Vel1Num][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * - sign * nx_L * MBHJetsVelocity) / - (this->BaryonField[DensNum][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); - this->BaryonField[Vel2Num][index] = (this->BaryonField[DensNum][index] * - this->BaryonField[Vel2Num][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * - sign * ny_L * MBHJetsVelocity) / - (this->BaryonField[DensNum][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); - this->BaryonField[Vel3Num][index] = (this->BaryonField[DensNum][index] * - this->BaryonField[Vel3Num][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * - sign * nz_L * MBHJetsVelocity) / - (this->BaryonField[DensNum][index] + - MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); - - float newvel[3] = {this->BaryonField[Vel1Num][index], - this->BaryonField[Vel2Num][index], - this->BaryonField[Vel3Num][index]}; - float newvelmag = sqrt(newvel[0]*newvel[0] + newvel[1]*newvel[1] + newvel[2]*newvel[2]); - float energytoadd = 0.5*newvelmag*newvelmag; - - if (GENum >= 0 && DualEnergyFormalism) - for (dim = 0; dim < GridRank; dim++) - this->BaryonField[TENum][index] += - 0.5 * this->BaryonField[Vel1Num+dim][index] * - this->BaryonField[Vel1Num+dim][index]; - + + int dim = 0; + if (GENum >= 0 && DualEnergyFormalism) + for (dim = 0; dim < GridRank; dim++) + this->BaryonField[TENum][index] -= + 0.5 * this->BaryonField[Vel1Num+dim][index] * + this->BaryonField[Vel1Num+dim][index]; + + this->BaryonField[Vel1Num][index] = (this->BaryonField[DensNum][index] * this->BaryonField[Vel1Num][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * + sign * nx_L * MBHJetsVelocity) / + (this->BaryonField[DensNum][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); + this->BaryonField[Vel2Num][index] = (this->BaryonField[DensNum][index] * + this->BaryonField[Vel2Num][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * + sign * ny_L * MBHJetsVelocity) / + (this->BaryonField[DensNum][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); + this->BaryonField[Vel3Num][index] = (this->BaryonField[DensNum][index] * + this->BaryonField[Vel3Num][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3)) * + sign * nz_L * MBHJetsVelocity) / + (this->BaryonField[DensNum][index] + + MassEjected / ((float)n_cell_edge*pow(this->GetCellWidth(0,0), 3))); + + float newvel[3] = {this->BaryonField[Vel1Num][index], + this->BaryonField[Vel2Num][index], + this->BaryonField[Vel3Num][index]}; + float newvelmag = sqrt(newvel[0]*newvel[0] + newvel[1]*newvel[1] + newvel[2]*newvel[2]); + float energytoadd = 0.5*newvelmag*newvelmag; + + if (GENum >= 0 && DualEnergyFormalism) + for (dim = 0; dim < GridRank; dim++) + this->BaryonField[TENum][index] += + 0.5 * this->BaryonField[Vel1Num+dim][index] * + this->BaryonField[Vel1Num+dim][index]; + #elif SINE_WAVE - this->BaryonField[Vel1Num][index] += sign * nx_L * MBHJetsVelocity * angle; - this->BaryonField[Vel2Num][index] += sign * ny_L * MBHJetsVelocity * angle; - this->BaryonField[Vel3Num][index] += sign * nz_L * MBHJetsVelocity * angle; - float v_ejecta[3] = { sign * nx_L * MBHJetsVelocity * angle, - sign * ny_L * MBHJetsVelocity * angle, - sign * nz_L * MBHJetsVelocity * angle}; - float v_ejectamag = sqrt(v_ejecta[0]*v_ejecta[0] + v_ejecta[1]*v_ejecta[1] + v_ejecta[2]*v_ejecta[2]); - float keadded = 0.5*(MassEjected/(float)n_cell_edge)*v_ejectamag*v_ejectamag; - - /* Update the new total energy. - * keadded is due to the new grid velocities. - * eint does not change - */ - if (GENum >= 0 && DualEnergyFormalism) - this->BaryonField[TENum][index] += keadded/MassEjected; - - + this->BaryonField[Vel1Num][index] += sign * nx_L * MBHJetsVelocity * angle; + this->BaryonField[Vel2Num][index] += sign * ny_L * MBHJetsVelocity * angle; + this->BaryonField[Vel3Num][index] += sign * nz_L * MBHJetsVelocity * angle; + float v_ejecta[3] = { sign * nx_L * MBHJetsVelocity * angle, + sign * ny_L * MBHJetsVelocity * angle, + sign * nz_L * MBHJetsVelocity * angle}; + float v_ejectamag = sqrt(v_ejecta[0]*v_ejecta[0] + v_ejecta[1]*v_ejecta[1] + v_ejecta[2]*v_ejecta[2]); + float keadded = 0.5*(MassEjected/(float)n_cell_edge)*v_ejectamag*v_ejectamag; + + /* Update the new total energy. + * keadded is due to the new grid velocities. + * eint does not change + */ + if (GENum >= 0 && DualEnergyFormalism) + this->BaryonField[TENum][index] += keadded/MassEjected; + + #else - - this->BaryonField[Vel1Num][index] += sign * nx_L * MBHJetsVelocity; - this->BaryonField[Vel2Num][index] += sign * ny_L * MBHJetsVelocity; - this->BaryonField[Vel3Num][index] += sign * nz_L * MBHJetsVelocity; - float newvel[3] = {this->BaryonField[Vel1Num][index], - this->BaryonField[Vel2Num][index], - this->BaryonField[Vel3Num][index]}; - float oldvelmag = sqrt(oldvel[0]*oldvel[0] + oldvel[1]*oldvel[1] + oldvel[2]*oldvel[2]); - float newvelmag = sqrt(newvel[0]*newvel[0] + newvel[1]*newvel[1] + newvel[2]*newvel[2]); - float kebefore = 0.5*(oldcellmass)*oldvelmag*oldvelmag; - float keafter = 0.5*(oldcellmass + (MassEjected/(float)n_cell_edge))*newvelmag*newvelmag; - float v_ejecta[3] = { sign * nx_L * MBHJetsVelocity, - sign * ny_L * MBHJetsVelocity, - sign * nz_L * MBHJetsVelocity}; - float v_ejectamag = sqrt(v_ejecta[0]*v_ejecta[0] + v_ejecta[1]*v_ejecta[1] + v_ejecta[2]*v_ejecta[2]); - float keadded = 0.5*(MassEjected/(float)n_cell_edge)*v_ejectamag*v_ejectamag; - - /* Update the new total energy. - * keadded is due to the new grid velocities. - * eint does not change - */ - totalenergyadded += keadded; - //#if SSFEED_DEBUG - //printf("%s: SSFEED_DEBUG: Adding %e energy to TE. This increases TE by a factor of %e\n", - // __FUNCTION__, keadded/MassEjected, (energybefore + keadded/MassEjected)/energybefore); - //#endif - if (GENum >= 0 && DualEnergyFormalism) - this->BaryonField[TENum][index] += keadded/MassEjected; - - totalenergyafter += this->BaryonField[TENum][index]; - //#if SSFEED_DEBUG - // printf("EnergyConservation: Total Energy Added = %e\n", totalenergyadded); - //printf("EnergyConservation: Delta Grid Energy = %e (with mass = %e)\t Jet Energy = %e\n", - // totalenergyafter - totalenergybefore, (totalenergyafter - totalenergybefore)*MassEjected, - // jetenergy); - //#endif - totalenergyafter = 0; totalenergybefore = 0;totalenergyadded= 0; + + this->BaryonField[Vel1Num][index] += sign * nx_L * MBHJetsVelocity; + this->BaryonField[Vel2Num][index] += sign * ny_L * MBHJetsVelocity; + this->BaryonField[Vel3Num][index] += sign * nz_L * MBHJetsVelocity; + float newvel[3] = {this->BaryonField[Vel1Num][index], + this->BaryonField[Vel2Num][index], + this->BaryonField[Vel3Num][index]}; + float oldvelmag = sqrt(oldvel[0]*oldvel[0] + oldvel[1]*oldvel[1] + oldvel[2]*oldvel[2]); + float newvelmag = sqrt(newvel[0]*newvel[0] + newvel[1]*newvel[1] + newvel[2]*newvel[2]); + float kebefore = 0.5*(oldcellmass)*oldvelmag*oldvelmag; + float keafter = 0.5*(oldcellmass + (MassEjected/(float)n_cell_edge))*newvelmag*newvelmag; + float v_ejecta[3] = { sign * nx_L * MBHJetsVelocity, + sign * ny_L * MBHJetsVelocity, + sign * nz_L * MBHJetsVelocity}; + float v_ejectamag = sqrt(v_ejecta[0]*v_ejecta[0] + v_ejecta[1]*v_ejecta[1] + v_ejecta[2]*v_ejecta[2]); + float keadded = 0.5*(MassEjected/(float)n_cell_edge)*v_ejectamag*v_ejectamag; + + /* Update the new total energy. + * keadded is due to the new grid velocities. + * eint does not change + */ + totalenergyadded += keadded; + //#if SSFEED_DEBUG + //printf("%s: SSFEED_DEBUG: Adding %e energy to TE. This increases TE by a factor of %e\n", + // __FUNCTION__, keadded/MassEjected, (energybefore + keadded/MassEjected)/energybefore); + //#endif + if (GENum >= 0 && DualEnergyFormalism) + this->BaryonField[TENum][index] += keadded/MassEjected; + + totalenergyafter += this->BaryonField[TENum][index]; + //#if SSFEED_DEBUG + // printf("EnergyConservation: Total Energy Added = %e\n", totalenergyadded); + //printf("EnergyConservation: Delta Grid Energy = %e (with mass = %e)\t Jet Energy = %e\n", + // totalenergyafter - totalenergybefore, (totalenergyafter - totalenergybefore)*MassEjected, + // jetenergy); + //#endif + totalenergyafter = 0; totalenergybefore = 0;totalenergyadded= 0; #endif - - //return SUCCESS; //works - //printf("DeltaGrid = %e\n", this->BaryonField[TENum][index] - energybefore); - - /* Update density, species and colour fields */ - float OldDensity = this->BaryonField[DensNum][index]; - float increase = (OldDensity + rho_jet) / OldDensity; - this->BaryonField[DensNum][index] += rho_jet; - //printf("%s: Increase in Density due to Jet = %e\n", __FUNCTION__, increase); - if (MultiSpecies) { - this->BaryonField[DeNum][index] *= increase; - this->BaryonField[HINum][index] *= increase; - this->BaryonField[HIINum][index] *= increase; - this->BaryonField[HeINum][index] *= increase; - this->BaryonField[HeIINum][index] *= increase; - this->BaryonField[HeIIINum][index] *= increase; - } - if (MultiSpecies > 1) { - this->BaryonField[HMNum][index] *= increase; - this->BaryonField[H2INum][index] *= increase; - this->BaryonField[H2IINum][index] *= increase; - } - if (MultiSpecies > 2) { - this->BaryonField[DINum][index] *= increase; - this->BaryonField[DIINum][index] *= increase; - this->BaryonField[HIINum][index] *= increase; - this->BaryonField[HDINum][index] *= increase; - } - + + //return SUCCESS; //works + //printf("DeltaGrid = %e\n", this->BaryonField[TENum][index] - energybefore); + + /* Update density, species and colour fields */ + float OldDensity = this->BaryonField[DensNum][index]; + float increase = (OldDensity + rho_jet) / OldDensity; + this->BaryonField[DensNum][index] += rho_jet; + //printf("%s: Increase in Density due to Jet = %e\n", __FUNCTION__, increase); + if (MultiSpecies) { + this->BaryonField[DeNum][index] *= increase; + this->BaryonField[HINum][index] *= increase; + this->BaryonField[HIINum][index] *= increase; + this->BaryonField[HeINum][index] *= increase; + this->BaryonField[HeIINum][index] *= increase; + this->BaryonField[HeIIINum][index] *= increase; + } + if (MultiSpecies > 1) { + this->BaryonField[HMNum][index] *= increase; + this->BaryonField[H2INum][index] *= increase; + this->BaryonField[H2IINum][index] *= increase; + } + if (MultiSpecies > 2) { + this->BaryonField[DINum][index] *= increase; + this->BaryonField[DIINum][index] *= increase; + this->BaryonField[HIINum][index] *= increase; + this->BaryonField[HDINum][index] *= increase; + } - } + + } #if IMPOSETHRESHOLD - SS->NotEjectedMass = MassKeptInReserve; - printf("Mass left over for next jet = %f Msolar\n", SS->NotEjectedMass*MassUnits/SolarMass); - SS->EjectedMassThreshold = THRESHOLDFRACTION; - if(SS->EjectedMassThreshold < 1e-3) - SS->EjectedMassThreshold = 1e-3; - SS->NotEjectedMass = 0.0; + SS->NotEjectedMass = MassKeptInReserve; + printf("Mass left over for next jet = %f Msolar\n", SS->NotEjectedMass*MassUnits/SolarMass); + SS->EjectedMassThreshold = THRESHOLDFRACTION; + if(SS->EjectedMassThreshold < 1e-3) + SS->EjectedMassThreshold = 1e-3; + SS->NotEjectedMass = 0.0; #if SSFEED_DEBUG - printf("%s: New threshold Mass set to %e Msolar, total BH Mass = %e Msolar\n", __FUNCTION__, - SS->EjectedMassThreshold, SS->Mass*MassConversion/SolarMass); + printf("%s: New threshold Mass set to %e Msolar, total BH Mass = %e Msolar\n", __FUNCTION__, + SS->EjectedMassThreshold, SS->Mass*MassConversion/SolarMass); #endif #else - SS->NotEjectedMass = 0.0; + SS->NotEjectedMass = 0.0; #endif - + } + } return SUCCESS; } - + diff --git a/src/enzo/Grid_ApplySphericalFeedbackToGrid.C b/src/enzo/Grid_ApplySphericalFeedbackToGrid.C index ea9655e58..67594397b 100644 --- a/src/enzo/Grid_ApplySphericalFeedbackToGrid.C +++ b/src/enzo/Grid_ApplySphericalFeedbackToGrid.C @@ -62,10 +62,8 @@ int grid::ApplySphericalFeedbackToGrid(ActiveParticleType** ThisParticle, MetalNum = max(Metal2Num, SNColourNum); MetallicityField = (MetalNum > 0) ? TRUE : FALSE; ActiveParticleType_SmartStar *SS = static_cast(* ThisParticle); - FLOAT radius = SS->InfluenceRadius; - if(radius == 0.0) - radius = 4*this->CellWidth[0][0]; - printf("%s: radius = %e\n", __FUNCTION__, radius); + FLOAT radius = max(64*this->CellWidth[0][0], SS->InfluenceRadius); + //printf("%s: radius (in cellwidths) = %f\n", __FUNCTION__, radius/this->CellWidth[0][0]); float MetalRadius = 1.0; FLOAT MetalRadius2 = radius * radius * MetalRadius * MetalRadius; float dx = float(this->CellWidth[0][0]); diff --git a/src/enzo/Grid_CalculateSmartStarAccretionRate.C b/src/enzo/Grid_CalculateSmartStarAccretionRate.C index e117f5f6f..f1c8601a3 100644 --- a/src/enzo/Grid_CalculateSmartStarAccretionRate.C +++ b/src/enzo/Grid_CalculateSmartStarAccretionRate.C @@ -69,7 +69,7 @@ float grid::CalculateSmartStarAccretionRate(ActiveParticleType* ThisParticle, ActiveParticleType_SmartStar* SS; SS = static_cast(ThisParticle); SS->mass_in_accretion_sphere = 0.0; - float eta_disk = SS->eta_disk; + float WeightedSum = 0, AverageDensity = 0, RhoInfinity = 0.0; float AverageT=0, TotalGasMass = 0; float lambda_c = 0.25*exp(1.5); diff --git a/src/enzo/Grid_RemoveMassFromGrid.C b/src/enzo/Grid_RemoveMassFromGrid.C index ade5af590..ca004eaae 100644 --- a/src/enzo/Grid_RemoveMassFromGrid.C +++ b/src/enzo/Grid_RemoveMassFromGrid.C @@ -27,7 +27,7 @@ #include "ActiveParticle_SmartStar.h" #define TINY_NUMBER 1e-20 #define SMALL_NUMBER 1e-6 -#define ACCRETION_LIMIT 9e-1 +#define ACCRETION_LIMIT 1e-1 #define N 8 #define ANGULAR_MOMENTUM_ACCRETION 0 #define DEBUG_AP 0 diff --git a/src/enzo/ReadParameterFile.C b/src/enzo/ReadParameterFile.C index 0f0e4e400..9a8ca53e9 100644 --- a/src/enzo/ReadParameterFile.C +++ b/src/enzo/ReadParameterFile.C @@ -1355,7 +1355,6 @@ int ReadParameterFile(FILE *fptr, TopGridData &MetaData, float *Initialdt) ret += sscanf(line, "SmartStarFeedbackEnergyCoupling = %"FSYM, &SmartStarFeedbackEnergyCoupling); ret += sscanf(line, "SmartStarFeedbackJetsThresholdMass = %"FSYM, &SmartStarFeedbackJetsThresholdMass); - ret += sscanf(line, "SmartStarSMSLifetime = %"FSYM, &SmartStarSMSLifetime); ret += sscanf(line, "SmartStarSuperEddingtonAdjustment = %"ISYM, &SmartStarSuperEddingtonAdjustment); ret += sscanf(line, "SmartStarJetVelocity = %"FSYM, &SmartStarJetVelocity); ret += sscanf(line, "UseGasDrag = %"ISYM, &UseGasDrag); diff --git a/src/enzo/SetDefaultGlobalValues.C b/src/enzo/SetDefaultGlobalValues.C index 2d82879a8..7d47136c1 100644 --- a/src/enzo/SetDefaultGlobalValues.C +++ b/src/enzo/SetDefaultGlobalValues.C @@ -1037,8 +1037,7 @@ int SetDefaultGlobalValues(TopGridData &MetaData) SmartStarFeedbackJetsThresholdMass = 1.0; SmartStarJetVelocity = 1e-1; //as a fraction of clight SmartStarSuperEddingtonAdjustment = TRUE; - SmartStarSpin = 0.7; - SmartStarSMSLifetime = 2e6; //2 Myr + SmartStarSpin = 0.674351; //This gives eta_disk = 0.1 /* Gas drag parameters */ UseGasDrag = 0; GasDragCoefficient = 0.; diff --git a/src/enzo/WriteParameterFile.C b/src/enzo/WriteParameterFile.C index 4bdd10091..76b93f286 100644 --- a/src/enzo/WriteParameterFile.C +++ b/src/enzo/WriteParameterFile.C @@ -343,7 +343,6 @@ int WriteParameterFile(FILE *fptr, TopGridData &MetaData, char *name = NULL) fprintf(fptr, "SmartStarFeedbackJetsThresholdMass = %"GSYM"\n", SmartStarFeedbackJetsThresholdMass); fprintf(fptr, "SmartStarJetVelocity = %"GSYM"\n", SmartStarJetVelocity); fprintf(fptr, "SmartStarSuperEddingtonAdjustment = %"ISYM"\n", SmartStarSuperEddingtonAdjustment); - fprintf(fptr, "SmartStarSMSLifetime = %"GSYM"\n", SmartStarSMSLifetime); fprintf(fptr, "FluxCorrection = %"ISYM"\n", FluxCorrection); fprintf(fptr, "UseCoolingTimestep = %"ISYM"\n", UseCoolingTimestep); fprintf(fptr, "CoolingTimestepSafetyFactor = %"GSYM"\n", CoolingTimestepSafetyFactor); diff --git a/src/enzo/global_data.h b/src/enzo/global_data.h index 50a25fa8c..883e377e7 100644 --- a/src/enzo/global_data.h +++ b/src/enzo/global_data.h @@ -1174,7 +1174,6 @@ EXTERN float SmartStarFeedbackJetsThresholdMass; EXTERN float SmartStarJetVelocity; EXTERN float SmartStarSpin; EXTERN int SmartStarSuperEddingtonAdjustment; -EXTERN float SmartStarSMSLifetime; /* For EnzoTiming Behavior */ EXTERN int TimingCycleSkip; // Frequency of timing data dumps. From 62b0c9e6b337030153e23aec10d4df93e4ba18cb Mon Sep 17 00:00:00 2001 From: John Regan Date: Tue, 16 Mar 2021 11:28:03 +0000 Subject: [PATCH 083/115] updating formation criteria --- src/enzo/ActiveParticle_SmartStar.C | 37 ++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 97c6d6a27..04db7cf25 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -158,8 +158,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation float *PotentialField = NULL; if(data.GravPotentialNum >= 0) PotentialField = thisGrid->BaryonField[data.GravPotentialNum]; - FLOAT dx_pc = dx*data.LengthUnits/pc_cm; //in pc - //printf("PotentialField = %p\n", PotentialField); + FLOAT dx_pc = dx*data.LengthUnits/pc_cm; //in pc const int offset[] = {1, GridDimension[0], GridDimension[0]*GridDimension[1]}; @@ -195,7 +194,15 @@ int ActiveParticleType_SmartStar::EvaluateFormation #if JEANSREFINEMENT if (JeansRefinement) { CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : data.Temperature[index]; - int JeansFactor = 1; //RefineByJeansLengthSafetyFactor + /* + * The Jeans length, at the maximum refinement level is + * resolved by this many cells. On exceeding this at the maximum + * refinement level we are no longer tracking the collapse. + * SS allows refinement once this exceeds 4 (Truelove condition) + * or have the safety factor (so as to reduce the occurance of + * particles due to minor fluctuations. + */ + int JeansFactor = max(4, RefineByJeansLengthSafetyFactor/2); JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / POW(data.LengthUnits*dx*JeansFactor,2); @@ -298,8 +305,9 @@ int ActiveParticleType_SmartStar::EvaluateFormation */ double JLength = JeansLength(CellTemperature, density[index], data.DensityUnits)/data.LengthUnits; + FLOAT search_radius = max(JLength, 4*dx); GravitationalMinimum = thisGrid->FindMinimumPotential(centralpos, - JLength*RefineByJeansLengthSafetyFactor*4.0, + search_radius, PotentialField); if(PotentialField[index] > GravitationalMinimum) { #if SSDEBUG @@ -309,7 +317,8 @@ int ActiveParticleType_SmartStar::EvaluateFormation continue; } #if SSDEBUG - fprintf(stdout, "%s: Gravitational Potential Passed!\n", __FUNCTION__); + printf("%s: search_radius = %f\n", __FUNCTION__, search_radius/dx); + fprintf(stdout, "%s: Gravitational Potential Passed!\n", __FUNCTION__); #endif } @@ -339,6 +348,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation printf("%s: Forming SS particle out of cellindex %d\n", __FUNCTION__, index); fflush(stdout); + /* * Now we need to check the H2 fraction and the accretion rate now. * If the H2fraction > PopIIIH2CriticalFraction then we are ok to form a PopIII star @@ -358,6 +368,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation * 2. If the metallicity is low but the H2 fraction is high then a PopIII star forms * 3. If the metallicty is low and the H2 fraction is low but the accretion rate is high * then a SMS can form + * 4. Otherwise star formation is suppressed * We want to avoid spurious SF in a minihalo that is being heated (e.g. by LW or dynamical * heating). Therefore we insist on the mass accretion criteria. If the mass accretion rate * is low we don't allow the SMS pathway to trigger spurious SF. @@ -372,7 +383,12 @@ int ActiveParticleType_SmartStar::EvaluateFormation else if(data.H2Fraction[index] > PopIIIH2CriticalFraction) { stellar_type = POPIII; } - else if(accrate*3.154e7*ConverttoSolar/data.TimeUnits > 1e-2) { + else if((accrate*3.154e7*ConverttoSolar/data.TimeUnits > CRITICAL_ACCRETION_RATE*10.0) + && (dx_pc < SMS_RESOLUTION)) { + /* + * The threshold for initially forming the SMS is set at 10 times the critical rates. This + * ensures we get regions of truly high accretion + */ stellar_type = SMS; printf("!!!!!!!!SMS Formed\t accrate = %e Msolar/yr", accrate*3.154e7*ConverttoSolar/data.TimeUnits); @@ -903,7 +919,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle float *Temperature = new float[size](); APGrid->ComputeTemperatureField(Temperature); float CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : Temperature[cellindex]; - int JeansFactor = 1; //RefineByJeansLengthSafetyFactor + int JeansFactor = max(4, RefineByJeansLengthSafetyFactor/2); float JeansDensityUnitConversion = (Gamma*pi*kboltz) / (Mu*mh*GravConst); float JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / POW(LengthUnits*dx*JeansFactor,2); @@ -1613,11 +1629,16 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, else { if(dx_pc < SMS_RESOLUTION) { /* - * Using the time-averaged accretion rates determine if the SMS is accreting fast enough or + * Using the time-averaged accretion rates determine if the + * SMS is accreting fast enough or * if it is falling onto the main sequence. + * This can also allow a POPIII star to change into a SMS */ if((SS->AccretionRate[SS->TimeIndex]*MassUnits/TimeUnits)*yr_s/SolarMass > CRITICAL_ACCRETION_RATE) { + if(SS->ParticleClass == POPIII) { + printf("%s: UPDATE: ParticleClass switching from POPIII to SMS\n", __FUNCTION__); + } SS->ParticleClass = SMS; } else { From 4bcb97924845690c38833a08bc185edd9b9d585a Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 19 Mar 2021 12:46:37 +0000 Subject: [PATCH 084/115] Adding in ShuCollapse Test --- .../BBCollapseTestSmartStarParticle.enzo | 5 +- .../CollapseTestSmartStars.enzo | 27 ++- .../CollapseTestSmartStars/shuprofile.py | 77 ++++++--- src/enzo/ActiveParticle.C | 4 +- src/enzo/ActiveParticleRoutines.C | 4 +- src/enzo/ActiveParticle_SmartStar.C | 20 ++- src/enzo/ActiveParticle_SmartStar.h | 9 +- src/enzo/Grid_AccreteOntoSmartStarParticle.C | 13 +- .../Grid_CalculateSmartStarAccretionRate.C | 2 +- src/enzo/Grid_CollapseTestInitializeGrid.C | 4 +- src/enzo/Grid_RemoveMassFromGrid.C | 163 ------------------ 11 files changed, 97 insertions(+), 231 deletions(-) diff --git a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo index ea5f48079..9821ca970 100644 --- a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo +++ b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo @@ -26,6 +26,7 @@ CollapseTestSphereRadius[0] = 0.15625 CollapseTestSphereCoreRadius[0] = 0.05 // only used with sphere type 5 CollapseTestSphereDensity[0] = 1e2 //100 // sphere density, the background density is 1 CollapseTestSphereTemperature[0] = 10 // put sphere in pressure equilibrium (rho * T is constant) +CollapseTestSphereRotationPeriod[0] = 8.72734 CollapseTestFracKeplerianRot[0] = 0.7 CollapseTestSphereType[0] = 11 // constant density // 1: uniform @@ -92,8 +93,8 @@ RefineByJeansLengthSafetyFactor = 16 // resolve Jeans length by 4 cells (used # GreensFunctionMaxNumber = 10 // # of greens function at any one time PotentialIterations = 100 -ComputePotential = 0 -WritePotential = 0 +ComputePotential = 1 +##WritePotential = 1 # # active particle parameters # diff --git a/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo b/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo index 897f666d6..d025bc627 100644 --- a/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo +++ b/run/Hydro/Hydro-3D/CollapseTestSmartStars/CollapseTestSmartStars.enzo @@ -6,7 +6,7 @@ # ProblemType = 27 // Collapse test TopGridRank = 3 -TopGridDimensions = 128 128 128 +TopGridDimensions = 64 64 64 SelfGravity = 1 // gravity on TopGridGravityBoundary = 0 // periodic LeftFaceBoundaryCondition = 3 3 3 // periodic @@ -20,7 +20,7 @@ CollapseTestRefineAtStart = 1 // check refinement before running CollapseTestNumberOfSpheres = 1 CollapseTestUseParticles = 0 CollapseTestInitialTemperature = 5e3 // temperature of the background gas -CollapseTestSpherePosition[0] = 0.5 0.5 0.5 +CollapseTestSpherePosition[0] = 0.50 0.50 0.50 CollapseTestSphereVelocity[0] = 0.0 0.0 0.0 CollapseTestSphereRadius[0] = 0.016203778 CollapseTestSphereCoreRadius[0] = 0.05 // only used with sphere type 5 @@ -47,8 +47,8 @@ GravitationalConstant = 1.39698e-3 // 4*pi*G_{cgs}*DensityUnits*TimeUnits^2 # # set I/O and stop/start parameters # -StopTime = 1.8 -dtDataDump = 0.5 +StopTime = 2.2 +dtDataDump = 0.1 #CycleSkipDataDump = 1 DataDumpDir = DD DataDumpName = DD @@ -76,10 +76,10 @@ Mu = 3.0 # # set grid refinement parameters # -StaticHierarchy = 1 // dynamic hierarchy -MaximumRefinementLevel = 0 // use up to 10 levels +StaticHierarchy = 0 // dynamic hierarchy +MaximumRefinementLevel = 7 // 7 levels of AMR RefineBy = 2 // refinement factor -CellFlaggingMethod = 2 4 // use baryon mass and Truelove criterion for refinement +CellFlaggingMethod = 2 4 // use baryon mass and Truelove criterion for refinement MinimumEfficiency = 0.3 #OutputFirstTimeAtLevel = 4 // output when level 4, 5, 6, etc reached (commented out for now) #StopFirstTimeAtLevel = 10 // stop if/when level 10 reached @@ -100,12 +100,7 @@ WritePotential = 0 # AppendActiveParticleType = SmartStar RadiativeTransfer = 0 -ActiveParticleDensityThreshold = 1.33e7 -MBHAccretion = 1 -SmartStarSMSLifetime = 1e100 -SmartStarFeedback = 0 //Sets feedback of any kind -SmartStarBHRadiativeFeedback = 0 //We don't want RT for a Black Hole -SmartStarRadiativeFeedback = 0 //Always required since we start life as an SMS? -SmartStarJetFeedback = 0 -SmartStarThermalFeedback = 0 -SmartStarJetVelocity = 1e-3 +ActiveParticleDensityThreshold = 1e11 +MBHAccretion = 8 +SmartStarFeedback = 0 //Sets feedback of any kind off + diff --git a/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py b/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py index 4b38b1a9c..84c8b91e1 100644 --- a/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py +++ b/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py @@ -1,4 +1,3 @@ - import matplotlib matplotlib.use('Agg') import yt @@ -11,26 +10,28 @@ from scipy.signal import savgol_filter yt.enable_parallelism() -mycolors = iter(['red', 'blue', 'black', 'green', 'magenta']) +mycolors = iter(['red', 'blue', 'black', 'green', 'magenta', 'grey']) def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) return -4.0*np.pi*data["radius"]*data["radius"]*data["density"]*data["radial_velocity"] #Add Derived Rates yt.add_field(("gas", "shell_accretion_rate"), units="Msun/yr", - function=_Accretion_Rate) + function=_Accretion_Rate, sampling_type="cell") -BASE = "/home/regan/data/SourceCodes/EnzoGit/fearmayo/enzo-dev/run/Hydro/Hydro-3D/CollapseTestSmartStars/" +BASE = "./" Mu = 3.0 CENTRE = [0.5, 0.5, 0.5] Files = glob.glob(BASE + "DD00??/DD00??") Files.sort() -#Files = ["DD0000/DD0000", -# "DD0001/DD0001", -# "DD0002/DD0002", -# "DD0003/DD0003"] +Files = ["DD0000/DD0000", + "DD0008/DD0008", + "DD0012/DD0012", + "DD0015/DD0015", + "DD0017/DD0017", + "DD0021/DD0021"] print("Files = ", Files) @@ -49,6 +50,7 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) accrate = [] ages = [] +cellwidth = 0.0 for f in Files: ff = f ds = yt.load(ff) @@ -56,8 +58,10 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) NumAPs = 0 flist = dir(ds.fields) if yt.is_root(): - print("Stats = %e cm" % (ds.index.get_smallest_dx().in_units("cm"))) - print("Stats = %e pc" % (ds.index.get_smallest_dx().in_units("pc"))) + print("CellWidth = %e cm" % (ds.index.get_smallest_dx().in_units("cm"))) + print("4*CellWidth = %e cm" % (4*ds.index.get_smallest_dx().in_units("cm"))) + print("CellWidth = %e pc" % (ds.index.get_smallest_dx().in_units("pc"))) + print("Current Time = %e s" % (ds.current_time.in_units("s"))) print("Current Time = %e code" % (ds.current_time.in_units("code_time"))) print("Current Time = %e yr" % (ds.current_time.in_units("yr"))) @@ -66,22 +70,27 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) centre = dd["SmartStar", "particle_position"][0] except: centre = CENTRE + cellwidth = ds.index.get_smallest_dx().in_units("cm") time = ds.current_time.in_units("yr") - if(time > 0): + if(time > 0 and NumAPs > 0): timeindex = dd["SmartStar", "TimeIndex"][0].d accrate = dd["SmartStar", "AccretionRate"][0][1:int(timeindex+1)].in_units("Msun/yr") ages = dd["SmartStar", "AccretionRateTime"][0][1:int(timeindex+1)].in_units("yr") deltaT = np.ediff1d(ages, to_begin=1) masses = accrate*deltaT - #print("accrate = ", accrate) + print("Pos = %f %f %f" % (dd["SmartStar", "particle_position"][0][0], + dd["SmartStar", "particle_position"][0][1], + dd["SmartStar", "particle_position"][0][2])) #print("ages = ", ages) #print("masses = ", masses) + if(time > 0 and NumAPs == 0): + continue print("NumAPs = ", NumAPs) print("Accreting Particle Position = ", centre) # Create a sphere of radius 1 kpc in the center of the box. my_sphere = ds.sphere(centre, (1.0, "pc")) - + color = next(mycolors) # Create a profile of the average density vs. radius. prof = yt.create_profile(my_sphere, "radius", YFields, units = {'radius': 'cm'}, @@ -93,7 +102,7 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) #Plot Density FieldsAxes["density"].loglog(Radius, Density, label="T = %2.2e yrs" % - (ds.current_time.in_units("yr")), linewidth=2.0) + (ds.current_time.in_units("yr")), linewidth=2.0, color=color) #Add in analytic expression from Shu et al. (1977) T = ds.current_time.in_units("s") @@ -106,7 +115,8 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) shu_density = np.power(cs, 1.5)*m0/(4*np.pi*G*np.sqrt(2.0*T)*np.power(Radius, 1.5)) shu_density = shu_density[Radius.d < 2e16] shu_radius = Radius[Radius.d < 2e16] - FieldsAxes["density"].loglog(shu_radius, shu_density, ls='dotted', linewidth=2.0) + #print("shu_density = ", shu_density) + FieldsAxes["density"].loglog(shu_radius, shu_density, ls='dotted', linewidth=2.0, color=color) #Radial Velocity Plots RadialVelocity = prof["radial_velocity"][prof["density"] > 0.0].in_units("km/s") EnclosedMass = prof["cell_mass"][prof["density"] > 0.0] @@ -114,11 +124,13 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) FieldsAxes["radial_velocity"].semilogx(Radius, RadialVelocity, label="T = %2.2e yrs" % (ds.current_time.in_units("yr")), - linewidth=2.0) + linewidth=2.0, color=color) #Add in analytic expression from Shu et al. (1977) + # Need reasonably high resolution to get here. shu_radial = -cs*m0*np.sqrt(2*cs*T/Radius)/1e5 shu_radial = shu_radial[Radius.d < 2e16] - FieldsAxes["radial_velocity"].semilogx(shu_radius, shu_radial, ls='dotted', linewidth=2.0) + FieldsAxes["radial_velocity"].semilogx(shu_radius, shu_radial, ls='dotted', linewidth=2.0, + color=color) #Accretion Plots AccretionRate = prof["shell_accretion_rate"][prof["density"] > 0.0] #print "Accretion Rate = ", AccretionRate @@ -126,7 +138,7 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) FieldsAxes["shell_accretion_rate"].loglog(Radius, AccretionRate, label="T = %2.2e yrs" % (ds.current_time.in_units("yr")) - ,linewidth=2.0) + ,linewidth=2.0, color=color) #Add in analytic expression shu_accretion_rate = (m0*m0*np.power(cs, 3.0)/G).d shu_accretion_rate = YTArray(shu_accretion_rate, 'g/s', registry=ds.unit_registry) @@ -134,10 +146,19 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) shu_accretion_rate = shu_accretion_rate[Radius.d < 2e16].in_units("Msun/yr") #print "Shu Accretion Rate = ", shu_accretion_rate FieldsAxes["shell_accretion_rate"].loglog(shu_radius, shu_accretion_rate, - ls='dotted', linewidth=2.0) + ls='dotted', linewidth=2.0, color=color) + + #ProjectionPlots + prj = yt.ProjectionPlot(ds, "x", "number_density", weight_field="density", width=(0.025, 'pc'), + axes_unit="cm") + prj.set_zlim("number_density", 1e4, 1e8) + prj.annotate_sphere(centre, radius=(0.0001, 'pc'), + circle_args={'color':'black', 'fill':'true'}) + prj.save("NumberDensity_Proj_%s.png" % (ds)) -XS = 1e15 + +XS = cellwidth.d/2 XE = 1e17 #Add in accretion radius #Add in minimum cell width @@ -164,7 +185,7 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) FieldsAxes["radial_velocity"].set_xlabel("R [cm]", fontsize=18) FieldsAxes["radial_velocity"].set_ylabel("V$_r$ [km s$^{-1}$]", fontsize=18) FieldsAxes["radial_velocity"].set_xlim(XS, XE) -FieldsAxes["radial_velocity"].set_ylim(-5, 0) +FieldsAxes["radial_velocity"].set_ylim(-15, 0) FieldsAxes["radial_velocity"].xaxis.labelpad = -2 FieldsFigure["radial_velocity"].savefig("RadialVelocityProfile.png") FieldsFigure["radial_velocity"].savefig("RadialVelocityProfile.pdf") @@ -188,17 +209,25 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) accrate = savgol_filter(accrate, 33, 1,mode='nearest') #plot the accretion rate over time -plt.plot(ages, accrate*1e4) +plt.plot(ages, accrate*1e4, lw=2.0, color='k') plt.xlabel("Time [yr]", fontsize=18) -plt.ylabel("Accretion Rate [M$_{\odot}$ yr$^{-1}$]", fontsize=18) +plt.ylabel("Accretion Rate [10$^4$ M$_{\odot}$ yr$^{-1}$]", fontsize=18) #plt.ylim(1e-5, 1e-3) plt.savefig("AccretionRateEvolution.png") +#Average Accretion Rate between 5000 and 12000 years +val_low = ages[ages > 5000][0] +index_low = np.asscalar(np.where(ages.d == val_low)[0]) +val_high = ages[ages > 12000][0] +index_high = np.asscalar(np.where(ages.d == val_high)[0]) + +avg_array = accrate[index_low:index_high] +print("Average Accretion Rate = %e Msolar/yr" % (np.mean(avg_array))) plt.figure() masses = np.cumsum(masses) masses = savgol_filter(masses, 5, 1,mode='nearest') #plot the mass against time -plt.plot(ages, masses) +plt.plot(ages, masses, lw=2.0, color='k') plt.xlabel("Time [yr]", fontsize=18) plt.ylabel("Particle Mass [M$_{\odot}$]", fontsize=18) plt.savefig("MassEvolution.png") diff --git a/src/enzo/ActiveParticle.C b/src/enzo/ActiveParticle.C index aa8873e99..5d76aa5a6 100644 --- a/src/enzo/ActiveParticle.C +++ b/src/enzo/ActiveParticle.C @@ -272,7 +272,7 @@ void ActiveParticleType::ConstructData(grid *_grid, } _grid->ConvertColorFieldsToFractions(); - + if(MultiSpecies > 1) { /* If creating primordial stars, make a total H2 density field */ float *h2field = NULL; @@ -287,7 +287,7 @@ void ActiveParticleType::ConstructData(grid *_grid, } data.H2Fraction = h2field; } - + } if (flags.CoolingTime) { /* Compute the cooling time. */ diff --git a/src/enzo/ActiveParticleRoutines.C b/src/enzo/ActiveParticleRoutines.C index 5749ff666..4f5692e08 100644 --- a/src/enzo/ActiveParticleRoutines.C +++ b/src/enzo/ActiveParticleRoutines.C @@ -242,15 +242,15 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) { int dim; double ratio1, ratio2; - ratio1 = Mass / (Mass + a->Mass); + ratio1 = (max(Mass, 1e-10)) / (max(1e-10,Mass) + max(1e-10, a->Mass)); ratio2 = 1.0 - ratio1; + Metallicity = ratio1 * Metallicity + ratio2 * a->Metallicity; for (dim = 0; dim < MAX_DIMENSION; dim++) { pos[dim] = ratio1 * pos[dim] + ratio2 * a->pos[dim]; vel[dim] = ratio1 * vel[dim] + ratio2 * a->vel[dim]; } - if(Mass > a->Mass) { ; } diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 04db7cf25..94ebb9e53 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -127,6 +127,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation SmartStarGrid *thisGrid = static_cast(thisgrid_orig); + static int shu_collapse = 0; int i,j,k,index,method,MassRefinementMethod; float *density = thisGrid->BaryonField[data.DensNum]; @@ -347,7 +348,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation #endif - printf("%s: Forming SS particle out of cellindex %d\n", __FUNCTION__, index); fflush(stdout); + //printf("%s: Forming SS particle out of cellindex %d\n", __FUNCTION__, index); fflush(stdout); /* * Now we need to check the H2 fraction and the accretion rate now. @@ -374,11 +375,14 @@ int ActiveParticleType_SmartStar::EvaluateFormation * is low we don't allow the SMS pathway to trigger spurious SF. */ int stellar_type = -99999; - if(HasMetalField && data.TotalMetals[index] > PopIIIMetalCriticalFraction) { + if(shu_collapse == 1) + continue; + if(MultiSpecies == 0) { //no chemistry, testing use only + stellar_type = POPIII; + shu_collapse = 1; //prevents further formation + } + else if(HasMetalField && data.TotalMetals[index] > PopIIIMetalCriticalFraction) { stellar_type = POPII; - // float PopIIMass = StarClusterFormEfficiency*ExtraDensity*dx*dx*dx*ConverttoSolar; - // if(PopIIMass < StarClusterMinimumMass) - // continue; } else if(data.H2Fraction[index] > PopIIIH2CriticalFraction) { stellar_type = POPIII; @@ -425,8 +429,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->vel[0] = apvel[0]; np->vel[1] = apvel[1]; np->vel[2] = apvel[2]; - - + if (HasMetalField) np->Metallicity = data.TotalMetals[index]; else @@ -930,6 +933,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle float ParticleDensity = density[cellindex] - DensityThreshold; float newcelldensity = density[cellindex] - ParticleDensity; + if(SMS == SS->ParticleClass) { if(dx_pc <= SMS_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ @@ -944,7 +948,6 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); ENZO_FAIL("Particle Density is negative. Oh dear.\n"); } - printf("SMS: cellindex %d updated - next.\n\n", cellindex); continue; } } @@ -962,7 +965,6 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); ENZO_FAIL("Particle Density is negative. Oh dear.\n"); } - printf("POPIII: cellindex %d updated - next.\n\n", cellindex); continue; } } diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index ea5f065de..2c957ec04 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -243,9 +243,9 @@ void ActiveParticleType_SmartStar::MergeSmartStars( FLOAT ParticleCoordinates[3*(*nParticles)]; fflush(stdout); - /* Particles merge once they come within 1 accretion radii of one another */ + /* Particles merge once they come within 2 accretion radii of one another */ - FLOAT MergingRadius = LevelArray[ThisLevel]->GridData->GetCellWidth(0,0)*ACCRETIONRADIUS; + FLOAT MergingRadius = 2.0*LevelArray[ThisLevel]->GridData->GetCellWidth(0,0)*ACCRETIONRADIUS; for (i=0; i<(*nParticles); i++) { tempPos = ParticleList[i]->ReturnPosition(); @@ -293,11 +293,10 @@ void ActiveParticleType_SmartStar::MergeSmartStars( it to the new grid*/ int NewGrid = -1; - for (i = 0; i < *ngroups; i++) { if (MergedParticles[i]->ReturnCurrentGrid()->PointInGrid( MergedParticles[i]->ReturnPosition()) == false) { - // Find the grid to transfer to + // Find the grid to transfer to for (j = 0; j < NumberOfGrids; j++) { if (LevelGrids[j]->GridData->PointInGrid( MergedParticles[i]->ReturnPosition())) { @@ -390,7 +389,7 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( ParticleList); //if (AssignActiveParticlesToGrids(ParticleList, nParticles, // LevelArray) == FAIL) - // return FAIL; + //return FAIL; if (debug) printf("Number of particles before merging: %"ISYM"\n",nParticles); /* Do Merging */ diff --git a/src/enzo/Grid_AccreteOntoSmartStarParticle.C b/src/enzo/Grid_AccreteOntoSmartStarParticle.C index 720a58f98..0678106a3 100644 --- a/src/enzo/Grid_AccreteOntoSmartStarParticle.C +++ b/src/enzo/Grid_AccreteOntoSmartStarParticle.C @@ -125,12 +125,17 @@ int grid::AccreteOntoSmartStarParticle( printf("%s: AccretedMass = %e\n", __FUNCTION__, AccretedMass); #endif float *Vel = SS->vel; - + + /* Smooth velocities over the cells in the accretion zone + * otherwise we treat the particle as a point mass which + * is undesirable + */ + float smoothingzone = pow(ACCRETIONRADIUS + 1, 3.0); float NewVelocity[3] = { - (Vel[0]+delta_vpart[0]), - (Vel[1]+delta_vpart[1]), - (Vel[2]+delta_vpart[2]) + (Vel[0]+delta_vpart[0]/smoothingzone), + (Vel[1]+delta_vpart[1]/smoothingzone), + (Vel[2]+delta_vpart[2]/smoothingzone) }; ThisParticle->SetVelocity(NewVelocity); diff --git a/src/enzo/Grid_CalculateSmartStarAccretionRate.C b/src/enzo/Grid_CalculateSmartStarAccretionRate.C index f1c8601a3..2c13e0b36 100644 --- a/src/enzo/Grid_CalculateSmartStarAccretionRate.C +++ b/src/enzo/Grid_CalculateSmartStarAccretionRate.C @@ -31,7 +31,7 @@ #define SMALL_NUMBER 1e-6 #define ACCRETION_LIMIT 1e-1 #define C_VISC 2.1e6 -#define DEBUG_AP 0 + float bondi_alpha(float x); int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, diff --git a/src/enzo/Grid_CollapseTestInitializeGrid.C b/src/enzo/Grid_CollapseTestInitializeGrid.C index c285f3a2e..7e1dd3480 100644 --- a/src/enzo/Grid_CollapseTestInitializeGrid.C +++ b/src/enzo/Grid_CollapseTestInitializeGrid.C @@ -159,8 +159,7 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, /* Set various units. */ float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, - VelocityUnits, CriticalDensity = 1, BoxLength = 1, mu = 0.6; - + VelocityUnits, CriticalDensity = 1, BoxLength = 1, mu = Mu; FLOAT a, dadt, ExpansionFactor = 1; GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, &TimeUnits, &VelocityUnits, Time); @@ -327,7 +326,6 @@ int grid::CollapseTestInitializeGrid(int NumberOfSpheres, case 2: SphereMass = 4*pi*pow((SphereRadius[sphere]*LengthUnits), 3) * (SphereDensity[sphere]*DensityUnits); - mu = Mu; printf("mass = %"GSYM", lunit = %"GSYM", dunit = %"GSYM", rho = %"GSYM", r = %"GSYM"\n", SphereMass, LengthUnits, DensityUnits, SphereDensity[sphere], SphereRadius[sphere]); diff --git a/src/enzo/Grid_RemoveMassFromGrid.C b/src/enzo/Grid_RemoveMassFromGrid.C index ca004eaae..a64e55ea0 100644 --- a/src/enzo/Grid_RemoveMassFromGrid.C +++ b/src/enzo/Grid_RemoveMassFromGrid.C @@ -468,166 +468,3 @@ int grid::RemoveMassFromGrid(ActiveParticleType* ThisParticle, return SUCCESS; } -#ifdef DONOTCOMPILE -/* - * Remove mass from Grid after AP formation. - * The mass should be removed in a resolution dependent way. - */ - -int grid::RemoveMassFromGridAfterFormation(FLOAT* starpos, - int ParticleClass, - FLOAT AccretionRadius, - float particle_mass, - int cellindex, - float newcelldensity, - float original_pmass) - -{ - FLOAT dx = CellWidth[0][0]; - float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, - PressureUnits = 0, GEUnits = 0, VelUnits = 0; - double MassUnits = 1, CellVolume = 1; - if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, Time) == FAIL) { - ENZO_FAIL("Error in GetUnits."); - } - MassUnits = DensityUnits * POW(LengthUnits,3); - int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; - if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) - { - ENZO_FAIL("Error in IdentifyPhysicalQuantities."); - } - FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc - float *density = BaryonField[DensNum]; - if(SMS == ParticleClass) { - - if(dx_pc <= SMS_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ - density[cellindex] = newcelldensity; - return SUCCESS; - } - } - - else if(POPIII == ParticleClass) { - if(dx_pc <= POPIII_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ - density[cellindex] = newcelldensity; - return SUCCESS; - } - } - else if(POPII == ParticleClass) { - /* - * For PopII stars we do this if the mass exceeds the minimum mass - */ - float PopIIMass = particle_mass*dx*dx*dx*MassUnits/SolarMass; - if(PopIIMass > StarClusterMinimumMass) { - density[cellindex] = (1 - StarClusterFormEfficiency)*density[cellindex]; - return SUCCESS; - } - } - - - - /* - * If the formation mass is below a resolution based threshold - * Remove mass from grid and replace by a uniform density sphere which accounts for the - * subgrid ionisation that has taken place and accounts for the mass that should have been - * accreted. - */ - - /*********************************************************************** - - For star formation, we need to find a sphere with enough mass to - accrete. We step out by a cell width when searching. - - ***********************************************************************/ - - FLOAT Radius = AccretionRadius; - int feedback_flag = -99999; - float MassEnclosed = 0; - float Metallicity2 = 0; - float Metallicity3 = 0; - float ColdGasMass = 0; - float AvgVelocity[MAX_DIMENSION]; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] = 0.0; - bool SphereTooSmall = true; - float ShellMass, ShellMetallicity2, ShellMetallicity3, ShellColdGasMass, - ShellVelocity[MAX_DIMENSION]; - while (SphereTooSmall) { - Radius += CellWidth[0][0]; - SphereContained = this->SphereContained(LevelArray, level, Radius); - if (SphereContained == FALSE) - break; - - - ShellMass = 0; - ShellMetallicity2 = 0; - ShellMetallicity3 = 0; - ShellColdGasMass = 0; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - ShellVelocity[dim] = 0.0; - - /* Sum enclosed mass in this grid */ - this->GetEnclosedMassInShell(starpos, Radius-CellWidth[0][0], Radius, - ShellMass, ShellMetallicity2, - ShellMetallicity3, - ShellColdGasMass, ShellVelocity, - feedback_flag); - - values[0] = ShellMetallicity2; - values[1] = ShellMetallicity3; - values[2] = ShellMass; - values[3] = ShellColdGasMass; - for (dim = 0; dim < MAX_DIMENSION; dim++) - values[4+dim] = ShellVelocity[dim]; - - LCAPERF_START("star_FindFeedbackSphere_Sum"); - CommunicationAllSumValues(values, 7); - LCAPERF_STOP("star_FindFeedbackSphere_Sum"); - - ShellMetallicity2 = values[0]; - ShellMetallicity3 = values[1]; - ShellMass = values[2]; - ShellColdGasMass = values[3]; - for (dim = 0; dim < MAX_DIMENSION; dim++) - ShellVelocity[dim] = values[4+dim]; - - MassEnclosed += ShellMass; - ColdGasMass += ShellColdGasMass; - - // Must first make mass-weighted, then add shell mass-weighted - // (already done in GetEnclosedMassInShell) velocity and - // metallicity. We divide out the mass after checking if mass is - // non-zero. - Metallicity2 = Metallicity2 * (MassEnclosed - ShellMass) + ShellMetallicity2; - Metallicity3 = Metallicity3 * (MassEnclosed - ShellMass) + ShellMetallicity3; - for (dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] = AvgVelocity[dim] * (MassEnclosed - ShellMass) + - ShellVelocity[dim]; - - if (MassEnclosed == 0) { - return SUCCESS; - } - - Metallicity2 /= MassEnclosed; - Metallicity3 /= MassEnclosed; - for (dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] /= MassEnclosed; - - - - - if(POPII == ParticleClass) { - - ; - - - } - SphereTooSmall = false; - } - - - return SUCCESS; -} -#endif From 0e6de247d3a9c7f3acc44e2a4674ce768e4d7bb7 Mon Sep 17 00:00:00 2001 From: John Regan Date: Wed, 24 Mar 2021 15:54:14 +0000 Subject: [PATCH 085/115] Added Collapse and Burkert-Bodenheimer Tests --- doc/manual/source/parameters/index.rst | 22 +++----- .../source/physics/active_particles.rst | 3 +- .../BBCollapseTestSmartStarParticle.enzo | 12 ++-- .../sinkslices.py | 3 +- .../CollapseTestSmartStars/shuprofile.py | 4 +- src/enzo/ActiveParticleRoutines.C | 2 + src/enzo/ActiveParticle_SmartStar.C | 55 ++++++++++--------- src/enzo/ActiveParticle_SmartStar.h | 14 ++--- 8 files changed, 56 insertions(+), 59 deletions(-) diff --git a/doc/manual/source/parameters/index.rst b/doc/manual/source/parameters/index.rst index 62068e9d7..fb5996a86 100644 --- a/doc/manual/source/parameters/index.rst +++ b/doc/manual/source/parameters/index.rst @@ -2495,12 +2495,12 @@ SmartStar Feedback Default: 0 ``SmartStarStellarRadiativeFeedback`` (external) - This parameter controls whether stellar feedback is activated or not. For feedback from PopIII or SMSs then this needs to be on. - The stellar radiative feedback is divided up into 5 energy bins. The energy bins have energies of 2.0 eV, 12.8 eV, 14.0 eV, 25.0 eV - and 200 eV. The fraction of energy assigned to each bin is determined using the PopIII tables from Schaerer et. al 2002 Table 4. - The spectrum for a PopIII star and SMS are different. For a PopIII star a spectrum for a 40 Msolar star is assumed and - weighted accordingly. For a SMS a 1000 Msolar star is assumed and weighted accordingly. - Future improvements to the SEDs employed here are under active investigation. + This parameter controls whether stellar feedback is activated or not. + For feedback from PopII, PopIII or SMSs then this needs to be on. + The stellar radiative feedback is divided up into 5 energy bins. See `DetermineSEDParameters.C` for details. + For PopII stars the energy bins are: 2.0 eV, 12.8 eV, 21.62 eV, 30.0 eV and 60 eV. + For PopIII stars the energy bins are: 2.0 eV, 12.8 eV, 28.0 eV, 30.0 eV and 58 eV. + For SMS stars the energy bins are: 2.0 eV and 12.8 eV Default: 0 ``SmartStarBHFeedback`` (external) @@ -2534,13 +2534,9 @@ SmartStar Feedback ``SmartStarSpin`` (external) The dimensionless spin of the SmartStar particle. This is a very unconstrained parameter and cannot be readily computed on the fly. This parameter - should be set if you want to have jet feedback. Setting this is zero and turning on jet feedback wouldn't make sense. The default is set to be 0.7 and - this is probably reasonable. - Default: 0.7 - -``SmartStarSMSLifetime`` (external) - This is the lifetime for a supermassive star in years. After this time has elapsed a SmartStar particle which is behaving like a SMS will collapse - directly into a black hole with no supernova event. Default: 1e6 + should be set if you want to have jet feedback. Setting this is zero and turning on jet feedback wouldn't make sense. The default is set to be 0.674351 and + this leads to a radiative efficiency of 1. + Default: 0.674351 ``SmartStarJetVelocity`` (external) The velocity that the jets are ejected at. Typically jets are observed to travel at a substantial fraction of the speed of light - diff --git a/doc/manual/source/physics/active_particles.rst b/doc/manual/source/physics/active_particles.rst index 5260be62c..276426bae 100644 --- a/doc/manual/source/physics/active_particles.rst +++ b/doc/manual/source/physics/active_particles.rst @@ -60,7 +60,8 @@ ______________________________ The ``SmartStar`` particle is built on top of the ``AccretingParticle`` type with additional feedback and accretion protocols attached. The ``SmartStar`` particle was designed to be a single particle type that could adjust to the environment -in which it finds itself. Currently it can represent a PopIII star, +in which it finds itself. ``SmartStar`` is designed to model resolved star formation. +Currently it can represent a PopII star, PopIII star, a super-massive star or a black hole. However, there is no inherent limit to the physical object it can represent. In that sense it may be suitable to augment the ``SmartStar`` particle with your required feature rather than implmenting a new feature. You will also be able to build on ``SmartStar`` tests and documentation too rather than starting from scratch. diff --git a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo index 9821ca970..af226dfcf 100644 --- a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo +++ b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/BBCollapseTestSmartStarParticle.enzo @@ -6,7 +6,7 @@ # ProblemType = 27 // Collapse test TopGridRank = 3 -TopGridDimensions = 32 32 32 +TopGridDimensions = 64 64 64 SelfGravity = 1 // gravity on TopGridGravityBoundary = 0 // periodic LeftFaceBoundaryCondition = 3 3 3 // periodic @@ -49,8 +49,8 @@ GravitationalConstant = 0.0320327594 // 4*pi*G_{cgs}*DensityUnits*TimeUnits^2 # # set I/O and stop/start parameters # -StopTime = 1.7 -dtDataDump = 6e-2 +StopTime = 1.45 +dtDataDump = 0.01 #CycleSkipDataDump = 1 DataDumpDir = DD DataDumpName = DD @@ -79,13 +79,13 @@ Mu = 3.0 # set grid refinement parameters # StaticHierarchy = 0 // dynamic hierarchy -MaximumRefinementLevel = 7 // use up to 7 levels +MaximumRefinementLevel = 4 // use up to 4 levels RefineBy = 2 // refinement factor CellFlaggingMethod = 2 6 // refine on baryon mass and Jeans Length MinimumEfficiency = 0.3 #OutputFirstTimeAtLevel = 4 // output when level 4, 5, 6, etc reached (commented out for now) #StopFirstTimeAtLevel = 10 // stop if/when level 10 reached -RefineByJeansLengthSafetyFactor = 16 // resolve Jeans length by 4 cells (used with CellFlaggingMethod 6) +RefineByJeansLengthSafetyFactor = 16 // resolve Jeans length by 16 cells (used with CellFlaggingMethod 6) # @@ -94,7 +94,7 @@ RefineByJeansLengthSafetyFactor = 16 // resolve Jeans length by 4 cells (used GreensFunctionMaxNumber = 10 // # of greens function at any one time PotentialIterations = 100 ComputePotential = 1 -##WritePotential = 1 +WritePotential = 0 # # active particle parameters # diff --git a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py index 4cd335952..ac9fad3eb 100644 --- a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py +++ b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py @@ -12,9 +12,8 @@ CENTRE = [0.5, 0.5, 0.5] #CENTRE = [0.50231934, 0.49035645, 0.49865723] AccretionRadius = 4 -BASE = "/home/regan/data/SourceCodes/Enzo-RT/enzo-3.0-rt/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/GravPotential/" BASE = "./GravPotential/" -fns = glob.glob(BASE + "DD002?/DD????.hierarchy") +fns = glob.glob(BASE + "DD013?/DD????.hierarchy") fns.sort() #print fns WIDTH = 8000 diff --git a/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py b/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py index 84c8b91e1..680ec7127 100644 --- a/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py +++ b/run/Hydro/Hydro-3D/CollapseTestSmartStars/shuprofile.py @@ -21,7 +21,7 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) BASE = "./" Mu = 3.0 -CENTRE = [0.5, 0.5, 0.5] +CENTRE = [0.50, 0.50, 0.50] Files = glob.glob(BASE + "DD00??/DD00??") @@ -150,7 +150,7 @@ def _Accretion_Rate(field, data): #M' = 4*pi*R*R*rho(R)*V(R) #ProjectionPlots - prj = yt.ProjectionPlot(ds, "x", "number_density", weight_field="density", width=(0.025, 'pc'), + prj = yt.ProjectionPlot(ds, "x", "number_density", weight_field="density", width=(0.025, 'pc'), center=centre, axes_unit="cm") prj.set_zlim("number_density", 1e4, 1e8) prj.annotate_sphere(centre, radius=(0.0001, 'pc'), diff --git a/src/enzo/ActiveParticleRoutines.C b/src/enzo/ActiveParticleRoutines.C index 4f5692e08..380a3cbe4 100644 --- a/src/enzo/ActiveParticleRoutines.C +++ b/src/enzo/ActiveParticleRoutines.C @@ -242,6 +242,8 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) { int dim; double ratio1, ratio2; + if((Mass == 0.0) || (a->Mass == 0.0)) + return; ratio1 = (max(Mass, 1e-10)) / (max(1e-10,Mass) + max(1e-10, a->Mass)); ratio2 = 1.0 - ratio1; diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 94ebb9e53..b48a26f9b 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -22,6 +22,7 @@ #define MASSTHRESHOLD 0.1 //Msolar in grid #define COOLING_TIME 0 #define NUMSSPARTICLETYPES 4 +#define JEANS_FACTOR 2 int DetermineSEDParameters(ActiveParticleType_SmartStar *SS,FLOAT Time, FLOAT dx); /* We need to make sure that we can operate on the grid, so this dance is @@ -127,7 +128,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation SmartStarGrid *thisGrid = static_cast(thisgrid_orig); - static int shu_collapse = 0; + //static int shu_collapse = 0; int i,j,k,index,method,MassRefinementMethod; float *density = thisGrid->BaryonField[data.DensNum]; @@ -196,14 +197,13 @@ int ActiveParticleType_SmartStar::EvaluateFormation if (JeansRefinement) { CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : data.Temperature[index]; /* - * The Jeans length, at the maximum refinement level is - * resolved by this many cells. On exceeding this at the maximum - * refinement level we are no longer tracking the collapse. - * SS allows refinement once this exceeds 4 (Truelove condition) - * or have the safety factor (so as to reduce the occurance of - * particles due to minor fluctuations. + * The density threshold is exceeded here once the Jeans + * Density in one cell is exceeded - see Krumholz et al. (2004) + * Krumholz et al. use a Jeans factor of 4, I found that + * pushing this to 2 (i.e. making the threshold higher) is + * more accurate. */ - int JeansFactor = max(4, RefineByJeansLengthSafetyFactor/2); + int JeansFactor = JEANS_FACTOR; JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / POW(data.LengthUnits*dx*JeansFactor,2); @@ -306,7 +306,7 @@ int ActiveParticleType_SmartStar::EvaluateFormation */ double JLength = JeansLength(CellTemperature, density[index], data.DensityUnits)/data.LengthUnits; - FLOAT search_radius = max(JLength, 4*dx); + FLOAT search_radius = JLength; GravitationalMinimum = thisGrid->FindMinimumPotential(centralpos, search_radius, PotentialField); @@ -314,11 +314,14 @@ int ActiveParticleType_SmartStar::EvaluateFormation #if SSDEBUG printf("FAILURE: GravitationalMinimum = %g\t " \ "PotentialField[index] = %g\n\n", GravitationalMinimum, PotentialField[index]); + printf("%s: Cellwidth = %f\t JLength = %f\n", __FUNCTION__, dx, JLength); + printf("%s: search_radius (in cellwidths) = %f\n", __FUNCTION__, search_radius/dx); #endif continue; } #if SSDEBUG - printf("%s: search_radius = %f\n", __FUNCTION__, search_radius/dx); + printf("%s: Cellwidth = %f\t JLength = %f\n", __FUNCTION__, dx, JLength); + printf("%s: search_radius (in cellwidths) = %f\n", __FUNCTION__, search_radius/dx); fprintf(stdout, "%s: Gravitational Potential Passed!\n", __FUNCTION__); #endif } @@ -375,11 +378,10 @@ int ActiveParticleType_SmartStar::EvaluateFormation * is low we don't allow the SMS pathway to trigger spurious SF. */ int stellar_type = -99999; - if(shu_collapse == 1) - continue; - if(MultiSpecies == 0) { //no chemistry, testing use only + //if(shu_collapse == 1) + // continue; + if(ProblemType == 27) { //collapse test stellar_type = POPIII; - shu_collapse = 1; //prevents further formation } else if(HasMetalField && data.TotalMetals[index] > PopIIIMetalCriticalFraction) { stellar_type = POPII; @@ -429,7 +431,12 @@ int ActiveParticleType_SmartStar::EvaluateFormation np->vel[0] = apvel[0]; np->vel[1] = apvel[1]; np->vel[2] = apvel[2]; - + if(ProblemType == 27) { //special case of pure spherical collapse + np->vel[0] = cellvel[0]; /* alternatively this could be set to zero */ + np->vel[1] = cellvel[1]; /* but the velocity of the cell is more consistent */ + np->vel[2] = cellvel[2]; + } + if (HasMetalField) np->Metallicity = data.TotalMetals[index]; else @@ -880,15 +887,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle continue; FLOAT dx = APGrid->CellWidth[0][0]; - float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, - PressureUnits = 0, GEUnits = 0, VelUnits = 0; - double MassUnits = 1, CellVolume = dx*dx*dx; - if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, Time) == FAIL) { - ENZO_FAIL("Error in GetUnits."); - } - MassUnits = DensityUnits * POW(LengthUnits,3); + FLOAT CellVolume = dx*dx*dx; int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; if (APGrid->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, Vel3Num, TENum) == FAIL) @@ -922,7 +921,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle float *Temperature = new float[size](); APGrid->ComputeTemperatureField(Temperature); float CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : Temperature[cellindex]; - int JeansFactor = max(4, RefineByJeansLengthSafetyFactor/2); + int JeansFactor = JEANS_FACTOR; float JeansDensityUnitConversion = (Gamma*pi*kboltz) / (Mu*mh*GravConst); float JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / POW(LengthUnits*dx*JeansFactor,2); @@ -965,6 +964,10 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); ENZO_FAIL("Particle Density is negative. Oh dear.\n"); } +#if SSDEBUG + printf("%s: Particle with initial mass %e (%e) Msolar created\n", __FUNCTION__, + SS->Mass*dx*dx*dx*MassUnits/SolarMass, SS->Mass); +#endif continue; } } @@ -1618,7 +1621,7 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, SS->TimeIndex = timeindex; fprintf(stdout, "old_mass = %e Msolar\t cmass = (%e code) %e Msolar\n", omass*MassConversion, cmass, cmass*MassConversion); - fprintf(stdout, "accrate = %e Msolar/yr\t deltatime = %3.3f Myrs\t index = %d\t Particle Mass = %1.1f Msolar\t Age = %1.3f Myr\t Lifetime = %1.2f Myr\t Class = %d\n", + fprintf(stdout, "accrate = %1.2e Msolar/yr\t deltatime = %3.3f Myrs\t index = %d\t Particle Mass = %1.2e Msolar\t Age = %1.3f Myr\t Lifetime = %1.2f Myr\t Class = %d\n", (SS->AccretionRate[timeindex]*MassUnits/TimeUnits)*yr_s/SolarMass, deltatime*TimeUnits/Myr_s, SS->TimeIndex, diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 2c957ec04..1c950acca 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -241,11 +241,9 @@ void ActiveParticleType_SmartStar::MergeSmartStars( &TimeUnits, &VelocityUnits, Time); /* Construct list of sink particle positions to pass to Foflist */ FLOAT ParticleCoordinates[3*(*nParticles)]; + /* Particles merge once they come within 1 accretion radii of one another */ - fflush(stdout); - /* Particles merge once they come within 2 accretion radii of one another */ - - FLOAT MergingRadius = 2.0*LevelArray[ThisLevel]->GridData->GetCellWidth(0,0)*ACCRETIONRADIUS; + FLOAT MergingRadius = 1.5*(LevelArray[ThisLevel]->GridData->GetCellWidth(0,0))*ACCRETIONRADIUS; for (i=0; i<(*nParticles); i++) { tempPos = ParticleList[i]->ReturnPosition(); @@ -365,7 +363,6 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( /* Calculate CellWidth on maximum refinement level */ - // This assumes a cubic box and may not work for simulations with MinimumMassForRefinementLevelExponent FLOAT dx = (DomainRightEdge[0] - DomainLeftEdge[0]) / (MetaData->TopGridDims[0]*POW(FLOAT(RefineBy),FLOAT(MaximumRefinementLevel))); @@ -384,12 +381,11 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( nParticles--; } } - /* TEST THIS IS CORRECT*/ ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, ParticleList); - //if (AssignActiveParticlesToGrids(ParticleList, nParticles, - // LevelArray) == FAIL) - //return FAIL; + if (AssignActiveParticlesToGrids(ParticleList, nParticles, + LevelArray) == FAIL) + return FAIL; if (debug) printf("Number of particles before merging: %"ISYM"\n",nParticles); /* Do Merging */ From 521b54c9af509bd04d49945e09eb436c0e3d1b3a Mon Sep 17 00:00:00 2001 From: John Regan Date: Wed, 24 Mar 2021 16:51:18 +0000 Subject: [PATCH 086/115] Adding notes file for BB test --- .../notes.txt | 33 +++++++++++++++++++ .../sinkslices.py | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/notes.txt diff --git a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/notes.txt b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/notes.txt new file mode 100644 index 000000000..72e72142c --- /dev/null +++ b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/notes.txt @@ -0,0 +1,33 @@ +Burkert-Bodenheimer Test +#This is based off the initial conditions given in Fedderath et al. 2010. It shows the collapse of a +#rotating sphere. Particles should form in the bar at the centre. The test is not part of the test +#infrastrure because it is, at the moment, difficult to automate + + + +# To run the test +# There is a bit of a palaver to get this running as the mechanism for +# running enzo with the gravitational potential (GP) turned on is a little +# difficult - in particular I don't think there is a currently a way to get +# enzo to run with the GP calculation from the start. So here is how I do it: + +1. ./enzo.exe -d BBCollapseTestSmartStarParticle.enzo +2. This will die after a couple of seconds - that's ok +3. ./enzo.exe -d -g DD0000/DD0000 #this turns on the gravitational potential +4. mpirun -np X ./enzo.exe -d -r GravPotential/DD0000/DD0000 + +This will run relatively slowly i.e. tens of minutes on around 32 cores. This is another reason +why this is currently not part of the test infrastructure. With the current setup the first particles +should appears in output DD0133. + + +#Results +The test should form 2 particles initially at the ends of a bar that forms in the middle of the +collapsing sphere. Several particles will subsequently form along the bar as the bar fragments. + +#Plots +Plots can be made of the collapse using sinkslices.py + + + + diff --git a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py index ac9fad3eb..cc907157d 100644 --- a/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py +++ b/run/Hydro/Hydro-3D/BurkertBodenheimerActiveParticles/sinkslices.py @@ -13,7 +13,7 @@ #CENTRE = [0.50231934, 0.49035645, 0.49865723] AccretionRadius = 4 BASE = "./GravPotential/" -fns = glob.glob(BASE + "DD013?/DD????.hierarchy") +fns = glob.glob(BASE + "DD014?/DD????.hierarchy") fns.sort() #print fns WIDTH = 8000 From 693bd0e21cd4fa631e2f4270b0db1919fded8566 Mon Sep 17 00:00:00 2001 From: John Regan Date: Wed, 14 Apr 2021 12:33:51 +0000 Subject: [PATCH 087/115] Fixed minor bug in DetermineSEDParameters.C --- src/enzo/ActiveParticle_SmartStar.C | 11 ++++------- src/enzo/DetermineSEDParameters.C | 3 ++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index b48a26f9b..7b4ed622a 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -314,13 +314,13 @@ int ActiveParticleType_SmartStar::EvaluateFormation #if SSDEBUG printf("FAILURE: GravitationalMinimum = %g\t " \ "PotentialField[index] = %g\n\n", GravitationalMinimum, PotentialField[index]); - printf("%s: Cellwidth = %f\t JLength = %f\n", __FUNCTION__, dx, JLength); + printf("%s: Cellwidth = %e\t JLength = %e\n", __FUNCTION__, dx, JLength); printf("%s: search_radius (in cellwidths) = %f\n", __FUNCTION__, search_radius/dx); #endif continue; } #if SSDEBUG - printf("%s: Cellwidth = %f\t JLength = %f\n", __FUNCTION__, dx, JLength); + printf("%s: Cellwidth = %e\t JLength = %e\n", __FUNCTION__, dx, JLength); printf("%s: search_radius (in cellwidths) = %f\n", __FUNCTION__, search_radius/dx); fprintf(stdout, "%s: Gravitational Potential Passed!\n", __FUNCTION__); #endif @@ -758,7 +758,7 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel } -#if SSDEBUG +#if SSDEBUG_RT printf("%s: SS (%d) Energy Bins = %1.1f (%1.1f) %1.1f (%1.1f) %1.1f (%1.1f) " \ "%1.1f (%1.1f) %1.1f (%1.1f)\n", __FUNCTION__, ThisParticle->ParticleClass, ThisParticle->RadiationEnergyBins[0], @@ -1639,7 +1639,7 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, * if it is falling onto the main sequence. * This can also allow a POPIII star to change into a SMS */ - if((SS->AccretionRate[SS->TimeIndex]*MassUnits/TimeUnits)*yr_s/SolarMass + if((SS->AccretionRate[timeindex]*MassUnits/TimeUnits)*yr_s/SolarMass > CRITICAL_ACCRETION_RATE) { if(SS->ParticleClass == POPIII) { printf("%s: UPDATE: ParticleClass switching from POPIII to SMS\n", __FUNCTION__); @@ -1662,9 +1662,6 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, } } } -#if SSDEBUG - printf("Done in %s\n", __FUNCTION__); -#endif return SUCCESS; } diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index 72916abba..6843d1611 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -208,7 +208,8 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) double QTotal = 0; for (int bin = 0; bin < NUMRADIATIONBINS; bin++) QTotal += Q[bin]; - for (int bin = 0; bin < NUMRADIATIONBINS; bin++) Q[bin] /= QTotal; + if(QTotal > 0.0) + for (int bin = 0; bin < NUMRADIATIONBINS; bin++) Q[bin] /= QTotal; for (int bin = 0; bin < NUMRADIATIONBINS; bin++) { this->RadiationSED[bin] = float(Q[bin]); } From 35f3f7b6cf3d52e18d2d9fc57e0c66376e341c79 Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 7 May 2021 12:56:09 +0100 Subject: [PATCH 088/115] compilation update for Kay --- src/enzo/ActiveParticle_SmartStar.C | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index b48a26f9b..ef838ea34 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -9,7 +9,7 @@ #include "ActiveParticle_SmartStar.h" #include "phys_constants.h" -#define SSDEBUG 0 +#define SSDEBUG 1 #define SSDEBUG_TOTALMASS 0 #define DYNAMIC_ACCRETION_RADIUS 0 @@ -809,8 +809,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle ActiveParticleList& ParticleList, LevelHierarchyEntry *LevelArray[], int ThisLevel) { - - int SSparticles[nParticles] = {-1}; + int *SSparticles = new int(nParticles); float StellarMasstoRemove = 0.0, CellDensityAfterFormation = 0.0; /* Skip accretion if we're not on the maximum refinement level. This should only ever happen right after creation and then @@ -828,7 +827,8 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle MassUnits = DensityUnits * POW(LengthUnits,3); float tdyn_code = StarClusterMinDynamicalTime/(TimeUnits/yr_s); - + for (int i = 0; i < nParticles; i++) + SSparticles[i] = -1; /* * Order particles in order of SMS, PopIII, PopII * SMS first since they have the highest accretion rates and hence From a35c9d7c86117c5693e378f2280e768d1b029cc1 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 14 May 2021 12:02:37 -0500 Subject: [PATCH 089/115] reverted default metallicity to 1e-20 --- src/enzo/Grid_AddFields.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enzo/Grid_AddFields.C b/src/enzo/Grid_AddFields.C index fc7f89ab6..78195f000 100644 --- a/src/enzo/Grid_AddFields.C +++ b/src/enzo/Grid_AddFields.C @@ -47,7 +47,7 @@ int grid::AddFields(int TypesToAdd[], int NumberOfFields) // added conditional for using a metallicity floor with rad-hydro if (TypesToAdd[i] == Metallicity ){ - value = 6.475e-6; + value = 1e-20; for (j = 0; j < size; j++) BaryonField[n][j] = value * BaryonField[0][j]; } From 72e3bbff1034b644b0a8cc9f933161db9cc5964d Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 14 May 2021 12:02:59 -0500 Subject: [PATCH 090/115] Disabled continuing star formation on prior particles --- src/enzo/Grid_MechStarsFeedbackRoutine.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index cd38905f4..36a036471 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -225,7 +225,7 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta &freeFallTime, &dynamicalTime, ip, jp, kp, Time, BaryonField[NumberOfBaryonFields], CellWidth[0][0], &gridShouldFormStars, ¬EnoughMetals, 1, NULL); - if (createStar) + if (false) // AIW: disabled for testing. Adding mass here without the probabilistic factor in creation is leading to too many stars. i think. -_- { float MassShouldForm = min((shieldedFraction * BaryonField[DensNum][index] * MassUnits / (freeFallTime * TimeUnits) * this->dtFixed * Myr_s), 0.5 * BaryonField[DensNum][index] * MassUnits); From 03f016e11ac80cc971a8be368f5e577424e25ff6 Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 14 May 2021 12:03:43 -0500 Subject: [PATCH 091/115] failure on metals check; turned debug off; updated a couple prints --- src/enzo/MechStars_checkCreationCriteria.C | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C index df8c2e7cc..facd5773f 100644 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ b/src/enzo/MechStars_checkCreationCriteria.C @@ -35,7 +35,7 @@ int checkCreationCriteria(float* Density, float* Metals, { float Zsolar = 0.02; float maxZ = 0.0; - bool debug = true; + bool debug = false; bool status = PASS; float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; @@ -72,7 +72,9 @@ int checkCreationCriteria(float* Density, float* Metals, /* in addition to the converging flow check, we check the virial parameter of the gas to see if it is locally gravitationally bound*/ - + // check that metals exist in enough quantity + if (Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity) + return FAIL; float div = 0.0; //divergence float alpha = 0.0; //virial parameter @@ -155,17 +157,17 @@ int checkCreationCriteria(float* Density, float* Metals, float Psi = 0.6*Tau*(0.01+Metals[index]/Density[index]/Zsolar)/ log(1+0.6*Phi+0.01*Phi*Phi); *shieldedFraction = 1.0 - 3.0/(1.0+4.0*Psi); - if (debug) - fprintf(stdout, "FS parts: Tau = %"GSYM" Phi = %"GSYM" Psi = %"GSYM" FS = %"GSYM"\n", - Tau, Phi, Psi, *shieldedFraction); + // if (debug) + // fprintf(stdout, "FS parts: Tau = %"GSYM" Phi = %"GSYM" Psi = %"GSYM" FS = %"GSYM"\n", + // Tau, Phi, Psi, *shieldedFraction); if (*shieldedFraction < 0) status = FAIL; *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; // that theres code-time if (status && debug) { - fprintf(stdout, "Check Creation positive! n_b = %"GSYM" M_b = %"GSYM" gradRho = %"GSYM" Fs = %"FSYM" M_j = %"GSYM" VirialPar = %"FSYM" divergence = %"FSYM" Temperature = %"GSYM" cSnd = %"GSYM" AltJeans = %"GSYM" AltAlpha = %"GSYM"\n", - dmean, baryonMass, gradRho, *shieldedFraction, jeansMass, alpha, div, Temperature[index], cSound*VelocityUnits/1e5, altJeans); + fprintf(stdout, "Check Creation positive! n_b = %"GSYM" M_b = %"GSYM" gradRho = %"GSYM" Fs = %"FSYM" M_j = %"GSYM" VirialPar = %"FSYM" divergence = %"FSYM" Temperature = %"GSYM" cSnd = %"GSYM" AltJeans = %"GSYM" AltAlpha = %"GSYM" Z = %"GSYM"\n", + dmean, baryonMass, gradRho, *shieldedFraction, jeansMass, alpha, div, Temperature[index], cSound*VelocityUnits/1e5, altJeans, Metals[index]/Density[index]/0.02); } //if (status && debug) fprintf(stdout, "passed creation criteria\n"); if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity && !continuingFormation) From 4b431af53a1fa798e988b73024aaf731d121b0bc Mon Sep 17 00:00:00 2001 From: Azton Wells Date: Fri, 14 May 2021 12:03:55 -0500 Subject: [PATCH 092/115] removed prints --- src/enzo/MechStars_determineSN.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enzo/MechStars_determineSN.C b/src/enzo/MechStars_determineSN.C index a8fba3010..7b2074225 100644 --- a/src/enzo/MechStars_determineSN.C +++ b/src/enzo/MechStars_determineSN.C @@ -53,14 +53,14 @@ int determineSN(float age, int* nSNII, int* nSNIA, RII = 0.0; RIA = 5.2e-8+1.6e-5*exp(-1.0*pow((age-50.0)/10.0, 2)/2.0); } - fprintf(stdout, "Rates: For age %f Myr, RII = %f; RIA = %f\n", age, RII, RIA); + // fprintf(stdout, "Rates: For age %f Myr, RII = %f; RIA = %f\n", age, RII, RIA); /* rates -> probabilities */ if (RII > 0){ srand(seed); // printf("Zcpl = %e", zCouple); PII = RII * massMsun / Myr_s *TimeUnits*dt; - printf("PII =%f\n %f %e %f\n", PII, RII, massMsun, age); random = float(rand())/float(RAND_MAX); + // printf("PII =%f\n %f %e %f rnd = %e\n", PII, RII, massMsun, age, random); if (PII > 1.0 && UnrestrictedSN == TRUE){ int round = (int)PII; *nSNII = round; From fa4c573307ab3e32bac32eb8028a4e27946fa7f8 Mon Sep 17 00:00:00 2001 From: John Regan Date: Mon, 24 May 2021 16:11:11 +0100 Subject: [PATCH 093/115] merged with azton wells changes. Issues with compilations in different configurations --- src/enzo/ActiveParticle_SmartStar.C | 1 + src/enzo/Grid_MechStarsDepositFeedback.C | 16 ++++++++-------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 24 +++++++++++++++++------- src/enzo/Grid_MechStarsSeedSupernova.C | 4 ++-- src/enzo/Grid_StarParticleHandler.C | 6 +++++- src/enzo/Make.config.objects | 5 ----- 6 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 1c3596618..f88ad6d7a 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -1053,6 +1053,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle while (Temp != NULL) { /* Zero under subgrid field */ + /* JR: IS this necessary here? */ if (!MarkedSubgrids) { Temp->GridData-> diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C index 82bb410c1..7667af163 100644 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ b/src/enzo/Grid_MechStarsDepositFeedback.C @@ -15,11 +15,11 @@ #include "StarParticleData.h" #include "phys_constants.h" -extern "C" void FORTRAN_NAME(cic_deposit)(float *xPosition, float *yPosition, - float *zPosition, int *gridRank, int *nParticles, - float *DepositQuantity, float *FieldToDepositTo, - float *leftEdge, int *xGridDim, int *yGridDim, - int *zGridDim, float *gridDx, float *cloudsize); +extern "C" void FORTRAN_NAME(cic_deposit)(FLOAT *xPosition, FLOAT *yPosition, + FLOAT *zPosition, int *gridRank, int *nParticles, + FLOAT *DepositQuantity, float *FieldToDepositTo, + FLOAT *leftEdge, int *xGridDim, int *yGridDim, + int *zGridDim, FLOAT *gridDx, FLOAT *cloudsize); int GetUnits(float *DensityUnits, float *LengthUnits, float *TemperatureUnits, float *TimeUnits, float *VelocityUnits, float *MassUnits, float Time); @@ -470,7 +470,7 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, FLOAT LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; FLOAT pX, pY, pZ; - float eCouple, geCouple, mCouple, zCouple, zIICouple, zIACouple, p3Couple; + FLOAT eCouple, geCouple, mCouple, zCouple, zIICouple, zIACouple, p3Couple; /* As a computational compromize, supernova are deposited CIC, but winds are deposited NGP. At VERY high resolution, well still do CIC for winds @@ -562,11 +562,11 @@ int grid::MechStars_DepositFeedback(float ejectaEnergy, int np = 1; shellMass *= -1 / MassUnits; FORTRAN_NAME(cic_deposit) - (xp, yp, zp, &GridRank, &np, &shellMass, density, LeftEdge, + ((FLOAT *)xp, (FLOAT *)yp, (FLOAT *)zp, &GridRank, &np, (FLOAT *)&shellMass, density, LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); shellMetals *= -1 / MassUnits; FORTRAN_NAME(cic_deposit) - (xp, yp, zp, &GridRank, &np, &shellMetals, metals, LeftEdge, + ((FLOAT *)xp, (FLOAT *)yp, (FLOAT *)zp, &GridRank, &np, (FLOAT *)&shellMetals, metals, LeftEdge, &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); /* diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C index 36a036471..0158d61f9 100644 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ b/src/enzo/Grid_MechStarsFeedbackRoutine.C @@ -300,10 +300,15 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta SNMassEjected = nSNII*10.5 + nSNIA * 1.5; float starMetal = (ParticleAttribute[2][pIndex] / Zsolar); //determines metal content of SNeII - MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, Temperature, - &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], - &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], - ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, starMetal, 0); + MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, + Temperature, &ParticleVelocity[0][pIndex], + &ParticleVelocity[1][pIndex], + &ParticleVelocity[2][pIndex], + (float *)&ParticlePosition[0][pIndex], + (float *)&ParticlePosition[1][pIndex], + (float *)&ParticlePosition[2][pIndex], + ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, + starMetal, 0); // can only track number of events in dynamical time if not using it to determine lifetime @@ -332,9 +337,14 @@ int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMeta if (windEnergy > 1e5) { //printf("Winds: M = %e E=%e\n", windMass, windEnergy); - MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, Temperature, - &ParticleVelocity[0][pIndex], &ParticleVelocity[1][pIndex], &ParticleVelocity[2][pIndex], - &ParticlePosition[0][pIndex], &ParticlePosition[1][pIndex], &ParticlePosition[2][pIndex], + MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, + Temperature, + &ParticleVelocity[0][pIndex], + &ParticleVelocity[1][pIndex], + &ParticleVelocity[2][pIndex], + (float *) &ParticlePosition[0][pIndex], + (float *) &ParticlePosition[1][pIndex], + (float *) &ParticlePosition[2][pIndex], ip, jp, kp, size, mu_field, 1, 0, 0, 0.0, 0); } } diff --git a/src/enzo/Grid_MechStarsSeedSupernova.C b/src/enzo/Grid_MechStarsSeedSupernova.C index 2e038e8af..d4ca445e5 100644 --- a/src/enzo/Grid_MechStarsSeedSupernova.C +++ b/src/enzo/Grid_MechStarsSeedSupernova.C @@ -30,7 +30,7 @@ extern "C" void FORTRAN_NAME(cic_deposit)(float* xPosition, float* yPosition, float* zPosition, int* gridRank, int* nParticles, float* DepositQuantity, float* FieldToDepositTo, float* leftEdge, int* xGridDim, int* yGridDim, - int* zGridDim, float* gridDx, float* cloudsize); + int* zGridDim, FLOAT* gridDx, float* cloudsize); int search_lower_bound(float *arr, float value, int low, int high, int total); unsigned_long_int mt_random(void); @@ -206,4 +206,4 @@ int grid::MechStars_SeedSupernova(float* totalMetal, float* temperature, int* se ip, jp, kp, size, mu_field, 0, 0, 0, 0, 1); return SUCCESS; -} \ No newline at end of file +} diff --git a/src/enzo/Grid_StarParticleHandler.C b/src/enzo/Grid_StarParticleHandler.C index 5e508dafc..00550b7ca 100644 --- a/src/enzo/Grid_StarParticleHandler.C +++ b/src/enzo/Grid_StarParticleHandler.C @@ -831,7 +831,8 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, for (i = NumberOfNewParticlesSoFar; i < NumberOfNewParticles; i++) tg->ParticleType[i] = NormalStarType; - } + } +#ifdef DONOTCOMPILE if (STARMAKE_METHOD(MECHANICAL) && level >= StarMakeLevel){ NumberOfNewParticlesSoFar = NumberOfParticles; int nRetStars = 0; @@ -846,6 +847,7 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, } } +#endif if (STARMAKE_METHOD(MOM_STAR)) { //---- UNIGRID ALGORITHM (NO JEANS MASS) @@ -1602,7 +1604,9 @@ int grid::StarParticleHandler(HierarchyEntry* SubgridPointer, int level, float *cooling_time = new float[size]; this->ComputeCoolingTime(cooling_time); //fprintf(stdout, "CALLING MECH FEEDBACK\n"); +#ifdef DONOTCOMPILE MechStars_FeedbackRoutine(level, &mu_field[0], temperature, MetalPointer, cooling_time, dmfield); +#endif delete [] cooling_time; } if (STARFEED_METHOD(MOM_STAR)) { diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index d0b0f0e0e..ff4a51b5b 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -551,10 +551,6 @@ OBJS_CONFIG_LIB = \ Grid_KHInitializeGrid.o \ Grid_KHInitializeGridRamp.o \ Grid_MagneticFieldResetter.o \ - Grid_MechStarsCreation.o\ - Grid_MechStarsDepositFeedback.o\ - Grid_MechStarsFeedbackRoutine.o\ - Grid_MechStarsSeedSupernova.o\ Grid_MirrorStarParticles.o \ Grid_MoveAllParticles.o \ Grid_MoveAllStars.o \ @@ -743,7 +739,6 @@ OBJS_CONFIG_LIB = \ mbh_maker.o \ mcooling.o \ MakeFieldConservative.o\ - MechStars_checkCreationCriteria.o\ MechStars_determineSN.o\ MechStars_determineWinds.o\ MechStars_transformComovingWithStar.o\ From c0b791032d6c3438aa643cd82ff05d911b36e1fc Mon Sep 17 00:00:00 2001 From: John Regan Date: Wed, 26 May 2021 16:33:08 +0100 Subject: [PATCH 094/115] potential bug in deleting particles in RemoveMassFromGrid. Not able to reproduce easily (without serious hacking) so currently unclear --- src/enzo/ActiveParticle_SmartStar.C | 51 +++++++++-------------------- src/enzo/ActiveParticle_SmartStar.h | 25 +++++--------- 2 files changed, 23 insertions(+), 53 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index f88ad6d7a..13be49ab3 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -1014,9 +1014,11 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); /* Mark particle for deletion */ SS->WillDelete = true; - ParticleList[pindex]->DisableParticle(LevelArray, MyProcessorNumber); - printf("Too late. Star is destroyed by surrounding SF. Particle %d deleted.\n", pindex); - + //ParticleList[pindex]->DisableParticle(LevelArray, MyProcessorNumber); + //ParticleList.erase(pindex); + + printf("P%d: Too late. Star is destroyed by surrounding SF. Particle %d deleted\n", + MyProcessorNumber, pindex); continue; } FLOAT Radius = 0.0; @@ -1044,41 +1046,18 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle for (int dim = 0; dim < MAX_DIMENSION; dim++) ShellVelocity[dim] = 0.0; - bool MarkedSubgrids = false; LevelHierarchyEntry *Temp = NULL; - HierarchyEntry *Temp2 = NULL; - - for (int l = ThisLevel; l < MAX_DEPTH_OF_HIERARCHY; l++) { - Temp = LevelArray[l]; - while (Temp != NULL) { - - /* Zero under subgrid field */ - /* JR: IS this necessary here? */ - - if (!MarkedSubgrids) { - Temp->GridData-> - ZeroSolutionUnderSubgrid(NULL, ZERO_UNDER_SUBGRID_FIELD); - Temp2 = Temp->GridHierarchyEntry->NextGridNextLevel; - while (Temp2 != NULL) { - Temp->GridData->ZeroSolutionUnderSubgrid(Temp2->GridData, - ZERO_UNDER_SUBGRID_FIELD); - Temp2 = Temp2->NextGridThisLevel; - } - } // ENDIF !MarkedSubgrids - /* Sum enclosed mass in this grid. Mass is in Msolar*/ - - Temp->GridData->GetEnclosedMassInShell(SS->pos, Radius-APGrid->CellWidth[0][0], Radius, - ShellMass, ShellMetallicity2, - ShellMetallicity3, - ShellColdGasMass, ShellVelocity, - -1); - - Temp = Temp->NextGridThisLevel; - - } // END: Grids + Temp = LevelArray[ThisLevel]; + while (Temp != NULL) { + Temp->GridData->GetEnclosedMassInShell(SS->pos, Radius-APGrid->CellWidth[0][0], Radius, + ShellMass, ShellMetallicity2, + ShellMetallicity3, + ShellColdGasMass, ShellVelocity, + -1); - } // END: level - MarkedSubgrids = true; + Temp = Temp->NextGridThisLevel; + } // END: Grids + MassEnclosed += ShellMass; ColdGasMass += ShellColdGasMass; // Must first make mass-weighted, then add shell mass-weighted diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 1c950acca..ce9130d7b 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -360,32 +360,23 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( if (nParticles == 0) return SUCCESS; - + /* Calculate CellWidth on maximum refinement level */ - FLOAT dx = (DomainRightEdge[0] - DomainLeftEdge[0]) / (MetaData->TopGridDims[0]*POW(FLOAT(RefineBy),FLOAT(MaximumRefinementLevel))); /* Remove mass from grid from newly formed particles */ RemoveMassFromGridAfterFormation(nParticles, ParticleList, LevelArray, ThisLevel); - - /* Clean any particles marked for deletion */ - for (i = 0; iShouldDelete() == true) { - printf("%s: Delete SS %d following RemoveMassFromGridAfterFormation\n", __FUNCTION__, - static_cast(ParticleList[i])->ReturnID()); - fflush(stdout); - ParticleList.erase(i); - i = -1; - nParticles--; - } - } - ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, - ParticleList); + //ParticleList.delete_marked_particles(); + + /* Regenerate the global list following deletions. */ + //ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, + // ParticleList); if (AssignActiveParticlesToGrids(ParticleList, nParticles, LevelArray) == FAIL) return FAIL; + if (debug) printf("Number of particles before merging: %"ISYM"\n",nParticles); /* Do Merging */ @@ -466,7 +457,7 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( */ for (i = 0; iShouldDelete() == true) { - printf("%s: Delete SS %d following Feedback\n", __FUNCTION__, + printf("%s: Delete SS %d\n", __FUNCTION__, static_cast(ParticleList[i])->ReturnID()); fflush(stdout); ParticleList.erase(i); From e0c7f024ab7e9290a5ebcdb57163dee316d9b078 Mon Sep 17 00:00:00 2001 From: John Regan Date: Tue, 22 Jun 2021 13:56:41 +0100 Subject: [PATCH 095/115] manually added a commit from JHW to fix MPI errors --- src/enzo/CommunicationCollectParticles.C | 1 + src/enzo/CommunicationReceiveHandler.C | 72 ++++++++++++++----- src/enzo/CommunicationShareGrids.C | 8 +++ src/enzo/CommunicationSyncNumberOfParticles.C | 2 +- .../CommunicationTransferActiveParticles.C | 2 +- src/enzo/CommunicationTransferParticlesOpt.C | 2 +- src/enzo/CommunicationTransferStarsOpt.C | 2 +- src/enzo/CommunicationTranspose.C | 16 +++-- src/enzo/DepositParticleMassFlaggingField.C | 10 --- src/enzo/EnzoTiming.h | 2 +- src/enzo/ErrorExceptions.h | 2 +- src/enzo/ExternalBoundary.h | 16 +++++ src/enzo/Grid_CollectActiveParticles.C | 14 ++-- .../Grid_CommunicationSendActiveParticles.C | 2 +- src/enzo/Grid_DeleteAllFields.C | 3 +- src/enzo/Grid_DepositMustRefineParticles.C | 3 +- src/enzo/Grid_SetParticleMassFlaggingField.C | 28 ++------ .../Grid_TransferSubgridActiveParticles.C | 35 ++++----- src/enzo/Grid_TransferSubgridStars.C | 16 ++--- src/enzo/OutputFromEvolveLevel.C | 21 +++++- src/enzo/RadiativeTransferReadParameters.C | 1 + src/enzo/RebuildHierarchy.C | 4 +- src/enzo/enzo.C | 21 +++++- 23 files changed, 179 insertions(+), 104 deletions(-) diff --git a/src/enzo/CommunicationCollectParticles.C b/src/enzo/CommunicationCollectParticles.C index 4f262a1fd..eca292e8e 100644 --- a/src/enzo/CommunicationCollectParticles.C +++ b/src/enzo/CommunicationCollectParticles.C @@ -215,6 +215,7 @@ int CommunicationCollectParticles(LevelHierarchyEntry *LevelArray[], TotalNumber = 0; TotalStars = 0; + APTotalNumber = 0; for (j = 0; j < NumberOfProcessors; j++) { TotalNumber += NumberToMove[j]; TotalStars += StarsToMove[j]; diff --git a/src/enzo/CommunicationReceiveHandler.C b/src/enzo/CommunicationReceiveHandler.C index d3323e745..302d14652 100644 --- a/src/enzo/CommunicationReceiveHandler.C +++ b/src/enzo/CommunicationReceiveHandler.C @@ -13,6 +13,8 @@ / ************************************************************************/ +#define NO_DEBUG_MPI + #ifdef USE_MPI #include "mpi.h" #endif /* USE_MPI */ @@ -32,6 +34,7 @@ #ifdef USE_MPI static MPI_Arg ListOfIndices[MAX_RECEIVE_BUFFERS]; static MPI_Status ListOfStatuses[MAX_RECEIVE_BUFFERS]; +void CommunicationErrorHandlerFn(MPI_Comm *comm, MPI_Arg *err, ...); #endif /* USE_MPI */ double ReturnWallTime(void); @@ -91,26 +94,59 @@ int CommunicationReceiveHandler(fluxes **SubgridFluxesEstimate[], ENZO_FAIL("Error in MPI_Waitsome\n"); } #endif - + MPI_Arg bsize; /* Should loop over newly received completions and check error msgs now. */ - for (index = 0; index < NumberOfCompleteRequests; index++) - if (ListOfStatuses[index].MPI_ERROR != 0) { - if (NoErrorSoFar) { - fprintf(stderr, "MPI Error on processor %"ISYM". " - "Error number %"ISYM" on request %"ISYM"\n", - MyProcessorNumber, ListOfStatuses[index].MPI_ERROR, index); - NoErrorSoFar = FALSE; - } - fprintf(stdout, "P(%"ISYM") index %"ISYM" -- mpi error %"ISYM"\n", - MyProcessorNumber, index, ListOfStatuses[index].MPI_ERROR); - fprintf(stdout, "%"ISYM": Type = %"ISYM", Grid1 = %x, Request = %"ISYM", " - "DependsOn = %"ISYM"\n", index, - CommunicationReceiveCallType[index], - CommunicationReceiveGridOne[index], - CommunicationReceiveMPI_Request[index], - CommunicationReceiveDependsOn[index]); - } + for (index = 0; index < NumberOfCompleteRequests; index++) { +#ifdef DEBUG_MPI + MPI_Get_count(ListOfStatuses+index, MPI_CHAR, &bsize); + fprintf(stderr, "P%"ISYM": MPI_Irecv[%d/%d] -- " + "Error number %d from processor %d with tag %d" + " on request %d (MPI_REQUEST_NULL = %d) with %d bytes\n", + MyProcessorNumber, index, NumberOfCompleteRequests, + ListOfStatuses[index].MPI_ERROR, + ListOfStatuses[index].MPI_SOURCE, + ListOfStatuses[index].MPI_TAG, + ListOfIndices[index], + (CommunicationReceiveMPI_Request[index] == MPI_REQUEST_NULL), + bsize); +#endif /* DEBUG_MPI */ + + if (ListOfStatuses[index].MPI_ERROR != 0) { + if (NoErrorSoFar) { + MPI_Get_count(ListOfStatuses+index, MPI_CHAR, &bsize); + fprintf(stderr, "MPI Error on processor %"ISYM". " + "Error number %d from processor %d with tag %d" + " on request %"ISYM" (MPI_REQUEST_NULL = %d) with %d bytes\n", + MyProcessorNumber, ListOfStatuses[index].MPI_ERROR, + ListOfStatuses[index].MPI_SOURCE, ListOfStatuses[index].MPI_TAG, + index, + (CommunicationReceiveMPI_Request[index] == MPI_REQUEST_NULL), + bsize); + NoErrorSoFar = FALSE; + } + int _id = -1; + if (CommunicationReceiveGridOne[index] != NULL) + _id = CommunicationReceiveGridOne[index]->GetGridID(); + fprintf(stderr, "P(%"ISYM") index %"ISYM" -- mpi error %"ISYM"\n", + MyProcessorNumber, index, ListOfStatuses[index].MPI_ERROR); + fprintf(stderr, "%"ISYM": Type = %"ISYM", Grid1 = %x (G%"ISYM"), " + "Request = %x (%"ISYM"), " + "Arg0/Arg1/Arg2 = %"ISYM"/%"ISYM"/%"ISYM", DependsOn = %"ISYM"\n", + index, + CommunicationReceiveCallType[index], + CommunicationReceiveGridOne[index], _id, + CommunicationReceiveMPI_Request[index], + MPI_REQUEST_NULL, + CommunicationReceiveArgumentInt[0][index], + CommunicationReceiveArgumentInt[1][index], + CommunicationReceiveArgumentInt[2][index], + CommunicationReceiveDependsOn[index]); + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Arg errcode = ListOfStatuses[index].MPI_ERROR; + CommunicationErrorHandlerFn(&comm, &errcode); + } // ENDIF error + } // ENDFOR requests /* Here we loop over the handles looking only for the ones for grid::CommunicationSendActiveParticles, and count how many there are, and how many are finished receiving. If all are, we can go ahead diff --git a/src/enzo/CommunicationShareGrids.C b/src/enzo/CommunicationShareGrids.C index e61c82732..81fbdbd70 100644 --- a/src/enzo/CommunicationShareGrids.C +++ b/src/enzo/CommunicationShareGrids.C @@ -53,6 +53,7 @@ int CommunicationShareGrids(HierarchyEntry *GridHierarchyPointer[], FLOAT RightEdge[MAX_DIMENSION]; int NumberOfParticles; int NumberOfStars; + int NumberOfActiveParticles; int ParentNumber; }; int i; @@ -90,9 +91,12 @@ int CommunicationShareGrids(HierarchyEntry *GridHierarchyPointer[], Temp->GridData->ReturnNumberOfParticles(); SendList[Counter].NumberOfStars = Temp->GridData->ReturnNumberOfStars(); + SendList[Counter].NumberOfActiveParticles = + Temp->GridData->ReturnNumberOfActiveParticles(); } else { SendList[Counter].NumberOfParticles = 0; SendList[Counter].NumberOfStars = 0; + SendList[Counter].NumberOfActiveParticles = 0; } SendList[Counter++].ParentNumber = i; Temp = Temp->NextGridThisLevel; @@ -221,6 +225,7 @@ int CommunicationShareGrids(HierarchyEntry *GridHierarchyPointer[], if (ShareParticles == TRUE) { ThisGrid->GridData->SetNumberOfParticles(SharedList[i].NumberOfParticles); ThisGrid->GridData->SetNumberOfStars(SharedList[i].NumberOfStars); + ThisGrid->GridData->SetNumberOfActiveParticles(SharedList[i].NumberOfActiveParticles); } if (SubgridParent != NULL && ShareParticles == TRUE) { @@ -231,6 +236,9 @@ int CommunicationShareGrids(HierarchyEntry *GridHierarchyPointer[], SubgridParent->GridData->SetNumberOfStars (SubgridParent->GridData->ReturnNumberOfStars() - SharedList[i].NumberOfStars); + SubgridParent->GridData->SetNumberOfActiveParticles + (SubgridParent->GridData->ReturnNumberOfActiveParticles() - + SharedList[i].NumberOfActiveParticles); } // ENDIF parent exists and sharing particles/stars diff --git a/src/enzo/CommunicationSyncNumberOfParticles.C b/src/enzo/CommunicationSyncNumberOfParticles.C index 25cf82c62..d24452cc3 100644 --- a/src/enzo/CommunicationSyncNumberOfParticles.C +++ b/src/enzo/CommunicationSyncNumberOfParticles.C @@ -49,7 +49,7 @@ int CommunicationSyncNumberOfParticles(HierarchyEntry *GridHierarchyPointer[], buffer[idx+3+j] = GridHierarchyPointer[i]->GridData-> ReturnNumberOfActiveParticlesOfThisType(j); } else { - buffer[idx+3+j] = 0.; + buffer[idx+3+j] = 0; } } } else { diff --git a/src/enzo/CommunicationTransferActiveParticles.C b/src/enzo/CommunicationTransferActiveParticles.C index 69133556f..940b4e942 100644 --- a/src/enzo/CommunicationTransferActiveParticles.C +++ b/src/enzo/CommunicationTransferActiveParticles.C @@ -92,7 +92,7 @@ int CommunicationTransferActiveParticles for (i = 0; i < Layout[dim]; i++) { ExactCount += ExactDims; - if (dim == 0) + if (i < Layout[dim]-1) ThisCount = nint(0.5*ExactCount)*2 - DisplacementCount; else ThisCount = nint(ExactCount) - DisplacementCount; diff --git a/src/enzo/CommunicationTransferParticlesOpt.C b/src/enzo/CommunicationTransferParticlesOpt.C index 65113f049..8e0dc77d4 100644 --- a/src/enzo/CommunicationTransferParticlesOpt.C +++ b/src/enzo/CommunicationTransferParticlesOpt.C @@ -96,7 +96,7 @@ int CommunicationTransferParticles(grid *GridPointer[], int NumberOfGrids, for (i = 0; i < Layout[dim]; i++) { ExactCount += ExactDims; - if (dim == 0) + if (i < Layout[dim]-1) ThisCount = nint(0.5*ExactCount)*2 - DisplacementCount; else ThisCount = nint(ExactCount) - DisplacementCount; diff --git a/src/enzo/CommunicationTransferStarsOpt.C b/src/enzo/CommunicationTransferStarsOpt.C index b354acc04..eaa983115 100644 --- a/src/enzo/CommunicationTransferStarsOpt.C +++ b/src/enzo/CommunicationTransferStarsOpt.C @@ -94,7 +94,7 @@ int CommunicationTransferStars(grid *GridPointer[], int NumberOfGrids, for (i = 0; i < Layout[dim]; i++) { ExactCount += ExactDims; - if (dim == 0) + if (i < Layout[dim]-1) ThisCount = nint(0.5*ExactCount)*2 - DisplacementCount; else ThisCount = nint(ExactCount) - DisplacementCount; diff --git a/src/enzo/CommunicationTranspose.C b/src/enzo/CommunicationTranspose.C index b2faaf8a5..99f1787d3 100644 --- a/src/enzo/CommunicationTranspose.C +++ b/src/enzo/CommunicationTranspose.C @@ -1020,6 +1020,7 @@ int NonBlockingCommunicationTranspose(region *FromRegion, int NumberOfFromRegion processing receives this cycle. */ MPI_Arg TotalCompletedRequests, CompletedRequests; + bool ProcessRequest; if (ReceiveMode) { TotalCompletedRequests = 0; @@ -1048,11 +1049,16 @@ int NonBlockingCommunicationTranspose(region *FromRegion, int NumberOfFromRegion /* First cycle only has one call. Break if we've already processed the first call, otherwise always process it. */ - if (n == 0 && request > 0) break; - if ((RequestHandle[request] == MPI_REQUEST_NULL && - ReceiveBuffer[request] != NULL) || - (n == 0 && request == 0)) { - + if (n == 0) { + if (request == 0) + ProcessRequest = true; + else + break; + } else { + ProcessRequest = (RequestHandle[request] == MPI_REQUEST_NULL) && + (ReceiveBuffer[request] != NULL); + } + if (ProcessRequest) { #ifdef DEBUG_NONBLOCKCT fprintf(stderr, "CT(%"ISYM"): request = %d, receives = %"ISYM"\n", MyProcessorNumber, request, receives); diff --git a/src/enzo/DepositParticleMassFlaggingField.C b/src/enzo/DepositParticleMassFlaggingField.C index 9f8c284bb..b6fbc9242 100644 --- a/src/enzo/DepositParticleMassFlaggingField.C +++ b/src/enzo/DepositParticleMassFlaggingField.C @@ -190,10 +190,6 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], MPI_SendListCount[proc] = NumberOfSends[proc]; } -// for (i = 0; i < TotalNumberOfSends; i++) -// printf("P%"ISYM" -- BB -- SendList[%"ISYM"]: %"ISYM" %"ISYM"\n", -// MyProcessorNumber, i, SendList[i].grid, SendList[i].proc); - // Sort by grid (destination) processor, then replace the // processor number with this processor number because the grid // processor needs it to post the receives. @@ -245,9 +241,6 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], for (i = 0; i < TotalNumberOfSends; i++) SendList[i].proc = MyProcessorNumber; -// for (i = 0; i < TotalNumberOfSends; i++) -// printf("P%"ISYM" -- SendList[%"ISYM"]: %"ISYM" %"ISYM"\n", -// MyProcessorNumber, i, SendList[i].grid, SendList[i].proc); #ifdef TIMING t0 = ReturnWallTime(); @@ -264,9 +257,6 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], printf("--> DPMFF: After Alltoallv :: %lg seconds\n", t1-t0); #endif -// for (i = 0; i < TotalNumberOfRecv; i++) -// printf("P%"ISYM" -- SharedList[%"ISYM"]: %"ISYM" %"ISYM"\n", -// MyProcessorNumber, i, SharedList[i].grid, SharedList[i].proc); delete [] NumberOfSends; delete [] MPI_SendListCount; diff --git a/src/enzo/EnzoTiming.h b/src/enzo/EnzoTiming.h index 6d7772d58..b891f7be4 100644 --- a/src/enzo/EnzoTiming.h +++ b/src/enzo/EnzoTiming.h @@ -158,7 +158,7 @@ namespace enzo_timing{ // Destructor, erases each timer. ~enzo_timer(void){ for( SectionMap::iterator iter=timers.begin(); iter!=timers.end(); ++iter){ - delete [] iter->second; + delete iter->second; timers.erase(iter); } timers.clear(); diff --git a/src/enzo/ErrorExceptions.h b/src/enzo/ErrorExceptions.h index 7df93dc33..05c8333c5 100644 --- a/src/enzo/ErrorExceptions.h +++ b/src/enzo/ErrorExceptions.h @@ -57,7 +57,7 @@ extern char current_error[255]; fprintf(stderr, "BT symbol: %s\n", symbols[i]); } - delete [] symbols; + delete symbols; } void WriteDebuggingOutput() { diff --git a/src/enzo/ExternalBoundary.h b/src/enzo/ExternalBoundary.h index 5c0257fd0..fa605b03b 100644 --- a/src/enzo/ExternalBoundary.h +++ b/src/enzo/ExternalBoundary.h @@ -48,6 +48,22 @@ class ExternalBoundary // Constructor (set rank and dims from TopGrid) // ExternalBoundary(); + + // + // Destructor + // + void CleanUp (void) { + for (int field = 0; field < MAX_NUMBER_OF_BARYON_FIELDS; field++) { + for (int dim = 0; dim < MAX_DIMENSION; dim++) { + for (int i = 0; i < 2; i++) { + if (BoundaryType[field][dim][i] != NULL) + delete [] BoundaryType[field][dim][i]; + if (BoundaryValue[field][dim][i] != NULL) + delete [] BoundaryValue[field][dim][i]; + } + } + } + } // // Prepare External Boundary (set dims, etc.) based on TopGrid in argument. // diff --git a/src/enzo/Grid_CollectActiveParticles.C b/src/enzo/Grid_CollectActiveParticles.C index 4f72df40d..2a3e7e66d 100644 --- a/src/enzo/Grid_CollectActiveParticles.C +++ b/src/enzo/Grid_CollectActiveParticles.C @@ -34,11 +34,11 @@ int grid::CollectActiveParticles(int GridNum, int* &NumberToMove, int i, j, dim, n1, grid, proc; /* ----------------------------------------------------------------- */ - /* Copy star out of grid. */ + /* Copy active particle out of grid. */ if (CopyDirection == COPY_OUT) { - /* If there are no stars to move, we're done. */ + /* If there are no active particles to move, we're done. */ if (NumberOfActiveParticles == 0) return SUCCESS; @@ -48,18 +48,18 @@ int grid::CollectActiveParticles(int GridNum, int* &NumberToMove, if (MyProcessorNumber == ProcessorNumber) return SUCCESS; - /* Add to the star count to move */ + /* Add to the active particle count to move */ - // NumberOfActiveParticles is still the number of local stars, not the + // NumberOfActiveParticles is still the number of local aps, not the // actual total! NumberToMove[ProcessorNumber] += NumberOfActiveParticles; - /* Move and delete stars */ + /* Move and delete active particles */ for (i = 0, n1 = StartIndex; i < NumberOfActiveParticles; i++, n1++) { List.copy_and_insert(*ActiveParticles[i]); List[n1]->SetGridID(GridNum); - } // ENDFOR stars + } // ENDFOR active particles StartIndex = n1; this->DeleteActiveParticles(); @@ -67,7 +67,7 @@ int grid::CollectActiveParticles(int GridNum, int* &NumberToMove, } // end: if (COPY_OUT) /* ----------------------------------------------------------------- */ - /* Copy stars back into grid. */ + /* Copy active particles back into grid. */ else { diff --git a/src/enzo/Grid_CommunicationSendActiveParticles.C b/src/enzo/Grid_CommunicationSendActiveParticles.C index 97e261f9f..a4a160fd2 100644 --- a/src/enzo/Grid_CommunicationSendActiveParticles.C +++ b/src/enzo/Grid_CommunicationSendActiveParticles.C @@ -117,7 +117,7 @@ int grid::CommunicationSendActiveParticles( Count = EnabledActiveParticlesCount; Source = ProcessorNumber; Dest = ToProcessor; - + // send if ((MyProcessorNumber == ProcessorNumber) && ((CommunicationDirection == COMMUNICATION_SEND_RECEIVE) || diff --git a/src/enzo/Grid_DeleteAllFields.C b/src/enzo/Grid_DeleteAllFields.C index 8441aaaea..d32678d08 100644 --- a/src/enzo/Grid_DeleteAllFields.C +++ b/src/enzo/Grid_DeleteAllFields.C @@ -30,7 +30,8 @@ void grid::DeleteAllFields() int i; this->DeleteParticles(); - + this->DeleteActiveParticles(); + for (i = 0; i < MAX_DIMENSION; i++) { delete [] ParticleAcceleration[i]; delete [] AccelerationField[i]; diff --git a/src/enzo/Grid_DepositMustRefineParticles.C b/src/enzo/Grid_DepositMustRefineParticles.C index 33c4d2c23..92870850d 100644 --- a/src/enzo/Grid_DepositMustRefineParticles.C +++ b/src/enzo/Grid_DepositMustRefineParticles.C @@ -92,10 +92,9 @@ int grid::DepositMustRefineParticles(int pmethod, int level, bool KeepFlaggingFi rules = new bool[NumberOfRules]; // Rules to prevent refinement, cancelling out the above rules. - bool *antirules; + bool *antirules = NULL; int *AntiFlaggingField; int NumberOfAntiRules = 0; - antirules = new bool[NumberOfAntiRules]; // Add an antirule to unflag over-refined dark matter particles. if (MustRefineParticlesCreateParticles == 4) { diff --git a/src/enzo/Grid_SetParticleMassFlaggingField.C b/src/enzo/Grid_SetParticleMassFlaggingField.C index c61186c0e..481ee3194 100644 --- a/src/enzo/Grid_SetParticleMassFlaggingField.C +++ b/src/enzo/Grid_SetParticleMassFlaggingField.C @@ -48,24 +48,14 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, /* Return if we're not needed here */ -// if (MyProcessorNumber == ProcessorNumber && -// CommunicationDirection == COMMUNICATION_SEND) -// return SUCCESS; - - //printf(" grid::SetParticleMassFlaggingField \n"); - if (MyProcessorNumber != ProcessorNumber && (CommunicationDirection == COMMUNICATION_RECEIVE || CommunicationDirection == COMMUNICATION_POST_RECEIVE)) return SUCCESS; -// printf("--> SetPMFlag[P%"ISYM"/%"ISYM"]: level %"ISYM", grid %"ISYM", " -// "comm_dir = %"ISYM", npart = %"ISYM"\n", -// MyProcessorNumber, ProcessorNumber, level, GridNum, -// CommunicationDirection, NumberOfParticles); #ifdef USE_MPI - MPI_Datatype DataType = (sizeof(float) == 4) ? MPI_FLOAT : MPI_DOUBLE; + MPI_Datatype DataType = FloatDataType; MPI_Arg Count; MPI_Arg Source; float *buffer = NULL; @@ -94,7 +84,7 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, // given range and has particles. if (MyProcessorNumber != ProcessorNumber && (MyProcessorNumber < StartProc || MyProcessorNumber >= EndProc || - NumberOfParticles == 0 && NumberOfActiveParticles == 0)) + (NumberOfParticles == 0 && NumberOfActiveParticles == 0))) return SUCCESS; /***********************************************************************/ @@ -160,11 +150,9 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, #ifdef USE_MPI if (MyProcessorNumber != ProcessorNumber) { - //MPI_Tag = Return_MPI_Tag(GridNum, MyProcessorNumber); -// printf("----> SetPMFlag[P%"ISYM"/%"ISYM"]: sending %"ISYM" floats.\n", -// MyProcessorNumber, ProcessorNumber, size); + MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); CommunicationBufferedSend(ParticleMassFlaggingField, size, DataType, - ProcessorNumber, MPI_SENDPMFLAG_TAG, + ProcessorNumber, Mtag, MPI_COMM_WORLD, size*sizeof(float)); delete [] ParticleMassFlaggingField; ParticleMassFlaggingField = NULL; @@ -194,21 +182,17 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, Count = size; for (proc = 0; proc < NumberOfSends; proc++) { Source = SendProcs[proc]; -// printf("----> SetPMFlag[P%"ISYM"/%"ISYM"]: " -// "posting receive for %"ISYM" floats, coming from P%"ISYM".\n", -// MyProcessorNumber, ProcessorNumber, size, Source); if (Source >= StartProc && Source < EndProc) { buffer = new float[size]; - MPI_Irecv(buffer, Count, DataType, Source, MPI_SENDPMFLAG_TAG, MPI_COMM_WORLD, + MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); + MPI_Irecv(buffer, Count, DataType, Source, Mtag, MPI_COMM_WORLD, CommunicationReceiveMPI_Request+CommunicationReceiveIndex); CommunicationReceiveGridOne[CommunicationReceiveIndex] = this; CommunicationReceiveGridTwo[CommunicationReceiveIndex] = NULL; CommunicationReceiveCallType[CommunicationReceiveIndex] = 13; CommunicationReceiveBuffer[CommunicationReceiveIndex] = buffer; -// CommunicationReceiveArgumentInt[0][CommunicationReceiveIndex] = StartProc; -// CommunicationReceiveArgumentInt[1][CommunicationReceiveIndex] = EndProc; CommunicationReceiveDependsOn[CommunicationReceiveIndex] = CommunicationReceiveCurrentDependsOn; CommunicationReceiveIndex++; diff --git a/src/enzo/Grid_TransferSubgridActiveParticles.C b/src/enzo/Grid_TransferSubgridActiveParticles.C index 5ba69d67e..da0e64a0d 100644 --- a/src/enzo/Grid_TransferSubgridActiveParticles.C +++ b/src/enzo/Grid_TransferSubgridActiveParticles.C @@ -40,11 +40,11 @@ int grid::TransferSubgridActiveParticles int i0, j0, k0; /* ----------------------------------------------------------------- */ - /* Copy stars out of grid. */ + /* Copy active particles out of grid. */ if (CopyDirection == COPY_OUT) { - /* If stars aren't distributed over several processors, exit + /* If aps aren't distributed over several processors, exit if this isn't the host processor. */ if (ParticlesAreLocal && MyProcessorNumber != ProcessorNumber) @@ -57,25 +57,25 @@ int grid::TransferSubgridActiveParticles /* Set boundaries (with and without ghost zones) */ - int StartIndex[] = {1,1,1}, EndIndex[] = {1,1,1}; + int _StartIndex[] = {1,1,1}, _EndIndex[] = {1,1,1}; if (IncludeGhostZones) for (dim = 0; dim < GridRank; dim++) { - StartIndex[dim] = 0; - EndIndex[dim] = GridDimension[dim]-1; + _StartIndex[dim] = 0; + _EndIndex[dim] = GridDimension[dim]-1; } else for (dim = 0; dim < GridRank; dim++) { - StartIndex[dim] = GridStartIndex[dim]; - EndIndex[dim] = GridEndIndex[dim]; + _StartIndex[dim] = GridStartIndex[dim]; + _EndIndex[dim] = GridEndIndex[dim]; } - /* Count the number of stars already moved */ + /* Count the number of aps already moved */ int PreviousTotalToMove = 0; for (i = 0; i < NumberOfProcessors; i++) PreviousTotalToMove += NumberToMove[i]; - /* Count stars to move */ + /* Count aps to move */ int *subgrid = NULL; subgrid = new int[NumberOfActiveParticles]; @@ -93,9 +93,9 @@ int grid::TransferSubgridActiveParticles k0 = int((this->ActiveParticles[i]->pos[2] - CellLeftEdge[2][0]) / CellWidth[2][0]); - i0 = max(min(EndIndex[0], i0), StartIndex[0]); - j0 = max(min(EndIndex[1], j0), StartIndex[1]); - k0 = max(min(EndIndex[2], k0), StartIndex[2]); + i0 = max(min(_EndIndex[0], i0), _StartIndex[0]); + j0 = max(min(_EndIndex[1], j0), _StartIndex[1]); + k0 = max(min(_EndIndex[2], k0), _StartIndex[2]); index = (k0*GridDimension[1] + j0)*GridDimension[0] + i0; @@ -167,14 +167,14 @@ int grid::TransferSubgridActiveParticles NumberOfActiveParticles = ParticlesLeft; - } // ENDIF stars to move + } // ENDIF aps to move delete [] subgrid; } // end: if (COPY_OUT) /* ----------------------------------------------------------------- */ - /* Copy stars back into grid. */ + /* Copy aps back into grid. */ else { @@ -182,15 +182,10 @@ int grid::TransferSubgridActiveParticles int NumberOfNewActiveParticles = EndIndex - StartIndex; - /* Copy stars from buffer into linked list */ + /* Copy active particles from buffer into linked list */ if (NumberOfNewActiveParticles > 0) { - // Increase the level if moving to a subgrid -// if (IncludeGhostZones == FALSE) -// for (i = StartIndex; i < EndIndex; i++) { -// } - this->AddActiveParticles(List, StartIndex, EndIndex); } // ENDIF new particles diff --git a/src/enzo/Grid_TransferSubgridStars.C b/src/enzo/Grid_TransferSubgridStars.C index 0c4a5e8c7..1d4b0a703 100644 --- a/src/enzo/Grid_TransferSubgridStars.C +++ b/src/enzo/Grid_TransferSubgridStars.C @@ -62,16 +62,16 @@ int grid::TransferSubgridStars(grid* Subgrids[], int NumberOfSubgrids, /* Set boundaries (with and without ghost zones) */ - int StartIndex[] = {1,1,1}, EndIndex[] = {1,1,1}; + int _StartIndex[] = {1,1,1}, _EndIndex[] = {1,1,1}; if (IncludeGhostZones) for (dim = 0; dim < GridRank; dim++) { - StartIndex[dim] = 0; - EndIndex[dim] = GridDimension[dim]-1; + _StartIndex[dim] = 0; + _EndIndex[dim] = GridDimension[dim]-1; } else for (dim = 0; dim < GridRank; dim++) { - StartIndex[dim] = GridStartIndex[dim]; - EndIndex[dim] = GridEndIndex[dim]; + _StartIndex[dim] = GridStartIndex[dim]; + _EndIndex[dim] = GridEndIndex[dim]; } /* Count the number of stars already moved */ @@ -96,9 +96,9 @@ int grid::TransferSubgridStars(grid* Subgrids[], int NumberOfSubgrids, if (GridRank > 1) k0 = int((cstar->pos[2] - CellLeftEdge[2][0])/CellWidth[2][0]); - i0 = max(min(EndIndex[0], i0), StartIndex[0]); - j0 = max(min(EndIndex[1], j0), StartIndex[1]); - k0 = max(min(EndIndex[2], k0), StartIndex[2]); + i0 = max(min(_EndIndex[0], i0), _StartIndex[0]); + j0 = max(min(_EndIndex[1], j0), _StartIndex[1]); + k0 = max(min(_EndIndex[2], k0), _StartIndex[2]); index = (k0*GridDimension[1] + j0)*GridDimension[0] + i0; diff --git a/src/enzo/OutputFromEvolveLevel.C b/src/enzo/OutputFromEvolveLevel.C index 295bf336e..8f1070d84 100644 --- a/src/enzo/OutputFromEvolveLevel.C +++ b/src/enzo/OutputFromEvolveLevel.C @@ -337,7 +337,26 @@ int OutputFromEvolveLevel(LevelHierarchyEntry *LevelArray[],TopGridData *MetaDat }//WriteOutput == TRUE - if( ExitEnzo == TRUE ){ + + if (ExitEnzo == TRUE) { + int i; + LevelHierarchyEntry *Previous, *Temp; + // Delete all data to cleanup for memory checkers (e.g. valgrind) + if (debug) + fprintf(stdout, "Cleanup: deleting all grid data"); + for (i = 0; i < MAX_DEPTH_OF_HIERARCHY; i++) { + Temp = LevelArray[i]; + while (Temp != NULL) { + delete Temp->GridData; + delete Temp->GridHierarchyEntry; + Previous = Temp; + Temp = Temp->NextGridThisLevel; + // Delete previous level hierarchy entry + delete Previous; + } + } + + if (MovieSkipTimestep != INT_UNDEFINED) { fprintf(stderr, "Closing movie file.\n"); MetaData->AmiraGrid.AMRHDF5Close(); diff --git a/src/enzo/RadiativeTransferReadParameters.C b/src/enzo/RadiativeTransferReadParameters.C index 7a792d931..dd45a38cb 100644 --- a/src/enzo/RadiativeTransferReadParameters.C +++ b/src/enzo/RadiativeTransferReadParameters.C @@ -167,6 +167,7 @@ int RadiativeTransferReadParameters(FILE *fptr) if (*dummy != 0) { dummy = new char[MAX_LINE_LENGTH]; + dummy[0] = 0; ret++; } diff --git a/src/enzo/RebuildHierarchy.C b/src/enzo/RebuildHierarchy.C index 9aae166f5..0bfba3cf7 100644 --- a/src/enzo/RebuildHierarchy.C +++ b/src/enzo/RebuildHierarchy.C @@ -577,12 +577,12 @@ int RebuildHierarchy(TopGridData *MetaData, case 1: case 2: case 3: - if (i >= LoadBalancingMinLevel && i <= LoadBalancingMaxLevel) + if (i+1 >= LoadBalancingMinLevel && i+1 <= LoadBalancingMaxLevel) CommunicationLoadBalanceGrids(SubgridHierarchyPointer, subgrids, MoveParticles); break; case 4: - if (i >= LoadBalancingMinLevel && i <= LoadBalancingMaxLevel) + if (i+1 >= LoadBalancingMinLevel && i+1 <= LoadBalancingMaxLevel) LoadBalanceHilbertCurve(SubgridHierarchyPointer, subgrids, MoveParticles); break; diff --git a/src/enzo/enzo.C b/src/enzo/enzo.C index ebf11892a..585099523 100644 --- a/src/enzo/enzo.C +++ b/src/enzo/enzo.C @@ -807,7 +807,26 @@ Eint32 MAIN_NAME(Eint32 argc, char *argv[]) my_exit(EXIT_FAILURE); } else - { + { + // Delete all data to cleanup for memory checkers (e.g. valgrind) + LevelHierarchyEntry *Previous, *Temp; + if (MyProcessorNumber == ROOT_PROCESSOR) + fprintf(stderr, "Cleanup: deleting all grid data\n"); + for (i = 0; i < MAX_DEPTH_OF_HIERARCHY; i++) { + Temp = LevelArray[i]; + while (Temp != NULL) { + delete Temp->GridData; + if (Temp->GridHierarchyEntry != &TopGrid) + delete Temp->GridHierarchyEntry; + Previous = Temp; + Temp = Temp->NextGridThisLevel; + // Delete previous level hierarchy entry + delete Previous; + } + } + Exterior.CleanUp(); + delete enzo_timer; + if (MyProcessorNumber == ROOT_PROCESSOR) { fprintf(stderr, "Successful run, exiting.\n"); } From e2e2b28a707dfeb5583d061f99eface795e30af6 Mon Sep 17 00:00:00 2001 From: regan Date: Tue, 29 Jun 2021 11:41:45 +0200 Subject: [PATCH 096/115] Revert "manually added a commit from JHW to fix MPI errors" This reverts commit e0c7f024ab7e9290a5ebcdb57163dee316d9b078. --- src/enzo/CommunicationCollectParticles.C | 1 - src/enzo/CommunicationReceiveHandler.C | 72 +++++-------------- src/enzo/CommunicationShareGrids.C | 8 --- src/enzo/CommunicationSyncNumberOfParticles.C | 2 +- .../CommunicationTransferActiveParticles.C | 2 +- src/enzo/CommunicationTransferParticlesOpt.C | 2 +- src/enzo/CommunicationTransferStarsOpt.C | 2 +- src/enzo/CommunicationTranspose.C | 16 ++--- src/enzo/DepositParticleMassFlaggingField.C | 10 +++ src/enzo/EnzoTiming.h | 2 +- src/enzo/ErrorExceptions.h | 2 +- src/enzo/ExternalBoundary.h | 16 ----- src/enzo/Grid_CollectActiveParticles.C | 14 ++-- .../Grid_CommunicationSendActiveParticles.C | 2 +- src/enzo/Grid_DeleteAllFields.C | 3 +- src/enzo/Grid_DepositMustRefineParticles.C | 3 +- src/enzo/Grid_SetParticleMassFlaggingField.C | 28 ++++++-- .../Grid_TransferSubgridActiveParticles.C | 35 +++++---- src/enzo/Grid_TransferSubgridStars.C | 16 ++--- src/enzo/OutputFromEvolveLevel.C | 21 +----- src/enzo/RadiativeTransferReadParameters.C | 1 - src/enzo/RebuildHierarchy.C | 4 +- src/enzo/enzo.C | 21 +----- 23 files changed, 104 insertions(+), 179 deletions(-) diff --git a/src/enzo/CommunicationCollectParticles.C b/src/enzo/CommunicationCollectParticles.C index eca292e8e..4f262a1fd 100644 --- a/src/enzo/CommunicationCollectParticles.C +++ b/src/enzo/CommunicationCollectParticles.C @@ -215,7 +215,6 @@ int CommunicationCollectParticles(LevelHierarchyEntry *LevelArray[], TotalNumber = 0; TotalStars = 0; - APTotalNumber = 0; for (j = 0; j < NumberOfProcessors; j++) { TotalNumber += NumberToMove[j]; TotalStars += StarsToMove[j]; diff --git a/src/enzo/CommunicationReceiveHandler.C b/src/enzo/CommunicationReceiveHandler.C index 302d14652..d3323e745 100644 --- a/src/enzo/CommunicationReceiveHandler.C +++ b/src/enzo/CommunicationReceiveHandler.C @@ -13,8 +13,6 @@ / ************************************************************************/ -#define NO_DEBUG_MPI - #ifdef USE_MPI #include "mpi.h" #endif /* USE_MPI */ @@ -34,7 +32,6 @@ #ifdef USE_MPI static MPI_Arg ListOfIndices[MAX_RECEIVE_BUFFERS]; static MPI_Status ListOfStatuses[MAX_RECEIVE_BUFFERS]; -void CommunicationErrorHandlerFn(MPI_Comm *comm, MPI_Arg *err, ...); #endif /* USE_MPI */ double ReturnWallTime(void); @@ -94,59 +91,26 @@ int CommunicationReceiveHandler(fluxes **SubgridFluxesEstimate[], ENZO_FAIL("Error in MPI_Waitsome\n"); } #endif - MPI_Arg bsize; + /* Should loop over newly received completions and check error msgs now. */ + for (index = 0; index < NumberOfCompleteRequests; index++) + if (ListOfStatuses[index].MPI_ERROR != 0) { + if (NoErrorSoFar) { + fprintf(stderr, "MPI Error on processor %"ISYM". " + "Error number %"ISYM" on request %"ISYM"\n", + MyProcessorNumber, ListOfStatuses[index].MPI_ERROR, index); + NoErrorSoFar = FALSE; + } + fprintf(stdout, "P(%"ISYM") index %"ISYM" -- mpi error %"ISYM"\n", + MyProcessorNumber, index, ListOfStatuses[index].MPI_ERROR); + fprintf(stdout, "%"ISYM": Type = %"ISYM", Grid1 = %x, Request = %"ISYM", " + "DependsOn = %"ISYM"\n", index, + CommunicationReceiveCallType[index], + CommunicationReceiveGridOne[index], + CommunicationReceiveMPI_Request[index], + CommunicationReceiveDependsOn[index]); + } - for (index = 0; index < NumberOfCompleteRequests; index++) { -#ifdef DEBUG_MPI - MPI_Get_count(ListOfStatuses+index, MPI_CHAR, &bsize); - fprintf(stderr, "P%"ISYM": MPI_Irecv[%d/%d] -- " - "Error number %d from processor %d with tag %d" - " on request %d (MPI_REQUEST_NULL = %d) with %d bytes\n", - MyProcessorNumber, index, NumberOfCompleteRequests, - ListOfStatuses[index].MPI_ERROR, - ListOfStatuses[index].MPI_SOURCE, - ListOfStatuses[index].MPI_TAG, - ListOfIndices[index], - (CommunicationReceiveMPI_Request[index] == MPI_REQUEST_NULL), - bsize); -#endif /* DEBUG_MPI */ - - if (ListOfStatuses[index].MPI_ERROR != 0) { - if (NoErrorSoFar) { - MPI_Get_count(ListOfStatuses+index, MPI_CHAR, &bsize); - fprintf(stderr, "MPI Error on processor %"ISYM". " - "Error number %d from processor %d with tag %d" - " on request %"ISYM" (MPI_REQUEST_NULL = %d) with %d bytes\n", - MyProcessorNumber, ListOfStatuses[index].MPI_ERROR, - ListOfStatuses[index].MPI_SOURCE, ListOfStatuses[index].MPI_TAG, - index, - (CommunicationReceiveMPI_Request[index] == MPI_REQUEST_NULL), - bsize); - NoErrorSoFar = FALSE; - } - int _id = -1; - if (CommunicationReceiveGridOne[index] != NULL) - _id = CommunicationReceiveGridOne[index]->GetGridID(); - fprintf(stderr, "P(%"ISYM") index %"ISYM" -- mpi error %"ISYM"\n", - MyProcessorNumber, index, ListOfStatuses[index].MPI_ERROR); - fprintf(stderr, "%"ISYM": Type = %"ISYM", Grid1 = %x (G%"ISYM"), " - "Request = %x (%"ISYM"), " - "Arg0/Arg1/Arg2 = %"ISYM"/%"ISYM"/%"ISYM", DependsOn = %"ISYM"\n", - index, - CommunicationReceiveCallType[index], - CommunicationReceiveGridOne[index], _id, - CommunicationReceiveMPI_Request[index], - MPI_REQUEST_NULL, - CommunicationReceiveArgumentInt[0][index], - CommunicationReceiveArgumentInt[1][index], - CommunicationReceiveArgumentInt[2][index], - CommunicationReceiveDependsOn[index]); - MPI_Comm comm = MPI_COMM_WORLD; - MPI_Arg errcode = ListOfStatuses[index].MPI_ERROR; - CommunicationErrorHandlerFn(&comm, &errcode); - } // ENDIF error - } // ENDFOR requests /* Here we loop over the handles looking only for the ones for grid::CommunicationSendActiveParticles, and count how many there are, and how many are finished receiving. If all are, we can go ahead diff --git a/src/enzo/CommunicationShareGrids.C b/src/enzo/CommunicationShareGrids.C index 81fbdbd70..e61c82732 100644 --- a/src/enzo/CommunicationShareGrids.C +++ b/src/enzo/CommunicationShareGrids.C @@ -53,7 +53,6 @@ int CommunicationShareGrids(HierarchyEntry *GridHierarchyPointer[], FLOAT RightEdge[MAX_DIMENSION]; int NumberOfParticles; int NumberOfStars; - int NumberOfActiveParticles; int ParentNumber; }; int i; @@ -91,12 +90,9 @@ int CommunicationShareGrids(HierarchyEntry *GridHierarchyPointer[], Temp->GridData->ReturnNumberOfParticles(); SendList[Counter].NumberOfStars = Temp->GridData->ReturnNumberOfStars(); - SendList[Counter].NumberOfActiveParticles = - Temp->GridData->ReturnNumberOfActiveParticles(); } else { SendList[Counter].NumberOfParticles = 0; SendList[Counter].NumberOfStars = 0; - SendList[Counter].NumberOfActiveParticles = 0; } SendList[Counter++].ParentNumber = i; Temp = Temp->NextGridThisLevel; @@ -225,7 +221,6 @@ int CommunicationShareGrids(HierarchyEntry *GridHierarchyPointer[], if (ShareParticles == TRUE) { ThisGrid->GridData->SetNumberOfParticles(SharedList[i].NumberOfParticles); ThisGrid->GridData->SetNumberOfStars(SharedList[i].NumberOfStars); - ThisGrid->GridData->SetNumberOfActiveParticles(SharedList[i].NumberOfActiveParticles); } if (SubgridParent != NULL && ShareParticles == TRUE) { @@ -236,9 +231,6 @@ int CommunicationShareGrids(HierarchyEntry *GridHierarchyPointer[], SubgridParent->GridData->SetNumberOfStars (SubgridParent->GridData->ReturnNumberOfStars() - SharedList[i].NumberOfStars); - SubgridParent->GridData->SetNumberOfActiveParticles - (SubgridParent->GridData->ReturnNumberOfActiveParticles() - - SharedList[i].NumberOfActiveParticles); } // ENDIF parent exists and sharing particles/stars diff --git a/src/enzo/CommunicationSyncNumberOfParticles.C b/src/enzo/CommunicationSyncNumberOfParticles.C index d24452cc3..25cf82c62 100644 --- a/src/enzo/CommunicationSyncNumberOfParticles.C +++ b/src/enzo/CommunicationSyncNumberOfParticles.C @@ -49,7 +49,7 @@ int CommunicationSyncNumberOfParticles(HierarchyEntry *GridHierarchyPointer[], buffer[idx+3+j] = GridHierarchyPointer[i]->GridData-> ReturnNumberOfActiveParticlesOfThisType(j); } else { - buffer[idx+3+j] = 0; + buffer[idx+3+j] = 0.; } } } else { diff --git a/src/enzo/CommunicationTransferActiveParticles.C b/src/enzo/CommunicationTransferActiveParticles.C index 940b4e942..69133556f 100644 --- a/src/enzo/CommunicationTransferActiveParticles.C +++ b/src/enzo/CommunicationTransferActiveParticles.C @@ -92,7 +92,7 @@ int CommunicationTransferActiveParticles for (i = 0; i < Layout[dim]; i++) { ExactCount += ExactDims; - if (i < Layout[dim]-1) + if (dim == 0) ThisCount = nint(0.5*ExactCount)*2 - DisplacementCount; else ThisCount = nint(ExactCount) - DisplacementCount; diff --git a/src/enzo/CommunicationTransferParticlesOpt.C b/src/enzo/CommunicationTransferParticlesOpt.C index 8e0dc77d4..65113f049 100644 --- a/src/enzo/CommunicationTransferParticlesOpt.C +++ b/src/enzo/CommunicationTransferParticlesOpt.C @@ -96,7 +96,7 @@ int CommunicationTransferParticles(grid *GridPointer[], int NumberOfGrids, for (i = 0; i < Layout[dim]; i++) { ExactCount += ExactDims; - if (i < Layout[dim]-1) + if (dim == 0) ThisCount = nint(0.5*ExactCount)*2 - DisplacementCount; else ThisCount = nint(ExactCount) - DisplacementCount; diff --git a/src/enzo/CommunicationTransferStarsOpt.C b/src/enzo/CommunicationTransferStarsOpt.C index eaa983115..b354acc04 100644 --- a/src/enzo/CommunicationTransferStarsOpt.C +++ b/src/enzo/CommunicationTransferStarsOpt.C @@ -94,7 +94,7 @@ int CommunicationTransferStars(grid *GridPointer[], int NumberOfGrids, for (i = 0; i < Layout[dim]; i++) { ExactCount += ExactDims; - if (i < Layout[dim]-1) + if (dim == 0) ThisCount = nint(0.5*ExactCount)*2 - DisplacementCount; else ThisCount = nint(ExactCount) - DisplacementCount; diff --git a/src/enzo/CommunicationTranspose.C b/src/enzo/CommunicationTranspose.C index 99f1787d3..b2faaf8a5 100644 --- a/src/enzo/CommunicationTranspose.C +++ b/src/enzo/CommunicationTranspose.C @@ -1020,7 +1020,6 @@ int NonBlockingCommunicationTranspose(region *FromRegion, int NumberOfFromRegion processing receives this cycle. */ MPI_Arg TotalCompletedRequests, CompletedRequests; - bool ProcessRequest; if (ReceiveMode) { TotalCompletedRequests = 0; @@ -1049,16 +1048,11 @@ int NonBlockingCommunicationTranspose(region *FromRegion, int NumberOfFromRegion /* First cycle only has one call. Break if we've already processed the first call, otherwise always process it. */ - if (n == 0) { - if (request == 0) - ProcessRequest = true; - else - break; - } else { - ProcessRequest = (RequestHandle[request] == MPI_REQUEST_NULL) && - (ReceiveBuffer[request] != NULL); - } - if (ProcessRequest) { + if (n == 0 && request > 0) break; + if ((RequestHandle[request] == MPI_REQUEST_NULL && + ReceiveBuffer[request] != NULL) || + (n == 0 && request == 0)) { + #ifdef DEBUG_NONBLOCKCT fprintf(stderr, "CT(%"ISYM"): request = %d, receives = %"ISYM"\n", MyProcessorNumber, request, receives); diff --git a/src/enzo/DepositParticleMassFlaggingField.C b/src/enzo/DepositParticleMassFlaggingField.C index b6fbc9242..9f8c284bb 100644 --- a/src/enzo/DepositParticleMassFlaggingField.C +++ b/src/enzo/DepositParticleMassFlaggingField.C @@ -190,6 +190,10 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], MPI_SendListCount[proc] = NumberOfSends[proc]; } +// for (i = 0; i < TotalNumberOfSends; i++) +// printf("P%"ISYM" -- BB -- SendList[%"ISYM"]: %"ISYM" %"ISYM"\n", +// MyProcessorNumber, i, SendList[i].grid, SendList[i].proc); + // Sort by grid (destination) processor, then replace the // processor number with this processor number because the grid // processor needs it to post the receives. @@ -241,6 +245,9 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], for (i = 0; i < TotalNumberOfSends; i++) SendList[i].proc = MyProcessorNumber; +// for (i = 0; i < TotalNumberOfSends; i++) +// printf("P%"ISYM" -- SendList[%"ISYM"]: %"ISYM" %"ISYM"\n", +// MyProcessorNumber, i, SendList[i].grid, SendList[i].proc); #ifdef TIMING t0 = ReturnWallTime(); @@ -257,6 +264,9 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], printf("--> DPMFF: After Alltoallv :: %lg seconds\n", t1-t0); #endif +// for (i = 0; i < TotalNumberOfRecv; i++) +// printf("P%"ISYM" -- SharedList[%"ISYM"]: %"ISYM" %"ISYM"\n", +// MyProcessorNumber, i, SharedList[i].grid, SharedList[i].proc); delete [] NumberOfSends; delete [] MPI_SendListCount; diff --git a/src/enzo/EnzoTiming.h b/src/enzo/EnzoTiming.h index b891f7be4..6d7772d58 100644 --- a/src/enzo/EnzoTiming.h +++ b/src/enzo/EnzoTiming.h @@ -158,7 +158,7 @@ namespace enzo_timing{ // Destructor, erases each timer. ~enzo_timer(void){ for( SectionMap::iterator iter=timers.begin(); iter!=timers.end(); ++iter){ - delete iter->second; + delete [] iter->second; timers.erase(iter); } timers.clear(); diff --git a/src/enzo/ErrorExceptions.h b/src/enzo/ErrorExceptions.h index 05c8333c5..7df93dc33 100644 --- a/src/enzo/ErrorExceptions.h +++ b/src/enzo/ErrorExceptions.h @@ -57,7 +57,7 @@ extern char current_error[255]; fprintf(stderr, "BT symbol: %s\n", symbols[i]); } - delete symbols; + delete [] symbols; } void WriteDebuggingOutput() { diff --git a/src/enzo/ExternalBoundary.h b/src/enzo/ExternalBoundary.h index fa605b03b..5c0257fd0 100644 --- a/src/enzo/ExternalBoundary.h +++ b/src/enzo/ExternalBoundary.h @@ -48,22 +48,6 @@ class ExternalBoundary // Constructor (set rank and dims from TopGrid) // ExternalBoundary(); - - // - // Destructor - // - void CleanUp (void) { - for (int field = 0; field < MAX_NUMBER_OF_BARYON_FIELDS; field++) { - for (int dim = 0; dim < MAX_DIMENSION; dim++) { - for (int i = 0; i < 2; i++) { - if (BoundaryType[field][dim][i] != NULL) - delete [] BoundaryType[field][dim][i]; - if (BoundaryValue[field][dim][i] != NULL) - delete [] BoundaryValue[field][dim][i]; - } - } - } - } // // Prepare External Boundary (set dims, etc.) based on TopGrid in argument. // diff --git a/src/enzo/Grid_CollectActiveParticles.C b/src/enzo/Grid_CollectActiveParticles.C index 2a3e7e66d..4f72df40d 100644 --- a/src/enzo/Grid_CollectActiveParticles.C +++ b/src/enzo/Grid_CollectActiveParticles.C @@ -34,11 +34,11 @@ int grid::CollectActiveParticles(int GridNum, int* &NumberToMove, int i, j, dim, n1, grid, proc; /* ----------------------------------------------------------------- */ - /* Copy active particle out of grid. */ + /* Copy star out of grid. */ if (CopyDirection == COPY_OUT) { - /* If there are no active particles to move, we're done. */ + /* If there are no stars to move, we're done. */ if (NumberOfActiveParticles == 0) return SUCCESS; @@ -48,18 +48,18 @@ int grid::CollectActiveParticles(int GridNum, int* &NumberToMove, if (MyProcessorNumber == ProcessorNumber) return SUCCESS; - /* Add to the active particle count to move */ + /* Add to the star count to move */ - // NumberOfActiveParticles is still the number of local aps, not the + // NumberOfActiveParticles is still the number of local stars, not the // actual total! NumberToMove[ProcessorNumber] += NumberOfActiveParticles; - /* Move and delete active particles */ + /* Move and delete stars */ for (i = 0, n1 = StartIndex; i < NumberOfActiveParticles; i++, n1++) { List.copy_and_insert(*ActiveParticles[i]); List[n1]->SetGridID(GridNum); - } // ENDFOR active particles + } // ENDFOR stars StartIndex = n1; this->DeleteActiveParticles(); @@ -67,7 +67,7 @@ int grid::CollectActiveParticles(int GridNum, int* &NumberToMove, } // end: if (COPY_OUT) /* ----------------------------------------------------------------- */ - /* Copy active particles back into grid. */ + /* Copy stars back into grid. */ else { diff --git a/src/enzo/Grid_CommunicationSendActiveParticles.C b/src/enzo/Grid_CommunicationSendActiveParticles.C index a4a160fd2..97e261f9f 100644 --- a/src/enzo/Grid_CommunicationSendActiveParticles.C +++ b/src/enzo/Grid_CommunicationSendActiveParticles.C @@ -117,7 +117,7 @@ int grid::CommunicationSendActiveParticles( Count = EnabledActiveParticlesCount; Source = ProcessorNumber; Dest = ToProcessor; - + // send if ((MyProcessorNumber == ProcessorNumber) && ((CommunicationDirection == COMMUNICATION_SEND_RECEIVE) || diff --git a/src/enzo/Grid_DeleteAllFields.C b/src/enzo/Grid_DeleteAllFields.C index d32678d08..8441aaaea 100644 --- a/src/enzo/Grid_DeleteAllFields.C +++ b/src/enzo/Grid_DeleteAllFields.C @@ -30,8 +30,7 @@ void grid::DeleteAllFields() int i; this->DeleteParticles(); - this->DeleteActiveParticles(); - + for (i = 0; i < MAX_DIMENSION; i++) { delete [] ParticleAcceleration[i]; delete [] AccelerationField[i]; diff --git a/src/enzo/Grid_DepositMustRefineParticles.C b/src/enzo/Grid_DepositMustRefineParticles.C index 92870850d..33c4d2c23 100644 --- a/src/enzo/Grid_DepositMustRefineParticles.C +++ b/src/enzo/Grid_DepositMustRefineParticles.C @@ -92,9 +92,10 @@ int grid::DepositMustRefineParticles(int pmethod, int level, bool KeepFlaggingFi rules = new bool[NumberOfRules]; // Rules to prevent refinement, cancelling out the above rules. - bool *antirules = NULL; + bool *antirules; int *AntiFlaggingField; int NumberOfAntiRules = 0; + antirules = new bool[NumberOfAntiRules]; // Add an antirule to unflag over-refined dark matter particles. if (MustRefineParticlesCreateParticles == 4) { diff --git a/src/enzo/Grid_SetParticleMassFlaggingField.C b/src/enzo/Grid_SetParticleMassFlaggingField.C index 481ee3194..c61186c0e 100644 --- a/src/enzo/Grid_SetParticleMassFlaggingField.C +++ b/src/enzo/Grid_SetParticleMassFlaggingField.C @@ -48,14 +48,24 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, /* Return if we're not needed here */ +// if (MyProcessorNumber == ProcessorNumber && +// CommunicationDirection == COMMUNICATION_SEND) +// return SUCCESS; + + //printf(" grid::SetParticleMassFlaggingField \n"); + if (MyProcessorNumber != ProcessorNumber && (CommunicationDirection == COMMUNICATION_RECEIVE || CommunicationDirection == COMMUNICATION_POST_RECEIVE)) return SUCCESS; +// printf("--> SetPMFlag[P%"ISYM"/%"ISYM"]: level %"ISYM", grid %"ISYM", " +// "comm_dir = %"ISYM", npart = %"ISYM"\n", +// MyProcessorNumber, ProcessorNumber, level, GridNum, +// CommunicationDirection, NumberOfParticles); #ifdef USE_MPI - MPI_Datatype DataType = FloatDataType; + MPI_Datatype DataType = (sizeof(float) == 4) ? MPI_FLOAT : MPI_DOUBLE; MPI_Arg Count; MPI_Arg Source; float *buffer = NULL; @@ -84,7 +94,7 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, // given range and has particles. if (MyProcessorNumber != ProcessorNumber && (MyProcessorNumber < StartProc || MyProcessorNumber >= EndProc || - (NumberOfParticles == 0 && NumberOfActiveParticles == 0))) + NumberOfParticles == 0 && NumberOfActiveParticles == 0)) return SUCCESS; /***********************************************************************/ @@ -150,9 +160,11 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, #ifdef USE_MPI if (MyProcessorNumber != ProcessorNumber) { - MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); + //MPI_Tag = Return_MPI_Tag(GridNum, MyProcessorNumber); +// printf("----> SetPMFlag[P%"ISYM"/%"ISYM"]: sending %"ISYM" floats.\n", +// MyProcessorNumber, ProcessorNumber, size); CommunicationBufferedSend(ParticleMassFlaggingField, size, DataType, - ProcessorNumber, Mtag, + ProcessorNumber, MPI_SENDPMFLAG_TAG, MPI_COMM_WORLD, size*sizeof(float)); delete [] ParticleMassFlaggingField; ParticleMassFlaggingField = NULL; @@ -182,17 +194,21 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, Count = size; for (proc = 0; proc < NumberOfSends; proc++) { Source = SendProcs[proc]; +// printf("----> SetPMFlag[P%"ISYM"/%"ISYM"]: " +// "posting receive for %"ISYM" floats, coming from P%"ISYM".\n", +// MyProcessorNumber, ProcessorNumber, size, Source); if (Source >= StartProc && Source < EndProc) { buffer = new float[size]; - MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); - MPI_Irecv(buffer, Count, DataType, Source, Mtag, MPI_COMM_WORLD, + MPI_Irecv(buffer, Count, DataType, Source, MPI_SENDPMFLAG_TAG, MPI_COMM_WORLD, CommunicationReceiveMPI_Request+CommunicationReceiveIndex); CommunicationReceiveGridOne[CommunicationReceiveIndex] = this; CommunicationReceiveGridTwo[CommunicationReceiveIndex] = NULL; CommunicationReceiveCallType[CommunicationReceiveIndex] = 13; CommunicationReceiveBuffer[CommunicationReceiveIndex] = buffer; +// CommunicationReceiveArgumentInt[0][CommunicationReceiveIndex] = StartProc; +// CommunicationReceiveArgumentInt[1][CommunicationReceiveIndex] = EndProc; CommunicationReceiveDependsOn[CommunicationReceiveIndex] = CommunicationReceiveCurrentDependsOn; CommunicationReceiveIndex++; diff --git a/src/enzo/Grid_TransferSubgridActiveParticles.C b/src/enzo/Grid_TransferSubgridActiveParticles.C index da0e64a0d..5ba69d67e 100644 --- a/src/enzo/Grid_TransferSubgridActiveParticles.C +++ b/src/enzo/Grid_TransferSubgridActiveParticles.C @@ -40,11 +40,11 @@ int grid::TransferSubgridActiveParticles int i0, j0, k0; /* ----------------------------------------------------------------- */ - /* Copy active particles out of grid. */ + /* Copy stars out of grid. */ if (CopyDirection == COPY_OUT) { - /* If aps aren't distributed over several processors, exit + /* If stars aren't distributed over several processors, exit if this isn't the host processor. */ if (ParticlesAreLocal && MyProcessorNumber != ProcessorNumber) @@ -57,25 +57,25 @@ int grid::TransferSubgridActiveParticles /* Set boundaries (with and without ghost zones) */ - int _StartIndex[] = {1,1,1}, _EndIndex[] = {1,1,1}; + int StartIndex[] = {1,1,1}, EndIndex[] = {1,1,1}; if (IncludeGhostZones) for (dim = 0; dim < GridRank; dim++) { - _StartIndex[dim] = 0; - _EndIndex[dim] = GridDimension[dim]-1; + StartIndex[dim] = 0; + EndIndex[dim] = GridDimension[dim]-1; } else for (dim = 0; dim < GridRank; dim++) { - _StartIndex[dim] = GridStartIndex[dim]; - _EndIndex[dim] = GridEndIndex[dim]; + StartIndex[dim] = GridStartIndex[dim]; + EndIndex[dim] = GridEndIndex[dim]; } - /* Count the number of aps already moved */ + /* Count the number of stars already moved */ int PreviousTotalToMove = 0; for (i = 0; i < NumberOfProcessors; i++) PreviousTotalToMove += NumberToMove[i]; - /* Count aps to move */ + /* Count stars to move */ int *subgrid = NULL; subgrid = new int[NumberOfActiveParticles]; @@ -93,9 +93,9 @@ int grid::TransferSubgridActiveParticles k0 = int((this->ActiveParticles[i]->pos[2] - CellLeftEdge[2][0]) / CellWidth[2][0]); - i0 = max(min(_EndIndex[0], i0), _StartIndex[0]); - j0 = max(min(_EndIndex[1], j0), _StartIndex[1]); - k0 = max(min(_EndIndex[2], k0), _StartIndex[2]); + i0 = max(min(EndIndex[0], i0), StartIndex[0]); + j0 = max(min(EndIndex[1], j0), StartIndex[1]); + k0 = max(min(EndIndex[2], k0), StartIndex[2]); index = (k0*GridDimension[1] + j0)*GridDimension[0] + i0; @@ -167,14 +167,14 @@ int grid::TransferSubgridActiveParticles NumberOfActiveParticles = ParticlesLeft; - } // ENDIF aps to move + } // ENDIF stars to move delete [] subgrid; } // end: if (COPY_OUT) /* ----------------------------------------------------------------- */ - /* Copy aps back into grid. */ + /* Copy stars back into grid. */ else { @@ -182,10 +182,15 @@ int grid::TransferSubgridActiveParticles int NumberOfNewActiveParticles = EndIndex - StartIndex; - /* Copy active particles from buffer into linked list */ + /* Copy stars from buffer into linked list */ if (NumberOfNewActiveParticles > 0) { + // Increase the level if moving to a subgrid +// if (IncludeGhostZones == FALSE) +// for (i = StartIndex; i < EndIndex; i++) { +// } + this->AddActiveParticles(List, StartIndex, EndIndex); } // ENDIF new particles diff --git a/src/enzo/Grid_TransferSubgridStars.C b/src/enzo/Grid_TransferSubgridStars.C index 1d4b0a703..0c4a5e8c7 100644 --- a/src/enzo/Grid_TransferSubgridStars.C +++ b/src/enzo/Grid_TransferSubgridStars.C @@ -62,16 +62,16 @@ int grid::TransferSubgridStars(grid* Subgrids[], int NumberOfSubgrids, /* Set boundaries (with and without ghost zones) */ - int _StartIndex[] = {1,1,1}, _EndIndex[] = {1,1,1}; + int StartIndex[] = {1,1,1}, EndIndex[] = {1,1,1}; if (IncludeGhostZones) for (dim = 0; dim < GridRank; dim++) { - _StartIndex[dim] = 0; - _EndIndex[dim] = GridDimension[dim]-1; + StartIndex[dim] = 0; + EndIndex[dim] = GridDimension[dim]-1; } else for (dim = 0; dim < GridRank; dim++) { - _StartIndex[dim] = GridStartIndex[dim]; - _EndIndex[dim] = GridEndIndex[dim]; + StartIndex[dim] = GridStartIndex[dim]; + EndIndex[dim] = GridEndIndex[dim]; } /* Count the number of stars already moved */ @@ -96,9 +96,9 @@ int grid::TransferSubgridStars(grid* Subgrids[], int NumberOfSubgrids, if (GridRank > 1) k0 = int((cstar->pos[2] - CellLeftEdge[2][0])/CellWidth[2][0]); - i0 = max(min(_EndIndex[0], i0), _StartIndex[0]); - j0 = max(min(_EndIndex[1], j0), _StartIndex[1]); - k0 = max(min(_EndIndex[2], k0), _StartIndex[2]); + i0 = max(min(EndIndex[0], i0), StartIndex[0]); + j0 = max(min(EndIndex[1], j0), StartIndex[1]); + k0 = max(min(EndIndex[2], k0), StartIndex[2]); index = (k0*GridDimension[1] + j0)*GridDimension[0] + i0; diff --git a/src/enzo/OutputFromEvolveLevel.C b/src/enzo/OutputFromEvolveLevel.C index 8f1070d84..295bf336e 100644 --- a/src/enzo/OutputFromEvolveLevel.C +++ b/src/enzo/OutputFromEvolveLevel.C @@ -337,26 +337,7 @@ int OutputFromEvolveLevel(LevelHierarchyEntry *LevelArray[],TopGridData *MetaDat }//WriteOutput == TRUE - - if (ExitEnzo == TRUE) { - int i; - LevelHierarchyEntry *Previous, *Temp; - // Delete all data to cleanup for memory checkers (e.g. valgrind) - if (debug) - fprintf(stdout, "Cleanup: deleting all grid data"); - for (i = 0; i < MAX_DEPTH_OF_HIERARCHY; i++) { - Temp = LevelArray[i]; - while (Temp != NULL) { - delete Temp->GridData; - delete Temp->GridHierarchyEntry; - Previous = Temp; - Temp = Temp->NextGridThisLevel; - // Delete previous level hierarchy entry - delete Previous; - } - } - - + if( ExitEnzo == TRUE ){ if (MovieSkipTimestep != INT_UNDEFINED) { fprintf(stderr, "Closing movie file.\n"); MetaData->AmiraGrid.AMRHDF5Close(); diff --git a/src/enzo/RadiativeTransferReadParameters.C b/src/enzo/RadiativeTransferReadParameters.C index dd45a38cb..7a792d931 100644 --- a/src/enzo/RadiativeTransferReadParameters.C +++ b/src/enzo/RadiativeTransferReadParameters.C @@ -167,7 +167,6 @@ int RadiativeTransferReadParameters(FILE *fptr) if (*dummy != 0) { dummy = new char[MAX_LINE_LENGTH]; - dummy[0] = 0; ret++; } diff --git a/src/enzo/RebuildHierarchy.C b/src/enzo/RebuildHierarchy.C index 0bfba3cf7..9aae166f5 100644 --- a/src/enzo/RebuildHierarchy.C +++ b/src/enzo/RebuildHierarchy.C @@ -577,12 +577,12 @@ int RebuildHierarchy(TopGridData *MetaData, case 1: case 2: case 3: - if (i+1 >= LoadBalancingMinLevel && i+1 <= LoadBalancingMaxLevel) + if (i >= LoadBalancingMinLevel && i <= LoadBalancingMaxLevel) CommunicationLoadBalanceGrids(SubgridHierarchyPointer, subgrids, MoveParticles); break; case 4: - if (i+1 >= LoadBalancingMinLevel && i+1 <= LoadBalancingMaxLevel) + if (i >= LoadBalancingMinLevel && i <= LoadBalancingMaxLevel) LoadBalanceHilbertCurve(SubgridHierarchyPointer, subgrids, MoveParticles); break; diff --git a/src/enzo/enzo.C b/src/enzo/enzo.C index 585099523..ebf11892a 100644 --- a/src/enzo/enzo.C +++ b/src/enzo/enzo.C @@ -807,26 +807,7 @@ Eint32 MAIN_NAME(Eint32 argc, char *argv[]) my_exit(EXIT_FAILURE); } else - { - // Delete all data to cleanup for memory checkers (e.g. valgrind) - LevelHierarchyEntry *Previous, *Temp; - if (MyProcessorNumber == ROOT_PROCESSOR) - fprintf(stderr, "Cleanup: deleting all grid data\n"); - for (i = 0; i < MAX_DEPTH_OF_HIERARCHY; i++) { - Temp = LevelArray[i]; - while (Temp != NULL) { - delete Temp->GridData; - if (Temp->GridHierarchyEntry != &TopGrid) - delete Temp->GridHierarchyEntry; - Previous = Temp; - Temp = Temp->NextGridThisLevel; - // Delete previous level hierarchy entry - delete Previous; - } - } - Exterior.CleanUp(); - delete enzo_timer; - + { if (MyProcessorNumber == ROOT_PROCESSOR) { fprintf(stderr, "Successful run, exiting.\n"); } From 091e926f9abcf929fb7fc4a6f35e1fa949a76447 Mon Sep 17 00:00:00 2001 From: regan Date: Thu, 1 Jul 2021 10:40:58 +0200 Subject: [PATCH 097/115] debugging seg fault on formation --- src/enzo/ActiveParticle_SmartStar.C | 26 +++++++++++--------- src/enzo/ActiveParticle_SmartStar.h | 20 +++++++++++---- src/enzo/CommunicationCollectParticles.C | 1 + src/enzo/DepositParticleMassFlaggingField.C | 10 -------- src/enzo/Grid_SetParticleMassFlaggingField.C | 23 +++++------------ 5 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 13be49ab3..dfb0690a3 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -811,13 +811,6 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle { int *SSparticles = new int(nParticles); float StellarMasstoRemove = 0.0, CellDensityAfterFormation = 0.0; - /* Skip accretion if we're not on the maximum refinement level. - This should only ever happen right after creation and then - only in pathological cases where sink creation is happening at - the edges of two regions at the maximum refinement level */ - - if (ThisLevel < MaximumRefinementLevel) - return SUCCESS; FLOAT Time = LevelArray[ThisLevel]->GridData->ReturnTime(); float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, VelocityUnits; @@ -827,8 +820,10 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle MassUnits = DensityUnits * POW(LengthUnits,3); float tdyn_code = StarClusterMinDynamicalTime/(TimeUnits/yr_s); + //printf("%s: nParticles = %d\n", __FUNCTION__, nParticles); for (int i = 0; i < nParticles; i++) SSparticles[i] = -1; + //return SUCCESS; //works /* * Order particles in order of SMS, PopIII, PopII * SMS first since they have the highest accretion rates and hence @@ -850,9 +845,11 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { ActiveParticleType_SmartStar* SS; + printf("%s: P%d: ParticleList[i] = %p\t SS->TimeIndex = %d\n", __FUNCTION__, MyProcessorNumber, ParticleList[i], SS->TimeIndex); SS = static_cast(ParticleList[i]); if(SS->ParticleClass == POPIII && SS->TimeIndex == 0) { - SSparticles[k++] = i; + printf("POPIII: Setting SSparticles[%d] = %d\n", k, i); fflush(stdout); + SSparticles[k++] = 6; //i; num_new_popiii_stars++; } } @@ -868,15 +865,19 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle } } } + //return SUCCESS; /*breaks*/ int num_new_stars = num_new_sms_stars + num_new_popiii_stars + num_new_popii_stars; if(num_new_stars == 0) return SUCCESS; - + printf("%s: JR: num_new_stars = %d\n", __FUNCTION__, num_new_stars); + printf("num_new_sms_stars = %d\t num_new_popiii_stars = %d\t num_new_popii_stars = %d\n", num_new_sms_stars , num_new_popiii_stars , num_new_popii_stars); + fflush(stdout); for (int k = 0; k < num_new_stars; k++) { int pindex = SSparticles[k]; grid* APGrid = ParticleList[pindex]->ReturnCurrentGrid(); if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { + printf("P%d\t num_new_stars = %d\n", MyProcessorNumber, num_new_stars); fflush(stdout); ActiveParticleType_SmartStar* SS; SS = static_cast(ParticleList[pindex]); @@ -1086,7 +1087,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle * mass of the particle in solar masses it is reset * below in code density units. */ - + printf("ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); if(POPIII == SS->ParticleClass) { SS->AssignMassFromIMF(); SS->StellarAge = SS->RadiationLifetime; @@ -1162,6 +1163,8 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle printf("%s: Particle Mass = %1.1f Msolar\n", __FUNCTION__, SS->Mass); printf("%s: Particle Class = %d\n", __FUNCTION__, SS->ParticleClass); printf("%s: Remove mass from sphere of radius %lf pc\n", __FUNCTION__, Radius*LengthUnits/pc_cm); + fflush(stdout); + /* Update cell information */ int index = 0; FLOAT delx = 0.0, dely = 0.0, delz = 0.0, radius2 = 0.0, DomainWidth[MAX_DIMENSION]; @@ -1173,7 +1176,8 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle MetalIINum, MBHColourNum, Galaxy1ColourNum, Galaxy2ColourNum) == FAIL) ENZO_FAIL("Error in grid->IdentifyColourFields.\n"); - + printf("%s: Colour Fields Identified\n", __FUNCTION__); fflush(stdout); + MetalNum = max(Metal2Num, SNColourNum); MetallicityField = (MetalNum > 0) ? TRUE : FALSE; float metallicity = 0.0; diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index ce9130d7b..8fe876bf9 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -30,13 +30,13 @@ #define DEBUG 0 /* Every how many times will the accretion rate be updated */ //#define FREQUENCY 100 -#define MAXACCRETIONRADIUS 128 /* Times the minimum cell width */ +#define MAXACCRETIONRADIUS 128 /* Times the minimum cell width (currently not used) */ #define ACCRETIONRADIUS 4 #define NUMRADIATIONBINS 5 #define CRITICAL_ACCRETION_RATE 0.001 //Msolar/yr (Haemerlee et al (2018)) #define TIMEGAP 100 // * timestep #define POPIII_RESOLUTION 0.001 //pc -#define SMS_RESOLUTION 0.1 //pc +#define SMS_RESOLUTION 1.0 //pc /* Prototypes */ int GetUnits(float *DensityUnits, float *LengthUnits, @@ -368,11 +368,21 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( /* Remove mass from grid from newly formed particles */ RemoveMassFromGridAfterFormation(nParticles, ParticleList, LevelArray, ThisLevel); - //ParticleList.delete_marked_particles(); + /* Clean any particles marked for deletion */ + for (i = 0; iShouldDelete() == true) { + printf("%s: Delete SS %d following RemoveMassFromGridAfterFormation\n", __FUNCTION__, + static_cast(ParticleList[i])->ReturnID()); + fflush(stdout); + ParticleList.erase(i); + i = -1; + nParticles--; + } + } /* Regenerate the global list following deletions. */ - //ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, - // ParticleList); + ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, + ParticleList); if (AssignActiveParticlesToGrids(ParticleList, nParticles, LevelArray) == FAIL) return FAIL; diff --git a/src/enzo/CommunicationCollectParticles.C b/src/enzo/CommunicationCollectParticles.C index 4f262a1fd..eca292e8e 100644 --- a/src/enzo/CommunicationCollectParticles.C +++ b/src/enzo/CommunicationCollectParticles.C @@ -215,6 +215,7 @@ int CommunicationCollectParticles(LevelHierarchyEntry *LevelArray[], TotalNumber = 0; TotalStars = 0; + APTotalNumber = 0; for (j = 0; j < NumberOfProcessors; j++) { TotalNumber += NumberToMove[j]; TotalStars += StarsToMove[j]; diff --git a/src/enzo/DepositParticleMassFlaggingField.C b/src/enzo/DepositParticleMassFlaggingField.C index 9f8c284bb..b6fbc9242 100644 --- a/src/enzo/DepositParticleMassFlaggingField.C +++ b/src/enzo/DepositParticleMassFlaggingField.C @@ -190,10 +190,6 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], MPI_SendListCount[proc] = NumberOfSends[proc]; } -// for (i = 0; i < TotalNumberOfSends; i++) -// printf("P%"ISYM" -- BB -- SendList[%"ISYM"]: %"ISYM" %"ISYM"\n", -// MyProcessorNumber, i, SendList[i].grid, SendList[i].proc); - // Sort by grid (destination) processor, then replace the // processor number with this processor number because the grid // processor needs it to post the receives. @@ -245,9 +241,6 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], for (i = 0; i < TotalNumberOfSends; i++) SendList[i].proc = MyProcessorNumber; -// for (i = 0; i < TotalNumberOfSends; i++) -// printf("P%"ISYM" -- SendList[%"ISYM"]: %"ISYM" %"ISYM"\n", -// MyProcessorNumber, i, SendList[i].grid, SendList[i].proc); #ifdef TIMING t0 = ReturnWallTime(); @@ -264,9 +257,6 @@ int DepositParticleMassFlaggingField(LevelHierarchyEntry* LevelArray[], printf("--> DPMFF: After Alltoallv :: %lg seconds\n", t1-t0); #endif -// for (i = 0; i < TotalNumberOfRecv; i++) -// printf("P%"ISYM" -- SharedList[%"ISYM"]: %"ISYM" %"ISYM"\n", -// MyProcessorNumber, i, SharedList[i].grid, SharedList[i].proc); delete [] NumberOfSends; delete [] MPI_SendListCount; diff --git a/src/enzo/Grid_SetParticleMassFlaggingField.C b/src/enzo/Grid_SetParticleMassFlaggingField.C index c61186c0e..f6e828843 100644 --- a/src/enzo/Grid_SetParticleMassFlaggingField.C +++ b/src/enzo/Grid_SetParticleMassFlaggingField.C @@ -59,13 +59,8 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, CommunicationDirection == COMMUNICATION_POST_RECEIVE)) return SUCCESS; -// printf("--> SetPMFlag[P%"ISYM"/%"ISYM"]: level %"ISYM", grid %"ISYM", " -// "comm_dir = %"ISYM", npart = %"ISYM"\n", -// MyProcessorNumber, ProcessorNumber, level, GridNum, -// CommunicationDirection, NumberOfParticles); - #ifdef USE_MPI - MPI_Datatype DataType = (sizeof(float) == 4) ? MPI_FLOAT : MPI_DOUBLE; + MPI_Datatype DataType = FloatDataType; MPI_Arg Count; MPI_Arg Source; float *buffer = NULL; @@ -94,7 +89,7 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, // given range and has particles. if (MyProcessorNumber != ProcessorNumber && (MyProcessorNumber < StartProc || MyProcessorNumber >= EndProc || - NumberOfParticles == 0 && NumberOfActiveParticles == 0)) + (NumberOfParticles == 0 && NumberOfActiveParticles == 0))) return SUCCESS; /***********************************************************************/ @@ -160,11 +155,9 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, #ifdef USE_MPI if (MyProcessorNumber != ProcessorNumber) { - //MPI_Tag = Return_MPI_Tag(GridNum, MyProcessorNumber); -// printf("----> SetPMFlag[P%"ISYM"/%"ISYM"]: sending %"ISYM" floats.\n", -// MyProcessorNumber, ProcessorNumber, size); + MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); CommunicationBufferedSend(ParticleMassFlaggingField, size, DataType, - ProcessorNumber, MPI_SENDPMFLAG_TAG, + ProcessorNumber, Mtag, MPI_COMM_WORLD, size*sizeof(float)); delete [] ParticleMassFlaggingField; ParticleMassFlaggingField = NULL; @@ -194,21 +187,17 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, Count = size; for (proc = 0; proc < NumberOfSends; proc++) { Source = SendProcs[proc]; -// printf("----> SetPMFlag[P%"ISYM"/%"ISYM"]: " -// "posting receive for %"ISYM" floats, coming from P%"ISYM".\n", -// MyProcessorNumber, ProcessorNumber, size, Source); if (Source >= StartProc && Source < EndProc) { buffer = new float[size]; - MPI_Irecv(buffer, Count, DataType, Source, MPI_SENDPMFLAG_TAG, MPI_COMM_WORLD, + MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); + MPI_Irecv(buffer, Count, DataType, Source, Mtag, MPI_COMM_WORLD, CommunicationReceiveMPI_Request+CommunicationReceiveIndex); CommunicationReceiveGridOne[CommunicationReceiveIndex] = this; CommunicationReceiveGridTwo[CommunicationReceiveIndex] = NULL; CommunicationReceiveCallType[CommunicationReceiveIndex] = 13; CommunicationReceiveBuffer[CommunicationReceiveIndex] = buffer; -// CommunicationReceiveArgumentInt[0][CommunicationReceiveIndex] = StartProc; -// CommunicationReceiveArgumentInt[1][CommunicationReceiveIndex] = EndProc; CommunicationReceiveDependsOn[CommunicationReceiveIndex] = CommunicationReceiveCurrentDependsOn; CommunicationReceiveIndex++; From 00435b2f569f58116003e9148de9fb9fc348f2e6 Mon Sep 17 00:00:00 2001 From: John Regan Date: Thu, 22 Jul 2021 09:36:50 +0200 Subject: [PATCH 098/115] Adding fallback option to first order interpolation --- src/enzo/ActiveParticle_SmartStar.C | 481 +++++++++--------- src/enzo/ActiveParticle_SmartStar.h | 2 +- src/enzo/Grid_InterpolateBoundaryFromParent.C | 36 +- src/enzo/Grid_InterpolateFieldValues.C | 37 +- 4 files changed, 305 insertions(+), 251 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index dfb0690a3..67e52cb54 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -9,7 +9,7 @@ #include "ActiveParticle_SmartStar.h" #include "phys_constants.h" -#define SSDEBUG 1 +#define SSDEBUG 0 #define SSDEBUG_TOTALMASS 0 #define DYNAMIC_ACCRETION_RADIUS 0 @@ -804,12 +804,13 @@ grid* ConstructFeedbackZone(ActiveParticleType* ThisParticle, int FeedbackRadius int DistributeFeedbackZone(grid* FeedbackZone, HierarchyEntry** Grids, int NumberOfGrids, int SendField); - +#define MAX_NUMBER_NEW_APS 100 int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticles, ActiveParticleList& ParticleList, LevelHierarchyEntry *LevelArray[], int ThisLevel) { - int *SSparticles = new int(nParticles); + //int *SSparticles = new int(nParticles); + int SSparticles[MAX_NUMBER_NEW_APS]; /* Assuming no more than 100 new particles per cycle */ float StellarMasstoRemove = 0.0, CellDensityAfterFormation = 0.0; FLOAT Time = LevelArray[ThisLevel]->GridData->ReturnTime(); float DensityUnits, LengthUnits, TemperatureUnits, TimeUnits, @@ -820,16 +821,15 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle MassUnits = DensityUnits * POW(LengthUnits,3); float tdyn_code = StarClusterMinDynamicalTime/(TimeUnits/yr_s); - //printf("%s: nParticles = %d\n", __FUNCTION__, nParticles); - for (int i = 0; i < nParticles; i++) + for (int i = 0; i < MAX_NUMBER_NEW_APS; i++) SSparticles[i] = -1; - //return SUCCESS; //works /* * Order particles in order of SMS, PopIII, PopII * SMS first since they have the highest accretion rates and hence * should be forming first */ int k = 0, num_new_sms_stars = 0, num_new_popiii_stars = 0, num_new_popii_stars = 0; + for (int i = 0; i < nParticles; i++) { grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { @@ -845,11 +845,9 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { ActiveParticleType_SmartStar* SS; - printf("%s: P%d: ParticleList[i] = %p\t SS->TimeIndex = %d\n", __FUNCTION__, MyProcessorNumber, ParticleList[i], SS->TimeIndex); SS = static_cast(ParticleList[i]); if(SS->ParticleClass == POPIII && SS->TimeIndex == 0) { - printf("POPIII: Setting SSparticles[%d] = %d\n", k, i); fflush(stdout); - SSparticles[k++] = 6; //i; + SSparticles[k++] = i; num_new_popiii_stars++; } } @@ -865,241 +863,237 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle } } } - //return SUCCESS; /*breaks*/ + int num_new_stars = num_new_sms_stars + num_new_popiii_stars + num_new_popii_stars; if(num_new_stars == 0) return SUCCESS; - printf("%s: JR: num_new_stars = %d\n", __FUNCTION__, num_new_stars); - printf("num_new_sms_stars = %d\t num_new_popiii_stars = %d\t num_new_popii_stars = %d\n", num_new_sms_stars , num_new_popiii_stars , num_new_popii_stars); - fflush(stdout); + for (int k = 0; k < num_new_stars; k++) { int pindex = SSparticles[k]; grid* APGrid = ParticleList[pindex]->ReturnCurrentGrid(); if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { - printf("P%d\t num_new_stars = %d\n", MyProcessorNumber, num_new_stars); fflush(stdout); ActiveParticleType_SmartStar* SS; SS = static_cast(ParticleList[pindex]); - /* * Only interested in newly formed particles */ if(SS->TimeIndex != 0) continue; - FLOAT dx = APGrid->CellWidth[0][0]; - FLOAT CellVolume = dx*dx*dx; - int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; - if (APGrid->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) - { - ENZO_FAIL("Error in IdentifyPhysicalQuantities."); - } - int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, - DINum, DIINum, HDINum; - if (MultiSpecies) - if (APGrid->IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, - HeIIINum, HMNum, H2INum, H2IINum, DINum, - DIINum, HDINum) == FAIL) { - ENZO_FAIL("Error in grid->IdentifySpeciesFields."); - } - FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc - float *density = APGrid->BaryonField[DensNum]; - int cellindex_x = (SS->pos[0] - APGrid->CellLeftEdge[0][0])/dx, - cellindex_y = (SS->pos[1] - APGrid->CellLeftEdge[1][0])/dx, - cellindex_z = (SS->pos[2] - APGrid->CellLeftEdge[2][0])/dx; - - int cellindex = APGrid->GetIndex(cellindex_x, cellindex_y, cellindex_z); - float DensityThreshold = ActiveParticleDensityThreshold*mh/DensityUnits; - + FLOAT dx = APGrid->CellWidth[0][0]; + FLOAT CellVolume = dx*dx*dx; + int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; + if (APGrid->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, + Vel3Num, TENum) == FAIL) + { + ENZO_FAIL("Error in IdentifyPhysicalQuantities."); + } + int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, + DINum, DIINum, HDINum; + if (MultiSpecies) + if (APGrid->IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, + HeIIINum, HMNum, H2INum, H2IINum, DINum, + DIINum, HDINum) == FAIL) { + ENZO_FAIL("Error in grid->IdentifySpeciesFields."); + } + FLOAT dx_pc = dx*LengthUnits/pc_cm; //in pc + float *density = APGrid->BaryonField[DensNum]; + int cellindex_x = (SS->pos[0] - APGrid->CellLeftEdge[0][0])/dx, + cellindex_y = (SS->pos[1] - APGrid->CellLeftEdge[1][0])/dx, + cellindex_z = (SS->pos[2] - APGrid->CellLeftEdge[2][0])/dx; + + int cellindex = APGrid->GetIndex(cellindex_x, cellindex_y, cellindex_z); + float DensityThreshold = ActiveParticleDensityThreshold*mh/DensityUnits; + #if JEANSREFINEMENT - bool JeansRefinement = false; - for (int method = 0; method < MAX_FLAGGING_METHODS; method++) - if (CellFlaggingMethod[method] == 6) - JeansRefinement = true; - if (JeansRefinement) { - int size = APGrid->GetGridSize(); - float *Temperature = new float[size](); - APGrid->ComputeTemperatureField(Temperature); - float CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : Temperature[cellindex]; - int JeansFactor = JEANS_FACTOR; - float JeansDensityUnitConversion = (Gamma*pi*kboltz) / (Mu*mh*GravConst); - float JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / - POW(LengthUnits*dx*JeansFactor,2); - JeansDensity /= DensityUnits; - DensityThreshold = min(DensityThreshold,JeansDensity); - } + bool JeansRefinement = false; + for (int method = 0; method < MAX_FLAGGING_METHODS; method++) + if (CellFlaggingMethod[method] == 6) + JeansRefinement = true; + if (JeansRefinement) { + int size = APGrid->GetGridSize(); + float *Temperature = new float[size](); + APGrid->ComputeTemperatureField(Temperature); + float CellTemperature = (JeansRefinementColdTemperature > 0) ? JeansRefinementColdTemperature : Temperature[cellindex]; + int JeansFactor = JEANS_FACTOR; + float JeansDensityUnitConversion = (Gamma*pi*kboltz) / (Mu*mh*GravConst); + float JeansDensity = JeansDensityUnitConversion * 1.01 * CellTemperature / + POW(LengthUnits*dx*JeansFactor,2); + JeansDensity /= DensityUnits; + DensityThreshold = min(DensityThreshold,JeansDensity); + } #endif - float ParticleDensity = density[cellindex] - DensityThreshold; - float newcelldensity = density[cellindex] - ParticleDensity; - - if(SMS == SS->ParticleClass) { - - if(dx_pc <= SMS_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ - density[cellindex] = newcelldensity; - SS->BirthTime = APGrid->ReturnTime(); - SS->Mass = ParticleDensity; - SS->oldmass = 0.0; - if(ParticleDensity < 0.0) { - printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); - printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); - printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); - printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); - ENZO_FAIL("Particle Density is negative. Oh dear.\n"); - } - continue; + float ParticleDensity = density[cellindex] - DensityThreshold; + float newcelldensity = density[cellindex] - ParticleDensity; + + if(SMS == SS->ParticleClass) { + + if(dx_pc <= SMS_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ + density[cellindex] = newcelldensity; + SS->BirthTime = APGrid->ReturnTime(); + SS->Mass = ParticleDensity; + SS->oldmass = 0.0; + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + ENZO_FAIL("Particle Density is negative. Oh dear.\n"); } + continue; } - - else if(POPIII == SS->ParticleClass) { - if(dx_pc <= POPIII_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ - density[cellindex] = newcelldensity; - SS->BirthTime = APGrid->ReturnTime(); - SS->Mass = ParticleDensity; - SS->oldmass = 0.0; - if(ParticleDensity < 0.0) { - printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); - printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); - printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); - printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); - ENZO_FAIL("Particle Density is negative. Oh dear.\n"); - } + } + + else if(POPIII == SS->ParticleClass) { + if(dx_pc <= POPIII_RESOLUTION) { /* Accrete as normal - just remove mass from the cell */ + density[cellindex] = newcelldensity; + SS->BirthTime = APGrid->ReturnTime(); + SS->Mass = ParticleDensity; + SS->oldmass = 0.0; + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + ENZO_FAIL("Particle Density is negative. Oh dear.\n"); + } #if SSDEBUG - printf("%s: Particle with initial mass %e (%e) Msolar created\n", __FUNCTION__, - SS->Mass*dx*dx*dx*MassUnits/SolarMass, SS->Mass); + printf("%s: Particle with initial mass %e (%e) Msolar created\n", __FUNCTION__, + SS->Mass*dx*dx*dx*MassUnits/SolarMass, SS->Mass); #endif - continue; - } + continue; } - else if(POPII == SS->ParticleClass) { - /* - * For PopII stars we do this if the mass exceeds the minimum mass - */ - float PopIIMass = SS->Mass*dx*dx*dx*MassUnits/SolarMass; - if(PopIIMass > StarClusterMinimumMass) { - density[cellindex] = (1 - StarClusterFormEfficiency)*density[cellindex]; - SS->BirthTime = APGrid->ReturnTime(); - SS->Mass = StarClusterFormEfficiency*density[cellindex]; - SS->oldmass = 0.0; - if(ParticleDensity < 0.0) { - printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); - printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); - printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); - printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); - ENZO_FAIL("Particle Density is negative. Oh dear.\n"); - } - printf("POPII: cellindex %d updated - next.\n\n", cellindex); - continue; + } + else if(POPII == SS->ParticleClass) { + /* + * For PopII stars we do this if the mass exceeds the minimum mass + */ + float PopIIMass = SS->Mass*dx*dx*dx*MassUnits/SolarMass; + if(PopIIMass > StarClusterMinimumMass) { + density[cellindex] = (1 - StarClusterFormEfficiency)*density[cellindex]; + SS->BirthTime = APGrid->ReturnTime(); + SS->Mass = StarClusterFormEfficiency*density[cellindex]; + SS->oldmass = 0.0; + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + ENZO_FAIL("Particle Density is negative. Oh dear.\n"); } - } - - /* - * If the formation mass is below a resolution based threshold - * Remove mass from grid and replace by a uniform density sphere which accounts for the - * subgrid ionisation that has taken place and accounts for the mass that should have been - * accreted. - */ - - /*********************************************************************** + printf("POPII: cellindex %d updated - next.\n\n", cellindex); + continue; + } + } + + /* + * If the formation mass is below a resolution based threshold + * Remove mass from grid and replace by a uniform density sphere which accounts for the + * subgrid ionisation that has taken place and accounts for the mass that should have been + * accreted. + */ + + /*********************************************************************** For star formation, we need to find a sphere with enough mass to accrete. We step out by a cell width when searching. - ***********************************************************************/ - printf("%s: Low resolution run.....\n", __FUNCTION__); - if(ParticleDensity < 0.0) { - printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); - printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); - printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); - printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); - /* Mark particle for deletion */ - SS->WillDelete = true; - //ParticleList[pindex]->DisableParticle(LevelArray, MyProcessorNumber); - //ParticleList.erase(pindex); - - printf("P%d: Too late. Star is destroyed by surrounding SF. Particle %d deleted\n", - MyProcessorNumber, pindex); - continue; - } - FLOAT Radius = 0.0; - int feedback_flag = -99999; - float MassEnclosed = 0; - float Metallicity2 = 0; - float Metallicity3 = 0; - float ColdGasMass = 0; - float AvgVelocity[MAX_DIMENSION]; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] = 0.0; - bool SphereTooSmall = true; - float ShellMass, ShellMetallicity2, ShellMetallicity3, ShellColdGasMass, - ShellVelocity[MAX_DIMENSION]; - while (SphereTooSmall) { - Radius += APGrid->CellWidth[0][0]; - bool IsSphereContained = SS->SphereContained(LevelArray, ThisLevel, Radius); - - if (IsSphereContained == false) - break; - ShellMass = 0; - ShellMetallicity2 = 0; - ShellMetallicity3 = 0; - ShellColdGasMass = 0; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - ShellVelocity[dim] = 0.0; - - LevelHierarchyEntry *Temp = NULL; - Temp = LevelArray[ThisLevel]; - while (Temp != NULL) { - Temp->GridData->GetEnclosedMassInShell(SS->pos, Radius-APGrid->CellWidth[0][0], Radius, - ShellMass, ShellMetallicity2, - ShellMetallicity3, - ShellColdGasMass, ShellVelocity, - -1); - - Temp = Temp->NextGridThisLevel; - } // END: Grids - - MassEnclosed += ShellMass; - ColdGasMass += ShellColdGasMass; - // Must first make mass-weighted, then add shell mass-weighted - // (already done in GetEnclosedMassInShell) velocity and - // metallicity. We divide out the mass after checking if mass is - // non-zero. - Metallicity2 = Metallicity2 * (MassEnclosed - ShellMass) + ShellMetallicity2; - Metallicity3 = Metallicity3 * (MassEnclosed - ShellMass) + ShellMetallicity3; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] = AvgVelocity[dim] * (MassEnclosed - ShellMass) + - ShellVelocity[dim]; - printf("MassEnclosed = %e Msolar\n", MassEnclosed); fflush(stdout); - if (MassEnclosed == 0) { - IsSphereContained = false; - return SUCCESS; - } - - Metallicity2 /= MassEnclosed; - Metallicity3 /= MassEnclosed; - for (int dim = 0; dim < MAX_DIMENSION; dim++) - AvgVelocity[dim] /= MassEnclosed; - - - /* Now remove mass based on star particle type - * Note that while SS->Mass gets set here with the - * mass of the particle in solar masses it is reset - * below in code density units. - */ - printf("ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); - if(POPIII == SS->ParticleClass) { - SS->AssignMassFromIMF(); - SS->StellarAge = SS->RadiationLifetime; - SphereTooSmall = MassEnclosed < (2*SS->Mass); - // to make the total mass PopIIIStarMass - StellarMasstoRemove = SS->Mass; // [Msolar] - printf("%s: Mass = %e Msolar\t StellarAge = %e Myr\n", __FUNCTION__, - SS->Mass, SS->StellarAge*TimeUnits/Myr_s); - SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/CellVolume; //code density - SS->oldmass = 0.0; - } - else if(SMS == SS->ParticleClass) { + ***********************************************************************/ + printf("%s: Low resolution run.....\n", __FUNCTION__); + if(ParticleDensity < 0.0) { + printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); + printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); + printf("DensityThreshold = %e cm^-3\n", DensityThreshold*DensityUnits/mh); + printf("SS->ParticleClass = %d\n", SS->ParticleClass); fflush(stdout); + /* Mark particle for deletion */ + SS->WillDelete = true; + //ParticleList[pindex]->DisableParticle(LevelArray, MyProcessorNumber); + //ParticleList.erase(pindex); + + printf("P%d: Too late. Star is destroyed by surrounding SF. Particle %d deleted\n", + MyProcessorNumber, pindex); + continue; + } + FLOAT Radius = 0.0; + int feedback_flag = -99999; + float MassEnclosed = 0; + float Metallicity2 = 0; + float Metallicity3 = 0; + float ColdGasMass = 0; + float AvgVelocity[MAX_DIMENSION]; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] = 0.0; + bool SphereTooSmall = true; + float ShellMass, ShellMetallicity2, ShellMetallicity3, ShellColdGasMass, + ShellVelocity[MAX_DIMENSION]; + while (SphereTooSmall) { + Radius += APGrid->CellWidth[0][0]; + bool IsSphereContained = SS->SphereContained(LevelArray, ThisLevel, Radius); + + if (IsSphereContained == false) + break; + ShellMass = 0; + ShellMetallicity2 = 0; + ShellMetallicity3 = 0; + ShellColdGasMass = 0; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + ShellVelocity[dim] = 0.0; + + LevelHierarchyEntry *Temp = NULL; + Temp = LevelArray[ThisLevel]; + while (Temp != NULL) { + Temp->GridData->GetEnclosedMassInShell(SS->pos, Radius-APGrid->CellWidth[0][0], Radius, + ShellMass, ShellMetallicity2, + ShellMetallicity3, + ShellColdGasMass, ShellVelocity, + -1); + + Temp = Temp->NextGridThisLevel; + } // END: Grids + + MassEnclosed += ShellMass; + ColdGasMass += ShellColdGasMass; + // Must first make mass-weighted, then add shell mass-weighted + // (already done in GetEnclosedMassInShell) velocity and + // metallicity. We divide out the mass after checking if mass is + // non-zero. + Metallicity2 = Metallicity2 * (MassEnclosed - ShellMass) + ShellMetallicity2; + Metallicity3 = Metallicity3 * (MassEnclosed - ShellMass) + ShellMetallicity3; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] = AvgVelocity[dim] * (MassEnclosed - ShellMass) + + ShellVelocity[dim]; + printf("MassEnclosed = %e Msolar\n", MassEnclosed); fflush(stdout); + if (MassEnclosed == 0) { + IsSphereContained = false; + return SUCCESS; + } + + Metallicity2 /= MassEnclosed; + Metallicity3 /= MassEnclosed; + for (int dim = 0; dim < MAX_DIMENSION; dim++) + AvgVelocity[dim] /= MassEnclosed; + + + /* Now remove mass based on star particle type + * Note that while SS->Mass gets set here with the + * mass of the particle in solar masses it is reset + * below in code density units. + */ + + if(POPIII == SS->ParticleClass) { + SS->AssignMassFromIMF(); + SS->StellarAge = SS->RadiationLifetime; + SphereTooSmall = MassEnclosed < (2*SS->Mass); + // to make the total mass PopIIIStarMass + StellarMasstoRemove = SS->Mass; // [Msolar] + printf("%s: Mass = %e Msolar\t StellarAge = %e Myr\n", __FUNCTION__, + SS->Mass, SS->StellarAge*TimeUnits/Myr_s); + SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/CellVolume; //code density + SS->oldmass = 0.0; + } + else if(SMS == SS->ParticleClass) { /* * We take here a fiducial SMS mass of 10,000 Msolar * since in this low resolution case accretion is @@ -1114,28 +1108,28 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/CellVolume; //code density SS->oldmass = 0.0; } - else if(POPII == SS->ParticleClass) { - float AvgDensity = (float) - (double(SolarMass * MassEnclosed) / - double(4*pi/3.0 * pow(Radius*LengthUnits, 3))); /* cgs density */ - float DynamicalTime = sqrt((3.0 * pi) / (32.0 * GravConst * AvgDensity)) / - TimeUnits; - float ColdGasFraction = ColdGasMass / MassEnclosed; - StellarMasstoRemove = ColdGasFraction * StarClusterFormEfficiency * MassEnclosed; //[Msolar] - SphereTooSmall = DynamicalTime < tdyn_code; - SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/CellVolume; //code density - SS->oldmass = 0.0; - SS->RadiationLifetime = 2e7*yr_s/TimeUnits; /* 20 Myr lifetime */ - } - // Remove the stellar mass from the sphere and distribute the - // gas evenly in the sphere since this is what will happen once - // the I-front passes through it. - - CellDensityAfterFormation = (float) - (double(SolarMass * (MassEnclosed - StellarMasstoRemove)) / - double(4.0*pi/3.0 * POW(Radius*LengthUnits, 3)) / - DensityUnits); /* converted to code density */ - + else if(POPII == SS->ParticleClass) { + float AvgDensity = (float) + (double(SolarMass * MassEnclosed) / + double(4*pi/3.0 * pow(Radius*LengthUnits, 3))); /* cgs density */ + float DynamicalTime = sqrt((3.0 * pi) / (32.0 * GravConst * AvgDensity)) / + TimeUnits; + float ColdGasFraction = ColdGasMass / MassEnclosed; + StellarMasstoRemove = ColdGasFraction * StarClusterFormEfficiency * MassEnclosed; //[Msolar] + SphereTooSmall = DynamicalTime < tdyn_code; + SS->Mass = (StellarMasstoRemove*SolarMass/MassUnits)/CellVolume; //code density + SS->oldmass = 0.0; + SS->RadiationLifetime = 2e7*yr_s/TimeUnits; /* 20 Myr lifetime */ + } + // Remove the stellar mass from the sphere and distribute the + // gas evenly in the sphere since this is what will happen once + // the I-front passes through it. + + CellDensityAfterFormation = (float) + (double(SolarMass * (MassEnclosed - StellarMasstoRemove)) / + double(4.0*pi/3.0 * POW(Radius*LengthUnits, 3)) / + DensityUnits); /* converted to code density */ + } /* end while(SphereTooSmall) */ #ifdef NOT_NECESSARY /* Don't allow the sphere to be too large (2x leeway) */ @@ -1160,11 +1154,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle * loop to find sufficient enclosed mass. */ SS->InfluenceRadius = Radius; - printf("%s: Particle Mass = %1.1f Msolar\n", __FUNCTION__, SS->Mass); - printf("%s: Particle Class = %d\n", __FUNCTION__, SS->ParticleClass); - printf("%s: Remove mass from sphere of radius %lf pc\n", __FUNCTION__, Radius*LengthUnits/pc_cm); - fflush(stdout); - + /* Update cell information */ int index = 0; FLOAT delx = 0.0, dely = 0.0, delz = 0.0, radius2 = 0.0, DomainWidth[MAX_DIMENSION]; @@ -1176,8 +1166,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle MetalIINum, MBHColourNum, Galaxy1ColourNum, Galaxy2ColourNum) == FAIL) ENZO_FAIL("Error in grid->IdentifyColourFields.\n"); - printf("%s: Colour Fields Identified\n", __FUNCTION__); fflush(stdout); - + MetalNum = max(Metal2Num, SNColourNum); MetallicityField = (MetalNum > 0) ? TRUE : FALSE; float metallicity = 0.0; @@ -1569,9 +1558,9 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, ActiveParticleType_SmartStar* SS; SS = static_cast(ParticleList[i]); #if SSDEBUG - printf("%s: deltatime = %f years\t TIMEGAP = %0.2f years\n", + printf("%s: deltatime = %f years\t TIMEGAP = %d timesteps\n", __FUNCTION__, (ctime - SS->AccretionRateTime[SS->TimeIndex])*TimeUnits/yr_s, - (float)TIMEGAP); + (int)TIMEGAP); #endif //We should update when the time between stored rates exceeds TIMEGAP diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 8fe876bf9..0f9ef0feb 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -33,7 +33,7 @@ #define MAXACCRETIONRADIUS 128 /* Times the minimum cell width (currently not used) */ #define ACCRETIONRADIUS 4 #define NUMRADIATIONBINS 5 -#define CRITICAL_ACCRETION_RATE 0.001 //Msolar/yr (Haemerlee et al (2018)) +#define CRITICAL_ACCRETION_RATE 0.005 //Msolar/yr (Haemerlee et al (2018)) #define TIMEGAP 100 // * timestep #define POPIII_RESOLUTION 0.001 //pc #define SMS_RESOLUTION 1.0 //pc diff --git a/src/enzo/Grid_InterpolateBoundaryFromParent.C b/src/enzo/Grid_InterpolateBoundaryFromParent.C index 88245cdae..62cf74588 100644 --- a/src/enzo/Grid_InterpolateBoundaryFromParent.C +++ b/src/enzo/Grid_InterpolateBoundaryFromParent.C @@ -358,7 +358,23 @@ int grid::InterpolateBoundaryFromParent(grid *ParentGrid) this->GridLeftEdge[0], this->GridLeftEdge[1], this->GridLeftEdge[2], this->GridRightEdge[0], this->GridRightEdge[1], this->GridRightEdge[2]); - ENZO_FAIL(""); + /* Give interpolation a second chance */ + if(InterpolationMethod == SecondOrderA) { + printf("%s: Falling back to first order interpolation\n", __FUNCTION__); fflush(stdout); + int FallBackInterpolationMethod = FirstOrderA; + interp_error = FALSE; + FORTRAN_NAME(interpolate)(&GridRank, + ParentTemp[densfield], ParentTempDim, + ParentTempStartIndex, ParentTempEndIndex, + Refinement, + TemporaryDensityField, TempDim, ZeroVector, Work, + &FallBackInterpolationMethod, + &SecondOrderBFlag[densfield], &interp_error); + if (interp_error) + ENZO_FAIL(""); + } + else + ENZO_FAIL(""); } } // ENDIF !AccelerationHack @@ -407,7 +423,23 @@ int grid::InterpolateBoundaryFromParent(grid *ParentGrid) this->GridLeftEdge[0], this->GridLeftEdge[1], this->GridLeftEdge[2], this->GridRightEdge[0], this->GridRightEdge[1], this->GridRightEdge[2]); - ENZO_FAIL(""); + /* Give interpolation a second chance */ + if(FieldInterpolationMethod == SecondOrderA) { + printf("%s: Falling back to first order interpolation\n", __FUNCTION__); fflush(stdout); + int FallBackInterpolationMethod = FirstOrderA; + interp_error = FALSE; + FORTRAN_NAME(interpolate)(&GridRank, + ParentTemp[densfield], ParentTempDim, + ParentTempStartIndex, ParentTempEndIndex, + Refinement, + TemporaryField, TempDim, ZeroVector, Work, + &FallBackInterpolationMethod, + &SecondOrderBFlag[field], &interp_error); + if (interp_error) + ENZO_FAIL(""); + } + else + ENZO_FAIL(""); } } diff --git a/src/enzo/Grid_InterpolateFieldValues.C b/src/enzo/Grid_InterpolateFieldValues.C index 611da5c24..d575eb15c 100644 --- a/src/enzo/Grid_InterpolateFieldValues.C +++ b/src/enzo/Grid_InterpolateFieldValues.C @@ -333,7 +333,23 @@ int grid::InterpolateFieldValues(grid *ParentGrid this->GridLeftEdge[0], this->GridLeftEdge[1], this->GridLeftEdge[2], this->GridRightEdge[0], this->GridRightEdge[1], this->GridRightEdge[2]); - ENZO_FAIL("interpolation error"); + /* Give interpolation a second chance */ + if(InterpolationMethod == SecondOrderA) { + printf("%s: Falling back to first order interpolation\n", __FUNCTION__); fflush(stdout); + int FallBackInterpolationMethod = FirstOrderA; + interp_error = FALSE; + FORTRAN_NAME(interpolate)(&GridRank, + ParentTemp[densfield], ParentTempDim, + ParentTempStartIndex, ParentTempEndIndex, + Refinement, + TemporaryDensityField, TempDim, ZeroVector, Work, + &FallBackInterpolationMethod, + &SecondOrderBFlag[densfield], &interp_error); + if (interp_error) + ENZO_FAIL("interpolation error"); + } + else + ENZO_FAIL("interpolation error"); } @@ -383,7 +399,24 @@ int grid::InterpolateFieldValues(grid *ParentGrid this->GridLeftEdge[0], this->GridLeftEdge[1], this->GridLeftEdge[2], this->GridRightEdge[0], this->GridRightEdge[1], this->GridRightEdge[2]); - ENZO_FAIL("interpolation error"); + /* Give interpolation a second chance */ + if(FieldInterpolationMethod == SecondOrderA) { + printf("%s: Falling back to first order interpolation for field %s\n", + __FUNCTION__, DataLabel[field]); fflush(stdout); + int FallBackInterpolationMethod = FirstOrderA; + interp_error = FALSE; + FORTRAN_NAME(interpolate)(&GridRank, + ParentTemp[densfield], ParentTempDim, + ParentTempStartIndex, ParentTempEndIndex, + Refinement, + TemporaryField, TempDim, ZeroVector, Work, + &FallBackInterpolationMethod, + &SecondOrderBFlag[densfield], &interp_error); + if (interp_error) + ENZO_FAIL("interpolation error"); + } + else + ENZO_FAIL("interpolation error"); } } From 770e3c099aeef12a349658d46724f029216d5c6a Mon Sep 17 00:00:00 2001 From: fearmayo Date: Tue, 24 Aug 2021 15:30:54 +0200 Subject: [PATCH 099/115] Debugging the MPI errors that cropped up --- src/enzo/ActiveParticle_SmartStar.C | 6 ++--- src/enzo/Grid_SetParticleMassFlaggingField.C | 25 +++++++------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 13be49ab3..8a34eedf0 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -804,12 +804,12 @@ grid* ConstructFeedbackZone(ActiveParticleType* ThisParticle, int FeedbackRadius int DistributeFeedbackZone(grid* FeedbackZone, HierarchyEntry** Grids, int NumberOfGrids, int SendField); - +#define MAX_NUMBER_NEW_APS 100 int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticles, ActiveParticleList& ParticleList, LevelHierarchyEntry *LevelArray[], int ThisLevel) { - int *SSparticles = new int(nParticles); + int SSparticles[MAX_NUMBER_NEW_APS]; /* Assuming no more than 100 new particles per cycle */ float StellarMasstoRemove = 0.0, CellDensityAfterFormation = 0.0; /* Skip accretion if we're not on the maximum refinement level. This should only ever happen right after creation and then @@ -827,7 +827,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle MassUnits = DensityUnits * POW(LengthUnits,3); float tdyn_code = StarClusterMinDynamicalTime/(TimeUnits/yr_s); - for (int i = 0; i < nParticles; i++) + for (int i = 0; i < MAX_NUMBER_NEW_APS; i++) SSparticles[i] = -1; /* * Order particles in order of SMS, PopIII, PopII diff --git a/src/enzo/Grid_SetParticleMassFlaggingField.C b/src/enzo/Grid_SetParticleMassFlaggingField.C index c61186c0e..c88ca0a87 100644 --- a/src/enzo/Grid_SetParticleMassFlaggingField.C +++ b/src/enzo/Grid_SetParticleMassFlaggingField.C @@ -59,13 +59,10 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, CommunicationDirection == COMMUNICATION_POST_RECEIVE)) return SUCCESS; -// printf("--> SetPMFlag[P%"ISYM"/%"ISYM"]: level %"ISYM", grid %"ISYM", " -// "comm_dir = %"ISYM", npart = %"ISYM"\n", -// MyProcessorNumber, ProcessorNumber, level, GridNum, -// CommunicationDirection, NumberOfParticles); #ifdef USE_MPI - MPI_Datatype DataType = (sizeof(float) == 4) ? MPI_FLOAT : MPI_DOUBLE; + //MPI_Datatype DataType = (sizeof(float) == 4) ? MPI_FLOAT : MPI_DOUBLE; + MPI_Datatype DataType = FloatDataType; MPI_Arg Count; MPI_Arg Source; float *buffer = NULL; @@ -94,7 +91,7 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, // given range and has particles. if (MyProcessorNumber != ProcessorNumber && (MyProcessorNumber < StartProc || MyProcessorNumber >= EndProc || - NumberOfParticles == 0 && NumberOfActiveParticles == 0)) + (NumberOfParticles == 0 && NumberOfActiveParticles == 0))) return SUCCESS; /***********************************************************************/ @@ -160,11 +157,10 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, #ifdef USE_MPI if (MyProcessorNumber != ProcessorNumber) { - //MPI_Tag = Return_MPI_Tag(GridNum, MyProcessorNumber); -// printf("----> SetPMFlag[P%"ISYM"/%"ISYM"]: sending %"ISYM" floats.\n", -// MyProcessorNumber, ProcessorNumber, size); + //MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); + MPI_Arg Mtag = 2001; CommunicationBufferedSend(ParticleMassFlaggingField, size, DataType, - ProcessorNumber, MPI_SENDPMFLAG_TAG, + ProcessorNumber, Mtag, MPI_COMM_WORLD, size*sizeof(float)); delete [] ParticleMassFlaggingField; ParticleMassFlaggingField = NULL; @@ -194,21 +190,18 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, Count = size; for (proc = 0; proc < NumberOfSends; proc++) { Source = SendProcs[proc]; -// printf("----> SetPMFlag[P%"ISYM"/%"ISYM"]: " -// "posting receive for %"ISYM" floats, coming from P%"ISYM".\n", -// MyProcessorNumber, ProcessorNumber, size, Source); if (Source >= StartProc && Source < EndProc) { buffer = new float[size]; - MPI_Irecv(buffer, Count, DataType, Source, MPI_SENDPMFLAG_TAG, MPI_COMM_WORLD, + //MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); + MPI_Arg Mtag = 2001; + MPI_Irecv(buffer, Count, DataType, Source, Mtag, MPI_COMM_WORLD, CommunicationReceiveMPI_Request+CommunicationReceiveIndex); CommunicationReceiveGridOne[CommunicationReceiveIndex] = this; CommunicationReceiveGridTwo[CommunicationReceiveIndex] = NULL; CommunicationReceiveCallType[CommunicationReceiveIndex] = 13; CommunicationReceiveBuffer[CommunicationReceiveIndex] = buffer; -// CommunicationReceiveArgumentInt[0][CommunicationReceiveIndex] = StartProc; -// CommunicationReceiveArgumentInt[1][CommunicationReceiveIndex] = EndProc; CommunicationReceiveDependsOn[CommunicationReceiveIndex] = CommunicationReceiveCurrentDependsOn; CommunicationReceiveIndex++; From b449623b66659c96a47ba7a0f681be4440135107 Mon Sep 17 00:00:00 2001 From: fearmayo Date: Wed, 6 Oct 2021 11:37:51 +0200 Subject: [PATCH 100/115] fixed memory leak - simone --- src/enzo/ActiveParticle_SmartStar.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index a030e4609..333269728 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -1357,8 +1357,7 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, #if BONDIHOYLERADIUS /* Check what the Bondi-Hoyle radius - we should accrete out to that if required */ float mparticle = ParticleList[i]->ReturnMass()*dx*dx*dx; - float *vparticle = new float[3]; - vparticle = ParticleList[i]->ReturnVelocity(); + float *vparticle = ParticleList[i]->ReturnVelocity(); int size = APGrid->GetGridSize(); float *Temperature = new float[size](); @@ -1370,6 +1369,7 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, static_cast(ParticleList[i])->AccretionRadius*LengthUnits/pc, static_cast(ParticleList[i])->AccretionRadius/dx); } + delete [] Temperature; #endif // No need to communicate the accretion rate to the other CPUs since this particle is already local. /* Need to decide how often I update the accretion history */ From 15d950b3920297ae2405192379a482ab0bb1ca2a Mon Sep 17 00:00:00 2001 From: John Regan Date: Wed, 15 Dec 2021 15:03:57 +0100 Subject: [PATCH 101/115] Fixed memory leak in RT in runs with a large number of grids --- src/enzo/ActiveParticle_SmartStar.C | 5 +-- src/enzo/EvolvePhotons.C | 32 ++++++-------------- src/enzo/Grid_SetParticleMassFlaggingField.C | 24 ++++++++++----- src/enzo/RadiativeTransferLWShielding.C | 8 +++-- src/enzo/RadiativeTransferXRays.C | 8 +++-- src/enzo/RebuildHierarchy.C | 1 + 6 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 333269728..3dde2484d 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -9,7 +9,7 @@ #include "ActiveParticle_SmartStar.h" #include "phys_constants.h" -#define SSDEBUG 0 +#define SSDEBUG 1 #define SSDEBUG_TOTALMASS 0 #define DYNAMIC_ACCRETION_RADIUS 0 @@ -22,7 +22,7 @@ #define MASSTHRESHOLD 0.1 //Msolar in grid #define COOLING_TIME 0 #define NUMSSPARTICLETYPES 4 -#define JEANS_FACTOR 2 +#define JEANS_FACTOR 4 int DetermineSEDParameters(ActiveParticleType_SmartStar *SS,FLOAT Time, FLOAT dx); /* We need to make sure that we can operate on the grid, so this dance is @@ -742,6 +742,7 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel if(POPII == ThisParticle->ParticleClass) { ramptime = yr_s * StarClusterMinDynamicalTime / TimeUnits; } + /* Call Function to return SED parameters */ if(ThisParticle->DetermineSEDParameters(Time, dx) == FAIL) return FAIL; diff --git a/src/enzo/EvolvePhotons.C b/src/enzo/EvolvePhotons.C index 050216826..92fda9cc0 100644 --- a/src/enzo/EvolvePhotons.C +++ b/src/enzo/EvolvePhotons.C @@ -285,7 +285,10 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], } /* Initialize radiation fields */ - + int MinDepth = 0; + if(CosmologySimulationNumberOfInitialGrids > 1) + MinDepth = CosmologySimulationNumberOfInitialGrids - 1; + START_PERF(); for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= 0 ; lvl--) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) @@ -295,17 +298,9 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], END_PERF(0); /* create temperature fields for Compton heating */ - - if (RadiationXRayComptonHeating) - for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= 0 ; lvl--) - for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) - if (Temp->GridData->InitializeTemperatureFieldForComptonHeating() == FAIL) { - ENZO_FAIL("Error in InitializeTemperatureFieldForComptonHeating.\n"); - } - /* Initialize Temperature Field for H2 shielding approximation */ - if(RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) { - for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= 0 ; lvl--) + if(RadiationXRayComptonHeating == 1 || RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) { + for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= MinDepth ; lvl--) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->InitializeTemperatureFieldForH2Shield() == FAIL) { ENZO_FAIL("Error in InitializeTemperatureFieldForH2Shield.\n"); @@ -315,7 +310,7 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], #if USE_H2II_LOOKUP /* Initialize Temperature Field for H2II cross section approximation */ if(RadiativeTransferH2IIDiss == TRUE) { - for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= 0 ; lvl--) + for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= MinDepth; lvl--) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->InitializeTemperatureFieldForH2IICrossSection() == FAIL) { ENZO_FAIL("Error in InitializeTemperatureFieldForH2II.\n"); @@ -633,22 +628,15 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], END_PERF(9); /* Clean up temperature field */ - - if (RadiationXRayComptonHeating) - for (lvl = 0; lvl < MAX_DEPTH_OF_HIERARCHY-1; lvl++) - for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) - if (Temp->GridData->FinalizeTemperatureFieldForComptonHeating() == FAIL) { - ENZO_FAIL("Error in FinalizeTemperatureFieldForComptonHeating.\n"); - } - if (RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) - for (lvl = 0; lvl < MAX_DEPTH_OF_HIERARCHY-1; lvl++) + if (RadiationXRayComptonHeating == 1 || RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) + for (lvl = MinDepth; lvl < MAX_DEPTH_OF_HIERARCHY-1; lvl++) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->FinalizeTemperatureFieldForH2Shield() == FAIL) { ENZO_FAIL("Error in FinalizeTemperatureFieldForH2Shield.\n"); } #if USE_H2II_LOOKUP if (RadiativeTransferH2IIDiss == TRUE) { - for (lvl = 0; lvl < MAX_DEPTH_OF_HIERARCHY-1; lvl++) + for (lvl = MinDepth; lvl < MAX_DEPTH_OF_HIERARCHY-1; lvl++) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->FinalizeTemperatureFieldForH2IICrossSection() == FAIL) { ENZO_FAIL("Error in FinalizeTemperatureFieldForH2Shield.\n"); diff --git a/src/enzo/Grid_SetParticleMassFlaggingField.C b/src/enzo/Grid_SetParticleMassFlaggingField.C index 63078f93f..b012ab91d 100644 --- a/src/enzo/Grid_SetParticleMassFlaggingField.C +++ b/src/enzo/Grid_SetParticleMassFlaggingField.C @@ -30,8 +30,8 @@ #ifdef USE_MPI int CommunicationBufferedSend(void *buffer, int size, MPI_Datatype Type, int Target, int Tag, MPI_Comm CommWorld, int BufferSize); +MPI_Arg Return_MPI_Tag(int grid_num, int proc); #endif /* USE_MPI */ -int Return_MPI_Tag(int grid_num, int proc); /* The following is defined in Grid_DepositParticlePositions.C. */ @@ -156,8 +156,12 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, #ifdef USE_MPI if (MyProcessorNumber != ProcessorNumber) { - //MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); - MPI_Arg Mtag = 2001; + MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); + if(Mtag < 0) { + fprintf(stderr, "MPI_TAG = %d, level = %d, Grid ID = %d, proc = %d\n", + Mtag, level, this->ID, ProcessorNumber); + ENZO_FAIL(""); + } CommunicationBufferedSend(ParticleMassFlaggingField, size, DataType, ProcessorNumber, Mtag, MPI_COMM_WORLD, size*sizeof(float)); @@ -192,8 +196,12 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, if (Source >= StartProc && Source < EndProc) { buffer = new float[size]; - //MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); - MPI_Arg Mtag = 2001; + MPI_Arg Mtag = Return_MPI_Tag(this->ID, ProcessorNumber); + if (Mtag < 0) { + fprintf(stderr, "MPI_TAG = %d, level = %d, Grid ID = %d, proc = %d\n", + Mtag, level, this->ID, ProcessorNumber); + ENZO_FAIL(""); + } MPI_Irecv(buffer, Count, DataType, Source, Mtag, MPI_COMM_WORLD, CommunicationReceiveMPI_Request+CommunicationReceiveIndex); @@ -220,9 +228,9 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, int Return_MPI_Tag(int grid_num, int proc) { - // Return a somewhat-unique MPI tag for communication. The factors - // are prime. - return 6373*MPI_SENDPMFLAG_TAG + 4041*grid_num + 1973*proc; + // Return a somewhat-unique 16-bit MPI tag for communication. The factors + // are prime. + return (6373*MPI_SENDPMFLAG_TAG + 4041*grid_num + 1973*proc) % (1 << 16); } #ifdef UNUSED diff --git a/src/enzo/RadiativeTransferLWShielding.C b/src/enzo/RadiativeTransferLWShielding.C index db4f305a8..c1638bfd5 100644 --- a/src/enzo/RadiativeTransferLWShielding.C +++ b/src/enzo/RadiativeTransferLWShielding.C @@ -94,9 +94,11 @@ int grid::RadiativeTransferLWShielding(PhotonPackageEntry **PP, FLOAT &dP, * of the Draine & Bertoldi fitting formaula for H2 self shielding may be * more appropriate */ - - - b = sqrt(2.0*kboltz*BaryonField[TemperatureField][cellindex]/H2mass); // cm s^-1 + float T = 10000; + if(BaryonField[TemperatureField]) + T = BaryonField[TemperatureField][cellindex]; + + b = sqrt(2.0*kboltz*T/H2mass); // cm s^-1 b5 = b/1e5; // cm s^-1 if ((*PP)->ColumnDensity < THRESHOLD_DENSITY_DB37) { shield1 = 1; diff --git a/src/enzo/RadiativeTransferXRays.C b/src/enzo/RadiativeTransferXRays.C index 0e756040c..d0a491b50 100644 --- a/src/enzo/RadiativeTransferXRays.C +++ b/src/enzo/RadiativeTransferXRays.C @@ -71,10 +71,12 @@ int grid::RadiativeTransferComptonHeating(PhotonPackageEntry **PP, FLOAT *dPXray // nonrelativistic Klein-Nishina cross-section in Rybicki & Lightman (1979) xE = (*PP)->Energy/5.11e5; // h*nu/(m_e*c^2) xray_sigma = sigma_thompson * (1 - 2.*xE + 26./5.*xE*xE) * LengthUnits; //Equation 7.6a - + float T = 10000; + if(BaryonField[TemperatureField]) + T = BaryonField[TemperatureField][cellindex]; // also, nonrelativistic energy transfer in Ciotti & Ostriker (2001) - excess_heating = photonrate * 4 * kboltz * BaryonField[TemperatureField][cellindex] * xE; - ratioE = 4 * kboltz * BaryonField[TemperatureField][cellindex] * xE / (*PP)->Energy; + excess_heating = photonrate * 4 * kboltz * T * xE; + ratioE = 4 * kboltz * T * xE / (*PP)->Energy; tau = dN*xray_sigma; diff --git a/src/enzo/RebuildHierarchy.C b/src/enzo/RebuildHierarchy.C index 9aae166f5..a0f5aab24 100644 --- a/src/enzo/RebuildHierarchy.C +++ b/src/enzo/RebuildHierarchy.C @@ -273,6 +273,7 @@ int RebuildHierarchy(TopGridData *MetaData, Temp = LevelArray[0]; while (Temp != NULL) { Temp->GridData->DebugCheck("Before TransferParticles"); + Temp->GridData->SetGridID(grids); GridPointer[grids++] = Temp->GridData; Temp = Temp->NextGridThisLevel; } From e6d10630540137234a33fa55f3a50b377ee13228 Mon Sep 17 00:00:00 2001 From: John Regan Date: Mon, 25 Apr 2022 16:29:21 +0100 Subject: [PATCH 102/115] Very massive PopIII stars use thermal feedback --- src/enzo/ActiveParticleRoutines.C | 6 +++-- src/enzo/ActiveParticle_SmartStar.C | 27 +++++++++++++------ src/enzo/ActiveParticle_SmartStar.h | 4 +-- src/enzo/DetermineSEDParameters.C | 6 ++--- src/enzo/EvolvePhotons.C | 9 ++++--- .../Grid_ApplySmartStarParticleFeedback.C | 25 ++++++++++++----- src/enzo/RadiativeTransferLWShielding.C | 6 +++-- src/enzo/TemperatureFieldToolsH2Shielding.C | 24 ++++++++--------- 8 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/enzo/ActiveParticleRoutines.C b/src/enzo/ActiveParticleRoutines.C index 380a3cbe4..2118677b5 100644 --- a/src/enzo/ActiveParticleRoutines.C +++ b/src/enzo/ActiveParticleRoutines.C @@ -242,7 +242,9 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) { int dim; double ratio1, ratio2; - if((Mass == 0.0) || (a->Mass == 0.0)) + printf("%s: Merging particles with masses of (Code: %e) and (Code: %e)\n", + __FUNCTION__, Mass, a->Mass); + if((Mass <= 1e-6) || (a->Mass <= 1e-6)) return; ratio1 = (max(Mass, 1e-10)) / (max(1e-10,Mass) + max(1e-10, a->Mass)); ratio2 = 1.0 - ratio1; @@ -265,7 +267,7 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) AccretionRateTime[i] = a->AccretionRateTime[i]; AccretionRate[i] = a->AccretionRate[i]; } - RadiationLifetime = a->RadiationLifetime; + RadiationLifetime = max(RadiationLifetime, a->RadiationLifetime); StellarAge = a->StellarAge; } NotEjectedMass += a->NotEjectedMass; diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 3dde2484d..4d9cab07c 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -174,9 +174,9 @@ int ActiveParticleType_SmartStar::EvaluateFormation JeansRefinement = true; } -#if SSDEBUG - fprintf(stdout, "%s: Right half thinking of creating a SmartSink particle\n", __FUNCTION__); fflush(stdout); -#endif + //#if SSDEBUG + //fprintf(stdout, "%s: Right half thinking of creating a SmartSink particle\n", __FUNCTION__); fflush(stdout); + //#endif #if MASSTHRESHOLDCHECK JeansMass = thisGrid->CalculateJeansMass(data.DensNum, data.Temperature, data.DensityUnits); //In Msolar #endif @@ -452,8 +452,8 @@ int ActiveParticleType_SmartStar::EvaluateFormation /* Calculate initial accretion rate onto cell */ np->AccretionRate[0] = accrate; np->AccretionRateTime[0] = np->BirthTime; - - np->RadiationLifetime= 0.0; + //default to 20 Myrs (gets updated later in evolution) + np->RadiationLifetime= 2e7*yr_s/data.TimeUnits; np->StellarAge = 0.0; np->NotEjectedMass = 0.0; @@ -734,6 +734,10 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel MassConversion = (double) (dx*dx*dx * mfactor); //Converts to Solar Masses source = ThisParticle->RadiationSourceInitialize(); double PMass = ThisParticle->Mass*MassConversion; + + if(ThisParticle->ParticleClass == POPIII && PMass > 500.0) + continue; //No stellar radiative feedback in this case (thermal mode only) + float ramptime = 0.0; if(POPIII == ThisParticle->ParticleClass || SMS == ThisParticle->ParticleClass) { @@ -748,7 +752,7 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel return FAIL; source->LifeTime = ThisParticle->RadiationLifetime; - source->Luminosity = (ThisParticle->LuminosityPerSolarMass * LConv) * PMass; + source->Luminosity = (ThisParticle->LuminosityPerSolarMass * LConv) * min(PMass, 100000.0); source->RampTime = ramptime; source->EnergyBins = RadiationSEDNumberOfBins; source->Energy = new float[RadiationSEDNumberOfBins]; @@ -935,6 +939,7 @@ int ActiveParticleType_SmartStar::RemoveMassFromGridAfterFormation(int nParticle SS->BirthTime = APGrid->ReturnTime(); SS->Mass = ParticleDensity; SS->oldmass = 0.0; + SS->RadiationLifetime = 1.5e6*yr_s/TimeUnits; //Woods et al. 2020 if(ParticleDensity < 0.0) { printf("%s: cellindex = %d\n", __FUNCTION__, cellindex); printf("density[cellindex] = %e cm^-3\n", density[cellindex]*DensityUnits/mh); @@ -1440,6 +1445,11 @@ int ActiveParticleType_SmartStar::SmartStarParticleFeedback(int nParticles, for (i = 0; i < nParticles; i++) { + + /* No feedback on very first cycle */ + //if(static_cast(ParticleList[i])->TimeIndex < 2) + // break; + FLOAT AccretionRadius = static_cast(ParticleList[i])->AccretionRadius; grid* FeedbackZone = ConstructFeedbackZone(ParticleList[i], int(AccretionRadius/dx), dx, Grids, NumberOfGrids, ALL_FIELDS); @@ -1594,11 +1604,12 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, SS->TimeIndex = timeindex; fprintf(stdout, "old_mass = %e Msolar\t cmass = (%e code) %e Msolar\n", omass*MassConversion, cmass, cmass*MassConversion); - fprintf(stdout, "accrate = %1.2e Msolar/yr\t deltatime = %3.3f Myrs\t index = %d\t Particle Mass = %1.2e Msolar\t Age = %1.3f Myr\t Lifetime = %1.2f Myr\t Class = %d\n", + fprintf(stdout, "accrate = %1.2e Msolar/yr\t deltatime = %3.3f kyrs\t index = %d\t Particle Mass = %1.2e Msolar\t (code mass: %e) Age = %1.3f Myr\t Lifetime = %1.2f Myr\t Class = %d\n", (SS->AccretionRate[timeindex]*MassUnits/TimeUnits)*yr_s/SolarMass, - deltatime*TimeUnits/Myr_s, + deltatime*TimeUnits*1000.0/Myr_s, SS->TimeIndex, SS->ReturnMass()*MassConversion, + SS->ReturnMass(), Age*TimeUnits/Myr_s, SS->RadiationLifetime*TimeUnits/Myr_s, SS->ParticleClass); diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 0f9ef0feb..1d5b68eed 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -461,7 +461,7 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( if (SmartStarParticleFeedback(nParticles, ParticleList, dx, LevelArray, ThisLevel) == FAIL) ENZO_FAIL("SmartStar Particle Feedback failed. \n"); - + /* Clean any particles marked for deletion. * After each deletion I need to reloop and check it again. */ @@ -477,12 +477,12 @@ int ActiveParticleType_SmartStar::AfterEvolveLevel( } ActiveParticleFindAll(LevelArray, &nParticles, SmartStarID, ParticleList); + /* This applies all of the updates made above */ if (AssignActiveParticlesToGrids(ParticleList, nParticles, LevelArray) == FAIL) return FAIL; ParticleList.clear(); - } return SUCCESS; diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index 6843d1611..99ec78412 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -293,13 +293,13 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) this->LuminosityPerSolarMass = LSuperEdd/BHMass; } } - + /* Employ some ramping to stop numerical meltdown */ float Age = (Time - this->ReturnBirthTime())*TimeUnits/yr_s; - //printf("%s: BH Age = %e yrs\n", __FUNCTION__, Age); + //printf("%s: BH Age = %e yrs\n", __FUNCTION__, Age); fflush(stdout); if(Age < RAMPAGE) { float ramp = (Age/RAMPAGE); - //printf("%s: ramp = %g\n", __FUNCTION__, ramp); + //printf("%s: ramp = %g\n", __FUNCTION__, ramp); fflush(stdout); this->LuminosityPerSolarMass = this->LuminosityPerSolarMass*ramp; } /* Use values from the BHArray to set the SED Fractions */ diff --git a/src/enzo/EvolvePhotons.C b/src/enzo/EvolvePhotons.C index 92fda9cc0..a061ee739 100644 --- a/src/enzo/EvolvePhotons.C +++ b/src/enzo/EvolvePhotons.C @@ -299,7 +299,8 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], /* create temperature fields for Compton heating */ /* Initialize Temperature Field for H2 shielding approximation */ - if(RadiationXRayComptonHeating == 1 || RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) { + if(RadiationXRayComptonHeating == 1 || RadiativeTransferH2ShieldType == 1 || + ProblemType == 50 || RadiativeTransferOpticallyThinH2) { for (lvl = MAX_DEPTH_OF_HIERARCHY-1; lvl >= MinDepth ; lvl--) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->InitializeTemperatureFieldForH2Shield() == FAIL) { @@ -626,14 +627,16 @@ int EvolvePhotons(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], } /* ENDIF radiation */ END_PERF(9); - +#ifdef NO_NEED_NOW /* Clean up temperature field */ - if (RadiationXRayComptonHeating == 1 || RadiativeTransferH2ShieldType == 1 || ProblemType == 50 || RadiativeTransferOpticallyThinH2) + if (RadiationXRayComptonHeating == 1 || RadiativeTransferH2ShieldType == 1 || + ProblemType == 50 || RadiativeTransferOpticallyThinH2) for (lvl = MinDepth; lvl < MAX_DEPTH_OF_HIERARCHY-1; lvl++) for (Temp = LevelArray[lvl]; Temp; Temp = Temp->NextGridThisLevel) if (Temp->GridData->FinalizeTemperatureFieldForH2Shield() == FAIL) { ENZO_FAIL("Error in FinalizeTemperatureFieldForH2Shield.\n"); } +#endif #if USE_H2II_LOOKUP if (RadiativeTransferH2IIDiss == TRUE) { for (lvl = MinDepth; lvl < MAX_DEPTH_OF_HIERARCHY-1; lvl++) diff --git a/src/enzo/Grid_ApplySmartStarParticleFeedback.C b/src/enzo/Grid_ApplySmartStarParticleFeedback.C index 5b2cf9332..7699f0e45 100644 --- a/src/enzo/Grid_ApplySmartStarParticleFeedback.C +++ b/src/enzo/Grid_ApplySmartStarParticleFeedback.C @@ -113,7 +113,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ } /*********************************************************************** - SUPERNOVAE + STELLAR THERMAL FEEDBACK & SUPERNOVAE ************************************************************************/ // Assume that the remnant is still in the free expansion stage and @@ -129,7 +129,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ */ if(SS->ParticleClass == SMS) { - if(Age > SS->RadiationLifetime) {/* SMS converts directly into DCBH */ + if(Age > SS->RadiationLifetime && Age*TimeUnits/Myr_s > 1e-3) {/* SMS converts directly into DCBH */ SS->ParticleClass = BH; SS->StellarAge = SS->RadiationLifetime; //Record last stellar age SS->RadiationLifetime = 1e20; @@ -141,8 +141,8 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ return SUCCESS; } /* POPIII Supernova */ else if(SS->ParticleClass == POPIII) { - - if(Age > SS->RadiationLifetime) {/* Star needs to go supernovae and change type */ + double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ + if(Age > SS->RadiationLifetime && Age*TimeUnits/Myr_s > 1e-3) {/* Star needs to go supernovae and change type */ /* We now need to convert this particle into a Black Hole if appropriate * 20 Msolar - 40.1 Msolar -> Type II supernova with BH remnant @@ -154,7 +154,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ printf("%s:Star going Supernova!\n", __FUNCTION__); printf("%s: Age = %1.2f Myr\t RadiationLifetime = %1.2f Myr\n", __FUNCTION__, Age*TimeUnits/Myr_s, SS->RadiationLifetime*TimeUnits/Myr_s); - double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ + printf("%s: StellarMass = %lf\n", __FUNCTION__, StellarMass); double SNEnergy, HeliumCoreMass, Delta_SF, MetalMass; FLOAT Radius = PopIIISupernovaRadius * pc_cm / LengthUnits; @@ -214,9 +214,22 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ SS->RadiationLifetime*TimeUnits/Myr_s); } + } + else if(StellarMass > 500.0) //PopIII star that is very massive (> 500 Msolar) + { + FLOAT EjectaMetalDensity = 0.0, EjectaThermalEnergy = 0.0, EjectaDensity = 0.0; + printf("%s:!!!!!!!Using Stellar Thermal Feedback Mode\n", __FUNCTION__); fflush(stdout); + + printf("%s: StellarMass = %lf\n", __FUNCTION__, StellarMass); + /* For this case we simply assume a Stroemgren sphere that ionised the nearby gas */ + float StellarTemperature = 1e5; + + EjectaThermalEnergy = StellarTemperature / (TemperatureUnits * (Gamma-1.0) * 0.6); + this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, + EjectaMetalDensity); } return SUCCESS; - } + } else if(SS->ParticleClass == POPII) { diff --git a/src/enzo/RadiativeTransferLWShielding.C b/src/enzo/RadiativeTransferLWShielding.C index c1638bfd5..32abbb018 100644 --- a/src/enzo/RadiativeTransferLWShielding.C +++ b/src/enzo/RadiativeTransferLWShielding.C @@ -94,10 +94,11 @@ int grid::RadiativeTransferLWShielding(PhotonPackageEntry **PP, FLOAT &dP, * of the Draine & Bertoldi fitting formaula for H2 self shielding may be * more appropriate */ - float T = 10000; + + float T = 10000.0; //arbitrary value - should be overwritten with if statement if(BaryonField[TemperatureField]) T = BaryonField[TemperatureField][cellindex]; - + b = sqrt(2.0*kboltz*T/H2mass); // cm s^-1 b5 = b/1e5; // cm s^-1 if ((*PP)->ColumnDensity < THRESHOLD_DENSITY_DB37) { @@ -121,6 +122,7 @@ int grid::RadiativeTransferLWShielding(PhotonPackageEntry **PP, FLOAT &dP, + (0.035/(pow(1 + x, 0.5)))*exp((-8.5e-4)*(pow(1 + x, 0.5))); H2Thin = FALSE; } + } else { diff --git a/src/enzo/TemperatureFieldToolsH2Shielding.C b/src/enzo/TemperatureFieldToolsH2Shielding.C index 2c2a1605a..9df433849 100644 --- a/src/enzo/TemperatureFieldToolsH2Shielding.C +++ b/src/enzo/TemperatureFieldToolsH2Shielding.C @@ -30,15 +30,17 @@ int grid::InitializeTemperatureFieldForH2Shield() if (MyProcessorNumber != ProcessorNumber) return SUCCESS; - //if (RadiativeTransferH2ShieldType != 1) - // return SUCCESS; + int TemperatureField = this->GetTemperatureFieldNumberForH2Shield(), size = 1; + float *temperature = NULL; - int TemperatureField, size = 1; - float *temperature; + if(BaryonField[TemperatureField] != NULL) { //already allocated + this->FinalizeTemperatureFieldForH2Shield(); + } //carry on + for (int dim=0; dimComputeTemperatureField(temperature) == FAIL) { fprintf(stderr, "Error in grid->ComputeTemperatureField.\n"); return FAIL; @@ -48,11 +50,13 @@ int grid::InitializeTemperatureFieldForH2Shield() BaryonField[TemperatureField] = new float[size]; - for (int i = 0; i < size; i++) + for (int i = 0; i < size; i++) { BaryonField[TemperatureField][i] = temperature[i]; - delete [] temperature; + } + delete [] temperature; return SUCCESS; + } @@ -61,11 +65,7 @@ int grid::FinalizeTemperatureFieldForH2Shield() if (MyProcessorNumber != ProcessorNumber) return SUCCESS; - //if (RadiativeTransferH2ShieldType != 1) - // return SUCCESS; - - int TemperatureField; - TemperatureField = this->GetTemperatureFieldNumberForH2Shield(); + int TemperatureField = this->GetTemperatureFieldNumberForH2Shield(); if (BaryonField[TemperatureField] != NULL) { delete [] BaryonField[TemperatureField]; From 4607036921e5829e10c4450e50fdab6a0fdfc16d Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 11:32:25 +0100 Subject: [PATCH 103/115] Removing mechanical star code in Grid_FindAllStarParticles --- src/enzo/Grid_FindAllStarParticles.C | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/enzo/Grid_FindAllStarParticles.C b/src/enzo/Grid_FindAllStarParticles.C index 1bfb75dc7..f77d81e75 100644 --- a/src/enzo/Grid_FindAllStarParticles.C +++ b/src/enzo/Grid_FindAllStarParticles.C @@ -62,9 +62,6 @@ int grid::FindAllStarParticles(int level) LifetimeFactor = 12.0; else LifetimeFactor = 1.0; - if (StarParticleFeedback == MECHANICAL){ - LifetimeFactor = huge_number; // mech stars dont die! - } if (this->Time >= ParticleAttribute[0][i] && this->Time <= ParticleAttribute[0][i] + LifetimeFactor * ParticleAttribute[1][i]) { @@ -91,10 +88,6 @@ int grid::FindAllStarParticles(int level) NewStar = new Star(this, i, level); InsertStarAfter(Stars, NewStar); NumberOfStars++; - if (StarParticleFeedback == MECHANICAL){ - NewStar->SetFeedbackFlag(MECHANICAL); - NewStar->LifeTime = huge_number; // Mechanical stars never "die", they can reaccrete or just deposit wind - } /* For MBHFeedback = 2 to 5 (FeedbackFlag=MBH_JETS), you need the angular momentum; if no file to read in, assume zero angular momentum accreted so far. -Ji-hoon Kim, Nov.2009 */ From 27d0781452654147784d6d117f853781c39e5c32 Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 11:34:16 +0100 Subject: [PATCH 104/115] Removing Grid_FlagCellsToBeRefinedByPopIII.C --- src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C | 143 ------------------- 1 file changed, 143 deletions(-) delete mode 100644 src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C diff --git a/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C b/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C deleted file mode 100644 index 288286795..000000000 --- a/src/enzo/Grid_FlagCellsToBeRefinedByPopIII.C +++ /dev/null @@ -1,143 +0,0 @@ -/*********************************************************************** -/ -/ Set flagging field to refine around pop III particles. -/ -/ written by: Azton Wells -/ date: Dec, 2019 -/ modified1: -/ -/ PURPOSE: -/ -************************************************************************/ - -#ifdef USE_MPI -#include "mpi.h" -#endif -#include -#include -#include -#include "ErrorExceptions.h" -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "Hierarchy.h" -#include "TopGridData.h" -#include "LevelHierarchy.h" -#include "CommunicationUtilities.h" -#include "phys_constants.h" -int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, FLOAT Time); -/* - New refinement criteria will refine the region around Pop III star particles. - This will ensure that their thermal feedback is effective, given that MaximumRefinementLevel is - sufficient - */ - -int grid::FlagCellsToBeRefinedByPopIII(int level) -{ - /* declarations */ - - float LengthUnits, TimeUnits, TemperatureUnits, VelocityUnits, - DensityUnits; - int i, j, k, index, dim, size = 1, NumberOfFlaggedCells = 0; - int Start[MAX_DIMENSION], End[MAX_DIMENSION]; - - FLOAT CellSize, xpos, ypos, zpos; - /* Return if this grid is not on this processor. */ - - if (MyProcessorNumber != ProcessorNumber) - return SUCCESS; - - /* error check */ - if (FlaggingField == NULL) - { - fprintf(stderr, "Flagging Field is undefined.\n"); - return -1; - } - - /* loop over dimensions - I guess this is unnecessary, - but it's handy to have shorter names */ - for (dim = 0; dim < MAX_DIMENSION; dim++) - { - Start[dim] = GridStartIndex[dim]; - End[dim] = GridEndIndex[dim]; - } - - /* compute size */ - for (int dim = 0; dim < GridRank; dim++) - size *= GridDimension[dim]; - GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, Time); - - //If A: no particles or - // B: the resolution is such that its already as refined as PopIIISupernovaMustRefineResolution - int nCellsPerRadius = 1.4*float(PopIIISupernovaRadius)/(CellWidth[0][0]*LengthUnits/pc_cm)+0.5; - if (NumberOfParticles == 0 || 2*nCellsPerRadius > PopIIISupernovaMustRefineResolution || level >= MaximumRefinementLevel){ - for (i = 0; i < size; i++) - { - if (FlaggingField[i] > 0){ - FlaggingField[i] = 1; - NumberOfFlaggedCells += 1; - } - } - return NumberOfFlaggedCells; - } - int istar = 0; - // printf("[%d] Checking particles %d<->%d::%f<->%f\n", level, 2*nCellsPerRadius, - // PopIIISupernovaMustRefineResolution, - // CellWidth[0][0]*LengthUnits/pc_cm, PopIIISupernovaRadius); - int np = 0; - while (istar < NumberOfParticles) - { - if (ParticleAttribute[0][istar] > 0.0 && ParticleType[istar] == 5) // if its a star - { - /* factor = birthtime + lifetime + refineTime */ - float factor = (ParticleAttribute[0][istar] + ParticleAttribute[1][istar]) * TimeUnits + PopIIIMustRefineRegionLifetime * 3.1557e13; - float m = ParticleMass[istar]*(DensityUnits*pow(LengthUnits*CellWidth[0][0], 3))/SolarMass; - if ((((11 < m && m < 40) || (140 < m && m < 260)) || (m < 1e-10)) && (Time * TimeUnits < factor)) - { - // fprintf(stdout, "Flagging cells for particle m=%"FSYM" fact=%"FSYM" Time=%"FSYM"\n", m, factor/3.1557e13, Time*TimeUnits/3.1557e13); - // refine a radius a*Pop3 SN radius - FLOAT radius = 1.4 * PopIIISupernovaRadius * 3.086e18 / LengthUnits; - CellSize = FLOAT(CellWidth[0][0]); - - for (k = Start[2]; k <= End[2]; k++) - for (j = Start[1]; j <= End[1]; j++) - for (i = Start[0]; i <= End[0]; i++) - { - index = i + j * GridDimension[0] + - k * GridDimension[1] * GridDimension[0]; - - xpos = GridLeftEdge[0] + (FLOAT(i - Start[0]) + 0.5) * CellSize; - ypos = GridLeftEdge[1] + (FLOAT(j - Start[1]) + 0.5) * CellSize; - zpos = GridLeftEdge[2] + (FLOAT(k - Start[2]) + 0.5) * CellSize; - float dist = pow(xpos - ParticlePosition[0][istar], 2) - + pow(ypos - ParticlePosition[1][istar], 2) - + pow(zpos - ParticlePosition[2][istar], 2); - if (dist < radius * radius) - { - FlaggingField[index] += 1; - np += 1; - } - } // end loop over cells - } // end if its a star - } // end if refine star - istar++; - } // end for particles - // // sum cells flagged - for (i = 0; i < size; i++) - { - if (FlaggingField[i] > 0){ - FlaggingField[i] = 1; - NumberOfFlaggedCells += 1; - } - } - // fprintf(stdout, "[ %d ] P3 flagged %d cells\n", level, NumberOfFlaggedCells); - - return NumberOfFlaggedCells; -} \ No newline at end of file From eff316e0763e346812a8bb7965e7ef85cba48a01 Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 11:39:52 +0100 Subject: [PATCH 105/115] Removing need to refine around PopIII particles --- src/enzo/Grid.h | 3 --- src/enzo/Grid_SetFlaggingField.C | 9 --------- src/enzo/Make.config.objects | 1 - 3 files changed, 13 deletions(-) diff --git a/src/enzo/Grid.h b/src/enzo/Grid.h index 5629947cf..047921f41 100644 --- a/src/enzo/Grid.h +++ b/src/enzo/Grid.h @@ -992,9 +992,6 @@ gradient force to gravitational force for one-zone collapse test. */ int FlagCellsToBeRefinedByMetalMass(int level); -/* Flag cells surrounding PopIII stars */ - - int FlagCellsToBeRefinedByPopIII(int level); /* Flagging all cell adjacent to a previous flagged cell. Also, remove all Flagged cells in the boundary zones and within one zone of the boundary. */ diff --git a/src/enzo/Grid_SetFlaggingField.C b/src/enzo/Grid_SetFlaggingField.C index aa82b90f8..98df34d62 100644 --- a/src/enzo/Grid_SetFlaggingField.C +++ b/src/enzo/Grid_SetFlaggingField.C @@ -279,15 +279,6 @@ int grid::SetFlaggingField(int &NumberOfFlaggedCells, int level) } break; - case 20: - // fprintf(stdout, "Calling FlagCellsToBeRefinedByPopIII\n"); - NumberOfFlaggedCells = this->FlagCellsToBeRefinedByPopIII(level); - if (NumberOfFlaggedCells < 0){ - fprintf(stderr, "Error in FlagCellsToBeRefinedByPopIII: NCells < 0.\n"); - return FAIL; - } - // fprintf(stdout, "Called FlagCellsToBeRefinedByPopIII\n"); - break; /* ==== METHOD 100: UNDO REFINEMENT IN SOME REGIONS ==== */ /* Must be done last ... */ diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index d3ee432ce..e06b7896b 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -505,7 +505,6 @@ OBJS_CONFIG_LIB = \ Grid_FlagCellsToBeRefinedByShockwaves.o \ Grid_FlagCellsToBeRefinedBySlope.o \ Grid_FlagCellsToBeRefinedBySecondDerivative.o \ - Grid_FlagCellsToBeRefinedByPopIII.o \ Grid_FlagRefinedCells.o \ Grid_FlagGridArray.o \ Grid_FreeExpansionInitializeGrid.o \ From 4d0ba412542abb84a3571ccb075395f1665d63dd Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 11:42:28 +0100 Subject: [PATCH 106/115] Removing mechanical star files --- src/enzo/Grid_MechStarsCreation.C | 272 ---------- src/enzo/Grid_MechStarsDepositFeedback.C | 640 ----------------------- src/enzo/Grid_MechStarsFeedbackRoutine.C | 371 ------------- src/enzo/Grid_MechStarsSeedSupernova.C | 209 -------- 4 files changed, 1492 deletions(-) delete mode 100644 src/enzo/Grid_MechStarsCreation.C delete mode 100644 src/enzo/Grid_MechStarsDepositFeedback.C delete mode 100644 src/enzo/Grid_MechStarsFeedbackRoutine.C delete mode 100644 src/enzo/Grid_MechStarsSeedSupernova.C diff --git a/src/enzo/Grid_MechStarsCreation.C b/src/enzo/Grid_MechStarsCreation.C deleted file mode 100644 index b27805dd0..000000000 --- a/src/enzo/Grid_MechStarsCreation.C +++ /dev/null @@ -1,272 +0,0 @@ -/* - Algorithm creates the stars for Mechanical star maker - Formation follows Hopkins 2017 "How to model supernovae" - - 07/2019: Azton Wells - */ -#include -#include -#include -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "fortran.def" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" -//Prototypes - int checkCreationCriteria(float* Density, - float* Metals, - float* Temperature,float* DMField, - float* Vel1, float* Vel2, float* Vel3, float* TotE, - float* CoolingTime, int* GridDim, - float* shieldedFraction, float* freeFallTime, - float* dynamicalTime, int i, int j, int k, - float Time, float* RefinementField, float CellWidth, - bool* gridShouldFormStars, bool* notEnoughMetals, - int continuingFormation, int* seedIndex); - int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, float *MassUnits, float Time); - int FindField(int field, int farray[], int numfields); - - -/* Creation Routine */ -int grid::MechStars_Creation(grid* ParticleArray, float* Temperature, - float *DMField, float* totalMetal, int level, float* CoolingTime, - int MaximumNumberOfNewParticles, int* NumberOfParticlesSoFar) -{ - /* If limiting timesteps for SNe, return if not the right level */ - if (level < StarMakeLevel) return 0; - /* - these flags are used to determine if we should set off a seed SNe - if (gridShouldFormStars && !notEnoughMetals) at the end, we'll seed - with P3 SNe if requested - */ - bool gridShouldFormStars=false, notEnoughMetals = true; - - bool debug = true; // local debug flag; theres a lot of printing in here - - - //get field numbers - int DensNum, GENum, Vel1Num, Vel2Num,Vel3Num, TENum; - if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) { - fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); - return FAIL; - } - - int MetallicityField = FALSE, MetalNum, MetalIaNum, MetalIINum, SNColourNum; - if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) - != -1) - { - MetallicityField = TRUE; - float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; - if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { - fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } - } - else - MetalNum = 0; - if (!MetalNum){ - fprintf(stderr, "Can only use mechanical star maker routines with metallicity enabled!"); - return FAIL; - } - MetalIaNum = FindField(MetalSNIaDensity, FieldType, NumberOfBaryonFields); - MetalIINum = FindField(MetalSNIIDensity, FieldType, NumberOfBaryonFields); - SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); - int size =1; - for (int dim = 0; dim < GridRank; dim ++) - size *= GridDimension[dim]; - - - float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; - if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { - fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } - - /* - ReDefine MassUnits so that code * mass = physical (Msun) - and physical(Msun) / MassUnits = code */ - MassUnits = DensityUnits*pow(LengthUnits*CellWidth[0][0], 3)/SolarMass; - - /* Index of last cell that was capable of star formation but has no metals */ - int *seedIndex = new int [3]; - - FLOAT dx = CellWidth[0][0]; - FLOAT cell_vol = dx*dx*dx; - int GZ = int(NumberOfGhostZones); - int nCreated = *NumberOfParticlesSoFar; - //fprintf(stdout, "Starting creation with %d prior particles\n",nCreated); - for (int k = GZ; k< GridDimension[2]-GZ; k++){ - for(int j = GZ; j < GridDimension[1]-GZ; j++){ - for (int i = GZ; i < GridDimension[0]-GZ; i++){ - /* - Particle creation has several criteria: - 0. is this the finest level for this cell - 1. Density > overdensity - 2. is flow converging by finite differences - 3. is cooling time < dynamical time - 4. is gas mass > jean critical mass - 5. is gas self shielded by Krumholz & Gnedin 2007 criteria - 6. is virial parameter < 1 - - */ - int index = i+ j*GridDimension[0]+k*GridDimension[0]*GridDimension[1]; - if (BaryonField[NumberOfBaryonFields][index] != 0.0) continue; - float shieldedFraction = 0; - float freeFallTime = 0; - float dynamicalTime = 0; - float Time = this->Time; - int createStar = false; - - - createStar = checkCreationCriteria(BaryonField[DensNum], - totalMetal, Temperature, DMField, - BaryonField[Vel1Num], BaryonField[Vel2Num], - BaryonField[Vel3Num], BaryonField[TENum], - CoolingTime, GridDimension, &shieldedFraction, - &freeFallTime, &dynamicalTime, i,j,k,Time, - BaryonField[NumberOfBaryonFields], CellWidth[0][0], - &gridShouldFormStars, ¬EnoughMetals, 0, seedIndex); - - - if (createStar){ - - /* Determine Mass of new particle */ - - float MassShouldForm = (shieldedFraction * BaryonField[DensNum][index] - * MassUnits / (freeFallTime * TimeUnits) * Myr_s); - // Probability has the last word here - // FIRE-2 uses p = 1 - exp (-MassShouldForm*dt / M_gas_particle) to convert a whole particle to star particle - float p_form = 1.0 - exp(-1*MassShouldForm * this->dtFixed / (StarMakerMaximumFormationMass)); - float random = (float) rand() / (float)(RAND_MAX); - - printf("Expected Mass = %12.5e; Cell_mass = %12.5e; f_s = %12.5e; t_ff = %12.5e; time-factor = %12.5e; nb = %12.5e; pform = %12.5e, rand = %12.5e; rand_max = %ld\n", - MassShouldForm, BaryonField[DensNum][index] * MassUnits, shieldedFraction, freeFallTime*TimeUnits, 1.0/(freeFallTime*TimeUnits) * Myr_s, - BaryonField[DensNum][index]*DensityUnits/(mh/0.6), p_form, random, RAND_MAX); - if (MassShouldForm < 0){ - printf("Negative formation mass: %f %f",shieldedFraction, freeFallTime); - continue; - } - - /* limit new mass to 1/2 gas in cell, or StarMakerMaximumFormationMass */ - float newMass = min(min(MassShouldForm/MassUnits, 0.5*BaryonField[DensNum][index]), StarMakerMaximumFormationMass/MassUnits); - - // only if mass is large enough - - if ((newMass*MassUnits < StarMakerMinimumMass) || (random > p_form)){ // too small mass or probability is not in your favor, young one. - continue; - } - float totalDensity = (BaryonField[DensNum][index]+DMField[index])*DensityUnits; - dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); - // fprintf(stdout, "DynamicalTime = %e\n", dynamicalTime); - ParticleArray->ParticleMass[nCreated] = newMass; - if (StarParticleRadiativeFeedback) - ParticleArray->ParticleAttribute[1][nCreated] = 25.0 * Myr_s * TimeUnits; // need 25 Myr lifetime for ray tracing feedback - else - ParticleArray->ParticleAttribute[1][nCreated] = 0.0; // Tracking SNE in TDP field dynamicalTime/TimeUnits; - ParticleArray->ParticleAttribute[0][nCreated] = Time; - - ParticleArray->ParticleAttribute[2][nCreated] = totalMetal[index] - /BaryonField[DensNum][index]; - if (StarMakerTypeIaSNe) - ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIaNum][index]; - - ParticleArray->ParticleType[nCreated] = PARTICLE_TYPE_STAR; - BaryonField[DensNum][index] -= newMass; - BaryonField[MetalNum][index] -= newMass*totalMetal[index]/BaryonField[DensNum][index]; - if (SNColourNum > 0) - BaryonField[SNColourNum][index] -= newMass/BaryonField[DensNum][index]*BaryonField[SNColourNum][index]/BaryonField[DensNum][index]; - - - // type IA metal field isnt here right now - // if (StarMakerTypeIASNe) - // ParticleArray->ParticleAttribute[3][nCreated] = BaryonField[MetalIANum]; - float vX = 0.0; - float vY = 0.0; - float vZ = 0.0; - if (HydroMethod != 0) - fprintf(stderr,"Mechanical star maker not tested for anything except HydroMethod = 0\n"); - /* average particle velocity over 125 cells to prevent runaway */ - for (int kp = k-2; kp <= k+2; kp++) - for (int jp = j-2; jp <= j+2 ; jp++) - for (int ip = i-2; ip <= i + 2 ; ip++) - { - int ind = ip + jp*GridDimension[0]+kp*GridDimension[0]+GridDimension[1]; - vX += BaryonField[Vel1Num][ind]; - vY += BaryonField[Vel2Num][ind]; - vZ += BaryonField[Vel3Num][ind]; - } - float MaxVelocity = 250.*1.0e5/VelocityUnits; - ParticleArray->ParticleVelocity[0][nCreated] = - (abs(vX/125.) > MaxVelocity)?(MaxVelocity*((vX > 0)?(1):(-1))):(vX/125.); - ParticleArray->ParticleVelocity[1][nCreated] = - (abs(vY/125.) > MaxVelocity)?(MaxVelocity*((vY > 0)?(1):(-1))):(vY/125.); - ParticleArray->ParticleVelocity[2][nCreated] = - (abs(vZ/125.) > MaxVelocity)?(MaxVelocity*((vZ > 0)?(1):(-1))):(vZ/125.); - - /* give it position at center of host cell */ - - ParticleArray->ParticlePosition[0][nCreated] = CellLeftEdge[0][0] - +(dx*(FLOAT(i)-0.5)); - ParticleArray->ParticlePosition[1][nCreated] = CellLeftEdge[1][0] - +(dx*(FLOAT(j)-0.5)); - ParticleArray->ParticlePosition[2][nCreated] = CellLeftEdge[2][0] - +(dx*(FLOAT(k)-0.5)); - if (nCreated >= MaximumNumberOfNewParticles) return nCreated; - if (debug) - fprintf(stdout,"Created star: [%f] %e %e ::: %d %d %d ::: %e %f %e %e::: %f %f %f ::: %f %f %f \t::: %d %d ::: %d %d %d\n", - Time*TimeUnits/3.1557e13, - BaryonField[DensNum][index], - BaryonField[DensNum][index]*MassUnits, - level, nCreated+1, - ParticleArray->ParticleType[nCreated], - ParticleArray->ParticleMass[nCreated]*MassUnits, - ParticleArray->ParticleAttribute[0][nCreated], - ParticleArray->ParticleAttribute[1][nCreated], - ParticleArray->ParticleAttribute[2][nCreated], - ParticleArray->ParticlePosition[0][nCreated], - ParticleArray->ParticlePosition[1][nCreated], - ParticleArray->ParticlePosition[2][nCreated], - ParticleArray->ParticleVelocity[0][nCreated]*VelocityUnits/1e5, - ParticleArray->ParticleVelocity[1][nCreated]*VelocityUnits/1e5, - ParticleArray->ParticleVelocity[2][nCreated]*VelocityUnits/1e5, - index, GridDimension[0]*GridDimension[2]*GridDimension[3], i,j,k); - nCreated ++; - } - }//end for k - }//end for j - } // end for i - /* - If the grid has met star formation criteria, but stars are not formed due to lack of metals, - we set off a P3 SN event at the last grid cell that could have hosted star formation. Can and will set - off multiple events per grid cell if the same cell meets criteria on the next iteration! - */ - if (gridShouldFormStars && MechStarsSeedField && (nCreated == 0)){ - // set off a p3 supernova at at the last cell that could - // host star formation in the grid if the - // grid can host star formation but has no appreciable metals - fprintf(stdout, "\n\n\n[%d] %d %d %d Creating seed field!\n\n\n\n", - ID,seedIndex[0], seedIndex[1], seedIndex[2]) ; - MechStars_SeedSupernova(&totalMetal[0], Temperature, seedIndex); - - } - //if (nCreated > 0 && debug){ - // fprintf(stdout, "Created %d star particles\n",nCreated); - // } - delete [] seedIndex; - // delete [] totalMetal; - *NumberOfParticlesSoFar = nCreated; - return nCreated; -} diff --git a/src/enzo/Grid_MechStarsDepositFeedback.C b/src/enzo/Grid_MechStarsDepositFeedback.C deleted file mode 100644 index 7667af163..000000000 --- a/src/enzo/Grid_MechStarsDepositFeedback.C +++ /dev/null @@ -1,640 +0,0 @@ -#include -#include -#include -#include -#include "ErrorExceptions.h" -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "fortran.def" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" - -extern "C" void FORTRAN_NAME(cic_deposit)(FLOAT *xPosition, FLOAT *yPosition, - FLOAT *zPosition, int *gridRank, int *nParticles, - FLOAT *DepositQuantity, float *FieldToDepositTo, - FLOAT *leftEdge, int *xGridDim, int *yGridDim, - int *zGridDim, FLOAT *gridDx, FLOAT *cloudsize); -int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, float *MassUnits, float Time); -int transformComovingWithStar(float *Density, float *Metals, - float *MetalsSNII, float *MetalsSNIA, - float *Vel1, float *Vel2, float *Vel3, - float *TE, float *GE, - float up, float vp, float wp, - int sizeX, int sizeY, int sizeZ, int direction); -int FindField(int field, int farray[], int numfields); - -int grid::MechStars_DepositFeedback(float ejectaEnergy, - float ejectaMass, float ejectaMetal, - float *totalMetals, float *temperature, - float *up, float *vp, float *wp, - float *xp, float *yp, float *zp, - int ip, int jp, int kp, - int size, float *muField, int winds, int nSNII, - int nSNIA, float starMetal, int isP3) -{ - - /* - This routine will create an isocahedron of coupling particles, where we determine - the feedback quantities. The vertices of the isocahedron are ~coupled particles - and all have radius dx from the source particle. - Each vertex particle will then be CIC deposited to the grid! - */ - //printf("In Feedback deposition\n"); - bool debug = false; - bool criticalDebug = false; - float min_winds = 1.0; - bool printout = debug && !winds; - int index = ip + jp * GridDimension[0] + kp * GridDimension[0] * GridDimension[1]; - if (printout) - printf("Host index = %d\n", index); - int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; - - /* Compute size (in floats) of the current grid. */ - float stretchFactor = 1.0; //1.5/sin(M_PI/10.0); // How far should cloud particles be from their host - // in units of dx. Since the cloud forms a sphere shell, stretchFactor > 1 is not recommended - size = 1; - for (int dim = 0; dim < GridRank; dim++) - size *= GridDimension[dim]; - float DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, - HMNum, H2INum, H2IINum, DINum, DIINum, HDINum; - /* Find fields: density, total energy, velocity1-3. */ - - if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) - { - fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); - return FAIL; - } - /* Set the units */ - float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; - if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, - &MassUnits, this->Time) == FAIL) - { - fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } - FLOAT dx = CellWidth[0][0]; - - if (printout) - printf("depositing quantities: Energy %e, Mass %e, Metals %e\n", - ejectaEnergy, ejectaMass, ejectaMetal); - - /* - get metallicity field and set flag; assumed true thoughout feedback - since so many quantities are metallicity dependent - */ - int MetallicityField = FALSE, MetalNum = -1, MetalIaNum = -1, MetalIINum = -1, SNColourNum = -1; - if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) - MetallicityField = TRUE; - else - { - fprintf(stdout, "MechStars only functions with metallicity field enabled!"); - ENZO_FAIL("Grid_MechStarsDepositFeedback: 91"); - MetalNum = 0; - } - if (StarMakerTypeIaSNe) - MetalIaNum = FindField(MetalSNIaDensity, FieldType, NumberOfBaryonFields); - if (StarMakerTypeIISNeMetalField) - MetalIINum = FindField(MetalSNIIDensity, FieldType, NumberOfBaryonFields); - if (MechStarsSeedField) - SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); - - if (MechStarsSeedField && SNColourNum < 0) - ENZO_FAIL("Cant use Seed Field without SNColour field"); - /* set other units that we need */ - MassUnits = DensityUnits * pow(LengthUnits * dx, 3) / SolarMass; //Msun! - float EnergyUnits = DensityUnits * pow(LengthUnits * dx, 3) * pow(LengthUnits / TimeUnits, 2.0); //[g cm^2/s^2] -> code_energy - float MomentaUnits = MassUnits * VelocityUnits; - - /* Make copys of pointers fields to work with (theyre just easier to type!). */ - float *density = BaryonField[DensNum]; - float *metals = BaryonField[MetalNum]; - float *metalsII = NULL; - float *metalsIA = NULL; - float *metalsIII = NULL; - if (StarMakerTypeIISNeMetalField) - metalsII = BaryonField[MetalIINum]; - if (StarMakerTypeIaSNe) - metalsIA = BaryonField[MetalIaNum]; - if (MechStarsSeedField) - metalsIII = BaryonField[SNColourNum]; - float *u = BaryonField[Vel1Num]; - float *v = BaryonField[Vel2Num]; - float *w = BaryonField[Vel3Num]; - float *totalEnergy = BaryonField[TENum]; - float *gasEnergy = BaryonField[GENum]; - - float phi = (1.0 + sqrt(5)) / 2.0; //Golden Ratio - float iphi = 1.0 / phi; // inverse GR - /* Particle Vectors */ - - /* A DODECAHEDRON+ISOCAHEDRON */ - int nCouple = 26; - float A = stretchFactor * dx; - FLOAT cloudSize = stretchFactor * dx; - - /* - Make a cloud of coupling particles; - each is on a grid with dx spacing - from the host particles. - */ - - FLOAT CloudParticleVectorX[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - // {1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, - // iphi, iphi, -iphi, -iphi, phi, phi, -phi, -phi, - // 0, 0, 0, 0, 1, 1, -1, -1, phi,-phi, phi,-phi}; - FLOAT CloudParticleVectorY[] = {1, 1, 1, 0, 0, -1, -1, -1, 0, 1, 1, 1, 0, 0, -1, -1, -1, 1, 1, 1, 0, 0, -1, -1, -1, 0}; - // {1,1,-1,-1, 1, 1, -1, -1, iphi, iphi, -iphi, -iphi, - // phi, -phi, phi,-phi, 0, 0, 0, 0,1, 1, -1, -1, - // phi, -phi, -phi, phi, 0, 0, 0, 0}; - FLOAT CloudParticleVectorZ[] = {1, 0, -1, 1, -1, 1, 0, -1, 0, 1, 0, -1, 1, -1, 1, 0, -1, 1, 0, -1, 1, -1, 1, 0, -1, 0}; - // {1,-1, 1,-1, 1,-1, 1,-1, phi,-phi, phi,-phi, - // 0, 0, 0, 0, iphi, -iphi, iphi, -iphi, - // phi, -phi, -phi, phi, 0, 0, 0, 0, 1, 1, -1, -1}; - float weightsVector[nCouple]; - /* Set position of feedback cloud particles */ - - FLOAT CloudParticlePositionX[nCouple]; - FLOAT CloudParticlePositionY[nCouple]; - FLOAT CloudParticlePositionZ[nCouple]; - - /*all possible values of x,y,z with origin particle at x=y=z=0.0 */ - - for (int cpInd = 0; cpInd < nCouple; cpInd++) - { - float norm = sqrt(CloudParticleVectorX[cpInd] * CloudParticleVectorX[cpInd] + CloudParticleVectorY[cpInd] * CloudParticleVectorY[cpInd] + CloudParticleVectorZ[cpInd] * CloudParticleVectorZ[cpInd]); - float xbaMag = A * A * norm * norm; - /* in this cloud, take the coupling particle position as 0.5, 0.5, 0.5 */ - CloudParticlePositionX[cpInd] = *xp - CloudParticleVectorX[cpInd] / norm * - A; - CloudParticlePositionY[cpInd] = *yp - CloudParticleVectorY[cpInd] / norm * - A; - CloudParticlePositionZ[cpInd] = *zp - CloudParticleVectorZ[cpInd] / norm * - A; - weightsVector[cpInd] = 0.5 * (1. - 1. / (1. + 1. / 4. / M_PI / 26. / xbaMag / M_PI)); - /* turn the vectors back into unit-vectors */ - CloudParticleVectorZ[cpInd] /= norm; - CloudParticleVectorY[cpInd] /= norm; - CloudParticleVectorX[cpInd] /= norm; - } - float weightsSum = 0.0; - for (int wind = 0; wind < nCouple; wind++) - { - weightsSum += weightsVector[wind]; - } - for (int wind = 0; wind < nCouple; wind++) - { - weightsVector[wind] /= weightsSum; - if (weightsVector[wind] == 0 || isnan(weightsVector[wind])) - { - ENZO_FAIL("NaN weight Vector!") - } - } - - /* transform to comoving with the star and take velocities to momenta. - Take Energy densities to energy. winds are ngp unless VERY high resolution - */ - if (!winds || dx * LengthUnits / pc_cm < min_winds) - transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], - BaryonField[MetalIINum], BaryonField[MetalIaNum], - BaryonField[Vel1Num], BaryonField[Vel2Num], BaryonField[Vel3Num], - BaryonField[TENum], BaryonField[GENum], - *up, *vp, *wp, GridDimension[0], GridDimension[1], - GridDimension[2], 1); - /* Use averaged quantities across multiple cells so that deposition is stable. - vmean is used to determine whether the supernova shell calculation should proceed: - M_shell > 0 iff v_shell > v_gas */ - float zmean = 0, dmean = 0, nmean = 0, vmean = 0, mu_mean = 0; - for (int ind = -1; ind <= 1; ind++) - { - zmean += totalMetals[index + ind] / BaryonField[DensNum][index + ind]; - zmean += totalMetals[index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind]; - zmean += totalMetals[index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; - - nmean += BaryonField[DensNum][index + ind] * DensityUnits; - nmean += BaryonField[DensNum][index + GridDimension[0] * ind] * DensityUnits; - nmean += BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind] * DensityUnits; - - // mu_mean += muField[index+ind]; - // mu_mean += muField[index+GridDimension[0]*ind]; - // mu_mean += muField[index+GridDimension[0]*GridDimension[1]*ind]; - - dmean += BaryonField[DensNum][index + ind]; - dmean += BaryonField[DensNum][index + GridDimension[0] * ind]; - dmean += BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; - - vmean += BaryonField[Vel1Num][index + ind] / BaryonField[DensNum][index + ind] * BaryonField[Vel1Num][index + ind] / BaryonField[DensNum][index + ind]; - vmean += BaryonField[Vel1Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind] * BaryonField[Vel1Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind]; - vmean += BaryonField[Vel1Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind] * BaryonField[Vel1Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; - - vmean += BaryonField[Vel2Num][index + ind] / BaryonField[DensNum][index + ind] * BaryonField[Vel2Num][index + ind] / BaryonField[DensNum][index + ind]; - vmean += BaryonField[Vel2Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind] * BaryonField[Vel2Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind]; - vmean += BaryonField[Vel2Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind] * BaryonField[Vel2Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; - - vmean += BaryonField[Vel3Num][index + ind] / BaryonField[DensNum][index + ind] * BaryonField[Vel3Num][index + ind] / BaryonField[DensNum][index + ind]; - vmean += BaryonField[Vel3Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind] * BaryonField[Vel3Num][index + GridDimension[0] * ind] / BaryonField[DensNum][index + GridDimension[0] * ind]; - vmean += BaryonField[Vel3Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind] * BaryonField[Vel3Num][index + GridDimension[0] * GridDimension[1] * ind] / BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]; - } - vmean = sqrt(vmean) / 27.0 * VelocityUnits; // cm/s! - zmean /= (27.0); - // mu_mean/= (dmean); - // if (abs(mu_mean) > 10){ - // mu_mean = 0.6; - // } - dmean = dmean * DensityUnits / (27.); - nmean = max(0.01, dmean / mh); - //nmean = max(nmean, 1e-1); - //if (debug) printf ("Zmean = %e Dmean = %e mu_mean = %e ", zmean, dmean, mu_mean); - //if (debug) printf ("Nmean = %f vmean = %f\n", nmean, vmean/1e5); - float zZsun = max(zmean, 1e-8); - float fz = (zZsun < 0.01) ? (2.0) : (pow(zZsun, -0.14)); - - /* Cooling radius as in Hopkins, but as an average over cells */ - - float CoolingRadius = 28.4 * - pow(max(0.1, nmean), -3.0 / 7.0) * pow(ejectaEnergy / 1.0e51, 2.0 / 7.0) * fz; - if (printout) - fprintf(stdout, "cooling radius [pc] = %e\n %f %e %f %e %e \n", - CoolingRadius, nmean, ejectaEnergy / 1e51, fz, zmean, dmean); - - float coupledEnergy = ejectaEnergy; - - if (printout) - fprintf(stdout, "Dx [pc] = %f\n", dx * LengthUnits / pc_cm); - - float dxRatio = stretchFactor * dx * LengthUnits / pc_cm / CoolingRadius; - if (winds) - dxRatio = min(stretchFactor * dx * LengthUnits / pc_cm / CoolingRadius, 50); - float pEjectMod = pow(2.0 * ejectaEnergy * (ejectaMass * SolarMass), 0.5) / SolarMass / 1e5; - - /* We want to couple one of four phases: free expansion, Sedov-taylor, shell formation, or terminal - The first three phases are take forms from Kim & Ostriker 2015, the last from Cioffi 1988*/ - - float cellwidth = stretchFactor * dx * LengthUnits / pc_cm; - - // if we resolve free expansion, all energy is thermally coupled - - float p_free = sqrt(ejectaMass*SolarMass*ejectaEnergy)/SolarMass/1e5;//1.73e4*sqrt(ejectaMass*ejectaEnergy/1e51/3.); // free exp. momentum eq 15 - float r_free = 2.75 * pow(ejectaMass / 3 / nmean, 1. / 3.); // free exp radius eq 2 - - // assuming r_sedov == dx, solve for t3 - - float t3_sedov = pow(cellwidth * pc_cm / (5.0 * pc_cm * pow(ejectaEnergy / 1e51 / nmean, 1.0 / 5.0)), 5. / 2.); - float p_sedov = 2.21e4 * pow(ejectaEnergy / 1e51, 4. / 5.) * pow(nmean, 1. / 5.) * pow(t3_sedov, 3. / 5.); // eq 16 - - // shell formation radius eq 8 - float r_shellform = 22.6 * pow(ejectaEnergy / 1e51, 0.29) * pow(nmean, -0.42); - // p_sf = m_sf*v_sf eq 9,11 - float p_shellform = 3.1e5 * pow(ejectaEnergy / 1e51, 0.94) * pow(nmean, -0.13); // p_sf = m_sf*v_sf eq 9,11 - - /* termninal momentum */ - float pTerminal = 4.8e5 * pow(nmean, -1.0 / 7.0) * pow(ejectaEnergy / 1e51, 13.0 / 14.0) * fz; // cioffi 1988, as written in Hopkins 2018 - - float coupledMomenta = 0.0; - float eKinetic = 0.0; - if (printout) - fprintf(stdout, "RADII: %e %e %e t_3=%e\n", r_free, r_shellform, CoolingRadius, t3_sedov); - - /* Select the mode of coupling */ - - if (cellwidth < r_free) - { - coupledMomenta = p_free; - if (printout) - fprintf(stdout, "Coupling free expansion\n"); - } - if (cellwidth > r_free && cellwidth < CoolingRadius) - { - coupledMomenta = min(p_sedov, pTerminal); - if (printout) - fprintf(stdout, "Coupling S-T phase\n"); - } - // if (cellwidth > r_shellform && cellwidth < CoolingRadius){ - // coupledMomenta = min(p_shellform+(cellwidth-r_shellform)*(pTerminal-p_shellform)/(CoolingRadius-r_shellform), pTerminal); - // if(printout)fprintf(stdout, "Coupling shell-forming stage\n");} - if (cellwidth > CoolingRadius) - { - coupledMomenta = pTerminal; - if (printout) - fprintf(stdout, "Coupling terminal momenta\n"); - } - if (printout) - fprintf(stdout, "Calculated p = %e\n", coupledMomenta); - - /* fading radius of a SNR. For real scale invariance, the momentum deposited should go to zero for large dx!*/ - // float *temperature = new float[size]; - // this->ComputeTemperatureField(temperature); - // float Gcode = GravConst*DensityUnits*pow(TimeUnits,2); - // float KBcode = kboltz*MassUnits/(LengthUnits*dx)/pow(TimeUnits,2); - // float cSound = sqrt(5/3*kboltz*temperature[index]/mh/muField[index])/1e5; //km/s - // float r_fade = 66.0*pow(ejectaEnergy/1e51, 0.32)*pow(nmean, -0.37)*pow(min(cSound/10, .1), -2.0/5.0); - // if(printout) fprintf(stdout, "Rfade = %e cs = %e \n", r_fade, cSound); - // delete [] temperature; - - // coupledMomenta = (cellwidth > r_fade)?(coupledMomenta*pow(r_fade/cellwidth,3/2)):(coupledMomenta); - float shellMass = 0.0, shellVelocity = 0.0; - if (printout) - printf("Coupled momentum: %e\n", coupledMomenta); - /* - If resolution is in a range comparable to Rcool and - Analytic SNR shell mass is on, adjust the shell mass - upper range of applicability for shell mass is determined by - local average gas velocity (v_shell ~ v_gas = no shell) - */ - if (cellwidth > r_shellform && coupledEnergy > 0 && AnalyticSNRShellMass) - { - shellVelocity = 413.0 * pow(nmean, 1.0 / 7.0) * pow(zZsun, 3.0 / 14.0) * pow(coupledEnergy / EnergyUnits / 1e51, 1.0 / 14.0) * pow(dxRatio, -7.0 / 3.0); //km/s - - if (shellVelocity > vmean / 1e5) - { - shellMass = max(8e3, coupledMomenta / shellVelocity); //Msun - - /* cant let host cells evacuate completely! - 7.974045e+017.974045e+017.974045e+017.974045e+017.974045e+01 Shell mass will be evacuated from central cells by CIC a negative mass, - so have to check that the neighbors can handle it too*/ - for (int ind = -1; ind <= 1; ind++) - { - float minD = min(BaryonField[DensNum][index + ind], BaryonField[DensNum][index + GridDimension[0] * ind]); - minD = min(minD, BaryonField[DensNum][index + GridDimension[0] * GridDimension[1] * ind]); - if (shellMass >= 0.25 * minD * MassUnits) - shellMass = 0.25 * minD * MassUnits; - } - } - } - - if (shellMass < 0.0) - { - fprintf(stdout, "Shell mass = %e Velocity= %e P = %e", - shellMass, shellVelocity, coupledMomenta); - ENZO_FAIL("SM_deposit: 252"); - } - float coupledMass = shellMass + ejectaMass; - eKinetic = coupledMomenta * coupledMomenta / (2.0 * dmean * pow(LengthUnits * CellWidth[0][0], 3) / SolarMass) * SolarMass * 1e10; - if (printout) - fprintf(stdout, "Ekinetic = %e Mass = %e\n", - eKinetic, dmean * pow(LengthUnits * CellWidth[0][0], 3) / SolarMass); - if (eKinetic > 1e60 && winds) - { - fprintf(stdout, "Ekinetic = %e Mass = %e\n", - eKinetic, dmean * pow(LengthUnits * CellWidth[0][0], 3) / SolarMass); - ENZO_FAIL("winds Ekinetic > reasonability!\n"); - } - if (eKinetic > 1e60 && !winds) - { - fprintf(stdout, "Ekinetic = %e Mass = %e\n", - eKinetic, dmean * pow(LengthUnits * CellWidth[0][0], 3) / SolarMass); - ENZO_FAIL("SNE Ekinetic > reasonability!\n"); - } - - float coupledGasEnergy = max(ejectaEnergy - eKinetic, 0); - if (printout) - fprintf(stdout, "Coupled Gas Energy = %e\n", coupledGasEnergy); - if (dxRatio > 1.0) - coupledGasEnergy = (DepositUnresolvedEnergyAsThermal) - ? (coupledGasEnergy) - : (coupledGasEnergy * pow(dxRatio, -6.5)); - if (winds) - coupledGasEnergy = ejectaEnergy; - float shellMetals = zZsun * 0.02 * shellMass; - float coupledMetals = 0.0, SNIAmetals = 0.0, SNIImetals = 0.0, P3metals = 0.0; - if (winds) - coupledMetals = ejectaMetal; //+ shellMetals; // winds only couple to metallicity - if (AnalyticSNRShellMass) - coupledMetals += shellMetals; - SNIAmetals = (StarMakerTypeIaSNe) ? nSNIA * 1.4 : 0.0; - if (!StarMakerTypeIaSNe) - coupledMetals += nSNIA * 1.4; - SNIImetals = (StarMakerTypeIISNeMetalField) ? nSNII * (1.91 + 0.0479 * max(starMetal, 1.65)) : 0.0; - if (!StarMakerTypeIISNeMetalField) - coupledMetals += nSNII * (1.91 + 0.0479 * max(starMetal, 1.65)); - if (isP3 && MechStarsSeedField) - P3metals = ejectaMetal; - - if (printout) - fprintf(stdout, "Coupled Metals: %e %e %e %e %e %e\n", ejectaMetal, SNIAmetals, SNIImetals, shellMetals, P3metals, coupledMetals); - - /* - Critical debug compares the pre-feedback and post-feedback field sums. Note that this doesn't - work well on vector quantities outside of an ideal test. - */ - float preMass = 0, preZ = 0, preP = 0, prePmag = 0, preTE = 0, preGE = 0, preZII = 0, preZIa = 0; - float dsum = 0.0, zsum = 0.0, psum = 0.0, psqsum = 0.0, tesum = 0.0, gesum = 0.0, kesum = 0.0; - float postMass = 0, postZ = 0, postP = 0, postPmag = 0, postTE = 0, postGE = 0, postZII = 0, postZIa = 0; - if (criticalDebug && !winds) - { - for (int i = 0; i < size; ++i) - { - preMass += BaryonField[DensNum][i]; - preZ += BaryonField[MetalNum][i]; - if (StarMakerTypeIISNeMetalField) - preZII += BaryonField[MetalIINum][i]; - if (StarMakerTypeIaSNe) - preZIa += BaryonField[MetalIaNum][i]; - if (MechStarsSeedField) - preZ += BaryonField[SNColourNum][i]; - preP += BaryonField[Vel1Num][i] + BaryonField[Vel2Num][i] + BaryonField[Vel3Num][i]; - prePmag += pow(BaryonField[Vel1Num][i] * MomentaUnits, 2) + - pow(BaryonField[Vel2Num][i] * MomentaUnits, 2) + pow(BaryonField[Vel3Num][i] * MomentaUnits, 2); - preTE += BaryonField[TENum][i]; - preGE += BaryonField[GENum][i]; - } - } - /* Reduce coupled quantities to per-particle quantity and converMetalNumt to - code units. - Hopkins has complicated weights due to complicated geometry. - This implementation is simple since our coupled particles are - spherically symmetric about the feedback particle*/ - - if (!winds) - coupledEnergy = min((nSNII + nSNIA) * 1e51, eKinetic); - - coupledEnergy = coupledEnergy / EnergyUnits; - coupledGasEnergy = coupledGasEnergy / EnergyUnits; - coupledMass /= MassUnits; - coupledMetals /= MassUnits; - coupledMomenta /= MomentaUnits; - SNIAmetals /= MassUnits; - SNIImetals /= MassUnits; - P3metals /= MassUnits; - /* CIC deposit the particles with their respective quantities */ - - FLOAT LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; - FLOAT pX, pY, pZ; - FLOAT eCouple, geCouple, mCouple, zCouple, zIICouple, zIACouple, p3Couple; - /* - As a computational compromize, supernova are deposited CIC, but winds are - deposited NGP. At VERY high resolution, well still do CIC for winds - */ - if (!DepositUnresolvedEnergyAsThermal) - { - for (int n = 0; n < nCouple; ++n) - { - pX = coupledMomenta * CloudParticleVectorX[n] * weightsVector[n]; - pY = coupledMomenta * CloudParticleVectorY[n] * weightsVector[n]; - pZ = coupledMomenta * CloudParticleVectorZ[n] * weightsVector[n]; - eCouple = coupledEnergy * weightsVector[n]; - geCouple = coupledGasEnergy * weightsVector[n]; - mCouple = coupledMass * weightsVector[n]; - zCouple = coupledMetals * weightsVector[n]; - if (isnan(zCouple)) - fprintf(stderr, "Nan metals! %e %e", coupledMetals, weightsVector[n]); - if (StarMakerTypeIISNeMetalField) - zIICouple = SNIImetals * weightsVector[n]; - if (StarMakerTypeIaSNe) - zIACouple = SNIAmetals * weightsVector[n]; - if (MechStarsSeedField) - p3Couple = P3metals * weightsVector[n]; - int np = 1; - - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &mCouple, &density[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &zCouple, &metals[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (pX != 0.0) - { - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &pX, &u[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - } - if (pY != 0.0) - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &pY, &v[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (pZ != 0.0) - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &pZ, &w[0], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (eCouple > 0 && DualEnergyFormalism) - { - if (geCouple > 0) - eCouple += geCouple; - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &eCouple, BaryonField[TENum], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - } - if (geCouple > 0) - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &geCouple, BaryonField[GENum], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (StarMakerTypeIISNeMetalField && zIICouple > 0.0) - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &zIICouple, metalsII, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (StarMakerTypeIaSNe && zIACouple > 0.0) - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &zIACouple, metalsIA, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - if (MechStarsSeedField && p3Couple > 0.0) - { - //if (printout)printf("Coupling %f to pIII metals %d\n",p3Couple*MassUnits, n); - FORTRAN_NAME(cic_deposit) - (&CloudParticlePositionX[n], &CloudParticlePositionY[n], - &CloudParticlePositionZ[n], &GridRank, &np, &p3Couple, metalsIII, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - } - } - } - // printf("\n"); - /* Deposit one negative mass particle centered on star to account for - shell mass leaving host cells . Same for metals that were evacuated*/ - int np = 1; - shellMass *= -1 / MassUnits; - FORTRAN_NAME(cic_deposit) - ((FLOAT *)xp, (FLOAT *)yp, (FLOAT *)zp, &GridRank, &np, (FLOAT *)&shellMass, density, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - shellMetals *= -1 / MassUnits; - FORTRAN_NAME(cic_deposit) - ((FLOAT *)xp, (FLOAT *)yp, (FLOAT *)zp, &GridRank, &np, (FLOAT *)&shellMetals, metals, LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], &dx, &cloudSize); - - /* - Lots of wind calculations make CIC take too much time, so direct deposit - to the host cell. Doing this also allows us to skip the comoving transformation since - the momentum goes uncoupled. Since the cooling radius is so small for wind enrgy (~10^15 erg), - this is totally appropriate for simulations with dx > 0.25pccm or so. - */ - if (DepositUnresolvedEnergyAsThermal) - { - float dm = coupledMass / (density[index] + coupledMass); - density[index] += coupledMass; - metals[index] += coupledMetals; - BaryonField[TENum][index] += dm * coupledEnergy / coupledMass; - BaryonField[GENum][index] += dm * coupledEnergy / coupledMass; - } - - if (criticalDebug && !winds) - { - for (int i = 0; i < size; i++) - { - postMass += BaryonField[DensNum][i]; - postZ += BaryonField[MetalNum][i]; - if (StarMakerTypeIISNeMetalField) - postZII += BaryonField[MetalIINum][i]; - if (StarMakerTypeIaSNe) - postZIa += BaryonField[MetalIaNum][i]; - if (SNColourNum > 0) - postZ += BaryonField[SNColourNum][i]; - postP += BaryonField[Vel1Num][i] + BaryonField[Vel2Num][i] + BaryonField[Vel3Num][i]; - postPmag += pow(BaryonField[Vel1Num][i] * MomentaUnits, 2) + - pow(BaryonField[Vel2Num][i] * MomentaUnits, 2) + pow(BaryonField[Vel3Num][i] * MomentaUnits, 2); - postTE += BaryonField[TENum][i]; - postGE += BaryonField[GENum][i]; - } - if (printout) - fprintf(stderr, "Difference quantities: dxRatio = %f dMass = %e dZ = %e dzII = %e dxIa = %e P = %e |P| = %e TE = %e GE = %e coupledGE = %e Ej = %e Mej = %e Zej = %e\n", - dxRatio, (postMass - preMass) * MassUnits, (postZ - preZ) * MassUnits, - (postZII - preZII) * MassUnits, (postZIa - preZIa) * MassUnits, - (postP - preP) * MomentaUnits, - (sqrt(postPmag) - sqrt(prePmag)), - (postTE - preTE) * EnergyUnits, (postGE - preGE) * EnergyUnits, - coupledGasEnergy * EnergyUnits, ejectaEnergy, - ejectaMass, ejectaMetal); - if (isnan(postMass) || isnan(postTE) || isnan(postPmag) || isnan(postZ)) - { - fprintf(stderr, "NAN IN GRID: %f %e %e %e-%e %e\n", postMass, postTE, postZ, preZ, postP); - for (float w : weightsVector) - { - fprintf(stderr, "%e\t", w); - } - fprintf(stderr, "\n"); - exit(3); - ENZO_FAIL("MechStars_depositFeedback.C: 530\n") - } - } - - /* Transform the grid back. Skip for winds, unless VERY high resolution*/ - if (!winds || dx * LengthUnits / pc_cm < min_winds) - transformComovingWithStar(BaryonField[DensNum], BaryonField[MetalNum], - BaryonField[MetalIINum], BaryonField[MetalIaNum], - BaryonField[Vel1Num], BaryonField[Vel2Num], - BaryonField[Vel3Num], - BaryonField[TENum], BaryonField[GENum], - *up, *vp, *wp, - GridDimension[0], GridDimension[1], - GridDimension[2], -1); - - // delete [] u,v,w, gasEnergy, totalEnergy; - return SUCCESS; -} diff --git a/src/enzo/Grid_MechStarsFeedbackRoutine.C b/src/enzo/Grid_MechStarsFeedbackRoutine.C deleted file mode 100644 index 0158d61f9..000000000 --- a/src/enzo/Grid_MechStarsFeedbackRoutine.C +++ /dev/null @@ -1,371 +0,0 @@ -/* - Routine to determine feedback quantities and couple them to the - Grid. Coupling follows the implementation of Hopkins 2017 with - modification for Enzo's fixed grid - - 07/2019: Azton Wells - */ -#include -#include -#include -#include -#include "ErrorExceptions.h" -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "fortran.def" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" - -int determineSN(float age, int *nSNII, int *nSNIA, float massMsun, - float TimeUnits, float dtFixed); -int determineWinds(float age, float *eWinds, float *zWinds, float *mWinds, - float massMsun, float zZsun, float TimeUnits, float dtFixed); -int checkCreationCriteria(float *Density, float *Metals, - float *Temperature, float *DMField, - float *Vel1, float *Vel2, float *Vel3, float* TotE, - float *CoolingTime, int *GridDim, - float *shieldedFraction, float *freeFallTime, - float *dynamicalTime, int i, int j, int k, - float Time, float *RefinementField, float CellWidth, - bool *gridShouldFormStars, bool *notEnoughMetals, - int continuingFormation, int *seedIndex); -int FindField(int field, int farray[], int numfields); -int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, float *MassUnits, FLOAT Time); -int MechStars_depositEmissivityField(int index, float cellwidth, - float *emissivity0, float age, float mass, - float TimeUnits, float dt); - -int grid::MechStars_FeedbackRoutine(int level, float *mu_field, float *totalMetal, - float *Temperature, float *CoolingTime, float *DMField) -{ - - //fprintf(stdout,"IN FEEDBACK ROUTINE\n %d %d %d\n", - //SingleSN, StellarWinds, UnrestrictedSN); - float Zsolar = 0.02; - float stretchFactor = 1.0; // radius from star particle to feedback cloud particle (in units of dx) - bool debug = false; - float startFB = MPI_Wtime(); - int dim, i, j, k, index, size, field, GhostZones = NumberOfGhostZones; - int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; - - /* Compute size (in floats) of the current grid. */ - - size = 1; - for (dim = 0; dim < GridRank; dim++) - size *= GridDimension[dim]; - int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, - HMNum, H2INum, H2IINum, DINum, DIINum, HDINum; - /* Find fields: density, total energy, velocity1-3. */ - - if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) - { - fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); - return FAIL; - } - /* Set the units */ - float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; - if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) - { - fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } - FLOAT dx = CellWidth[0][0]; - MassUnits = DensityUnits * pow(LengthUnits * dx, 3) / SolarMass; - /* - get metallicity field and set flag; assumed true thoughout feedback - since so many quantities are metallicity dependent - */ - int MetallicityField = FALSE, MetalNum, SNColourNum = -1; - if ((MetalNum = FindField(Metallicity, FieldType, NumberOfBaryonFields)) != -1) - MetallicityField = TRUE; - else - MetalNum = 0; - if (MechStarsSeedField) - SNColourNum = FindField(SNColour, FieldType, NumberOfBaryonFields); - - /* Find and set emissivity field if being used */ - int EmisNum = -1; - if (StarMakerEmissivityField) - { - EmisNum = FindField(Emissivity0, FieldType, NumberOfBaryonFields); - } - if (EmisNum > 0) - { - /* Zero the emissivity first, as we dont want to to accumulate */ - for (int i = 0; i < size; ++i) - BaryonField[EmisNum][i] = 0.0; - } - - int numSN = 0; // counter of events - int c = 0; // counter of particles - // printf("\nIterating all particles "); - for (int pIndex = 0; pIndex < NumberOfParticles; pIndex++) - { - - if (ParticleType[pIndex] == PARTICLE_TYPE_STAR && ParticleMass[pIndex] > 00.0 && ParticleAttribute[0][pIndex] > 0.0) - { - float age = (Time - ParticleAttribute[0][pIndex]) * TimeUnits / 3.1557e13; // Myr - c++; - - /* get index of cell hosting particle */ - FLOAT xp = ParticlePosition[0][pIndex]; - FLOAT yp = ParticlePosition[1][pIndex]; - FLOAT zp = ParticlePosition[2][pIndex]; - - int ip = (xp - CellLeftEdge[0][0] - 0.5 * dx) / dx; - int jp = (yp - CellLeftEdge[1][0] - 0.5 * dx) / dx; - int kp = (zp - CellLeftEdge[2][0] - 0.5 * dx) / dx; - - /* error check particle position; Cant be on the border or outside grid - If on border, reposition to within grid for CIC deposit */ - - FLOAT gridDx = GridDimension[0] * dx; - FLOAT gridDy = GridDimension[1] * dx; - FLOAT gridDz = GridDimension[2] * dx; - /* Keep particle 2 cells from edge since we cant transfer to - neighboring grids */ - FLOAT borderDx = (stretchFactor)*dx; - if (xp > GridRightEdge[0] - || xp < GridLeftEdge[0] - || yp > GridRightEdge[1] - || yp < GridLeftEdge[1] - || zp > GridRightEdge[2] - || zp < GridLeftEdge[2]) - { - if (debug){ - fprintf(stderr, "[%d--%e] Particle %" ISYM " with type %" ISYM " out of grid! Mass: %" GSYM " age: %" FSYM "\npos: %" FSYM ", %" FSYM " %" FSYM ", Vel: %" FSYM " %" FSYM " %f\nLeftEdge: %" FSYM " %" FSYM " %" FSYM "\nRightEdge: %" FSYM " %" FSYM " %" FSYM "\n", - level, dx, pIndex, ParticleType[pIndex], ParticleMass[pIndex] * MassUnits, - age, xp, yp, zp, - ParticleVelocity[0][pIndex], - ParticleVelocity[1][pIndex], - ParticleVelocity[2][pIndex], - GridLeftEdge[0], GridLeftEdge[1], GridLeftEdge[2], - GridRightEdge[0], GridRightEdge[1], GridRightEdge[2]); - fprintf(stderr, "Particle %d: Ct = %f Zzsun = %f TDP = %f\n", - pIndex, ParticleAttribute[0][pIndex], - ParticleAttribute[2][pIndex], - ParticleAttribute[1][pIndex]); - fprintf(stderr, "Accelerations: %"FSYM", %"FSYM", %"FSYM"\n", - ParticleAcceleration[0][pIndex], ParticleAcceleration[1][pIndex], - ParticleAcceleration[2][pIndex]); - } - continue; - // EnzoFatalException("Star Maker Mechanical: particle out of grid!\n"); - //raise(SIGABRT); // fails more quickly and puts out a core dump for analysis - } - int shifted = 0; - - if (xp < CellLeftEdge[0][0] + borderDx) - { - xp = CellLeftEdge[0][0] + borderDx + 0.5 * dx; - shifted++; - } - if (xp > CellLeftEdge[0][0] + gridDx - borderDx) - { - xp = CellLeftEdge[0][0] + gridDx - borderDx - 0.5 * dx; - shifted = 1; - } - if (yp < CellLeftEdge[1][0] + borderDx) - { - yp = CellLeftEdge[1][0] + borderDx + 0.5 * dx; - shifted = 1; - } - if (yp > CellLeftEdge[1][0] + gridDx - borderDx) - { - yp = CellLeftEdge[1][0] + gridDx - borderDx - 0.5 * dx; - shifted = 1; - } - if (zp < CellLeftEdge[2][0] + borderDx) - { - zp = CellLeftEdge[2][0] + borderDx + 0.5 * dx; - shifted = 1; - } - if (zp > CellLeftEdge[2][0] + gridDx - borderDx) - { - zp = CellLeftEdge[2][0] + gridDx - borderDx - 0.5 * dx; - shifted = 1; - } - - index = ip + jp * GridDimension[0] + kp * GridDimension[0] * GridDimension[1]; - - float shieldedFraction = 0, dynamicalTime = 0, freeFallTime = 0; - bool gridShouldFormStars = true, notEnoughMetals = false; - float zFraction = totalMetal[index]; - float pmassMsun = ParticleMass[pIndex] * MassUnits; - if (ParticleMass[pIndex] * MassUnits < StarMakerMaximumMass && ProblemType != 90) - /* - Check for continual formation. Continually forming new mass allows the - star particle count to stay lower, ultimately reducing runtime by having - fewer particles to iterate. - */ - { - int createStar = 0; - /* - if the age is relatively low, calculate continuing formation. - if the age is old, we'd rather form a new particle to get some more - supernova and high-power winds popping off. - */ - if (age < 5) - createStar = checkCreationCriteria(BaryonField[DensNum], - &zFraction, Temperature, DMField, - BaryonField[Vel1Num], BaryonField[Vel2Num], - BaryonField[Vel3Num], BaryonField[TENum], - CoolingTime, GridDimension, &shieldedFraction, - &freeFallTime, &dynamicalTime, ip, jp, kp, Time, - BaryonField[NumberOfBaryonFields], CellWidth[0][0], - &gridShouldFormStars, ¬EnoughMetals, 1, NULL); - if (false) // AIW: disabled for testing. Adding mass here without the probabilistic factor in creation is leading to too many stars. i think. -_- - { - float MassShouldForm = min((shieldedFraction * BaryonField[DensNum][index] * MassUnits / (freeFallTime * TimeUnits) * this->dtFixed * Myr_s), - 0.5 * BaryonField[DensNum][index] * MassUnits); - MassShouldForm = min(MassShouldForm, StarMakerMaximumMass-pmassMsun); // dont form if the star is already at the top of the mass allowed - //printf("Adding new mass %e\n",MassShouldForm); - /* Dont allow negative mass, or taking all gas in cell */ - if (MassShouldForm < 0) - MassShouldForm = 0; - // if (MassShouldForm > 0.5 * BaryonField[DensNum][index] * MassUnits) - // MassShouldForm = 0.5 * BaryonField[DensNum][index] * MassUnits; - - // Set units and modify particle - MassShouldForm /= MassUnits; - if (MassShouldForm > 0) - { - float delta = MassShouldForm / (ParticleMass[pIndex] + MassShouldForm); - - /* fractional metallicity */ - zFraction /= BaryonField[DensNum][index]; - // update mass-weighted metallicity fraction of star particle - ParticleAttribute[2][pIndex] = (ParticleAttribute[2][pIndex] * ParticleMass[pIndex] + zFraction * MassShouldForm) / - (ParticleMass[pIndex] + MassShouldForm); - /* Add new formation mass to particle */ - if (MassShouldForm < 0.5 * BaryonField[DensNum][index]) - { - ParticleMass[pIndex] += MassShouldForm; - printf("[%f] added new mass %e + %e = %e newZ = %f newAge = %f\n", - Time * TimeUnits / 3.1557e13, (ParticleMass[pIndex] - MassShouldForm) * MassUnits, - MassShouldForm * MassUnits, ParticleMass[pIndex] * MassUnits, - ParticleAttribute[2][pIndex], (Time - ParticleAttribute[0][pIndex]) * TimeUnits / 3.1557e13); - - /* Take formed mass out of grid cell */ - - BaryonField[DensNum][index] -= MassShouldForm; - - /* Take metals out of host cell too! */ - - BaryonField[MetalNum][index] -= BaryonField[MetalNum][index] / BaryonField[DensNum][index] * MassShouldForm; - if (MechStarsSeedField) - BaryonField[SNColourNum][index] -= BaryonField[SNColourNum][index] / BaryonField[DensNum][index] * MassShouldForm; - } - } - } - } - - /* Start actual feedback: Supernova calculations */ - - int nSNII = 0; - int nSNIA = 0; - float SNMassEjected = 0, SNMetalEjected = 0; - - /* determine how many supernova events */ - - if (SingleSN) - { - /* - Determine SN events from rates (currently taken from - Hopkins, 2018) - */ - determineSN(age, &nSNII, &nSNIA, ParticleMass[pIndex] * MassUnits, - TimeUnits, dtFixed); - numSN += nSNII + nSNIA; - if ((nSNII > 0 || nSNIA > 0) && debug) - fprintf(stdout, "SUPERNOVAE!!!! %d %d level = %d age = %f\n", nSNII, nSNIA, level, age); - if (nSNII > 0 || nSNIA > 0) - { - /* set feedback qtys based on number and types of events */ - /* 1e51 erg per sn */ - float energySN = (nSNII + nSNIA) * 1e51; - - /*10.5 Msun ejecta for type II and IA*/ - SNMassEjected = nSNII*10.5 + nSNIA * 1.5; - float starMetal = (ParticleAttribute[2][pIndex] / Zsolar); //determines metal content of SNeII - - MechStars_DepositFeedback(energySN, SNMassEjected, SNMetalEjected, totalMetal, - Temperature, &ParticleVelocity[0][pIndex], - &ParticleVelocity[1][pIndex], - &ParticleVelocity[2][pIndex], - (float *)&ParticlePosition[0][pIndex], - (float *)&ParticlePosition[1][pIndex], - (float *)&ParticlePosition[2][pIndex], - ip, jp, kp, size, mu_field, 0, nSNII, nSNIA, - starMetal, 0); - - // can only track number of events in dynamical time if not using it to determine lifetime - - if (!StarParticleRadiativeFeedback) - ParticleAttribute[1][pIndex] += nSNII + nSNIA; - } - } - - /* Do the same for winds. Cooling Radius is very small, - So almost no energy is coupled, but some mass may be. */ - float windEnergy = 0, windMass = 0, windMetals = 0; - - /* - Ignore very old stars, veryvery young stars, and ones whose mass is depleted - */ - if (StellarWinds && age > 0.001 && ParticleMass[pIndex] * MassUnits > 1) - { - // printf("Checking Winds\n"); - float zZsun = min(ParticleAttribute[2][pIndex] / Zsolar, MechStarsCriticalMetallicity); - - determineWinds(age, &windEnergy, &windMass, &windMetals, - ParticleMass[pIndex] * MassUnits, zZsun, - TimeUnits, dtFixed); - if (windMass > 100) - fprintf(stdout, "Really High Wind Mass = %e\n", windMass); - if (windEnergy > 1e5) - { - //printf("Winds: M = %e E=%e\n", windMass, windEnergy); - MechStars_DepositFeedback(windEnergy, windMass, windMetals, totalMetal, - Temperature, - &ParticleVelocity[0][pIndex], - &ParticleVelocity[1][pIndex], - &ParticleVelocity[2][pIndex], - (float *) &ParticlePosition[0][pIndex], - (float *) &ParticlePosition[1][pIndex], - (float *) &ParticlePosition[2][pIndex], - ip, jp, kp, size, mu_field, 1, 0, 0, 0.0, 0); - } - } - if (windMass > 0.0 || SNMassEjected > 0) - { - ParticleMass[pIndex] -= (windMass + SNMassEjected) / MassUnits; - } - /* - if these stars are used in conjunction with FLDImplicit or FLDSplit. This functionality has not been verified - */ - if (StarMakerEmissivityField) - { - MechStars_depositEmissivityField(index, CellWidth[0][0], BaryonField[EmisNum], - age, ParticleMass[pIndex] * MassUnits, TimeUnits, dtFixed); - } - } - } // end iteration over particles - if (c > 0) - { - fprintf(stdout, "Ptcl Number = %d Events = %d FeedbackTime = %e Size = %d\n", - c, numSN, MPI_Wtime() - startFB, GridDimension[0] * GridDimension[1] * GridDimension[2]); - } - return SUCCESS; -} diff --git a/src/enzo/Grid_MechStarsSeedSupernova.C b/src/enzo/Grid_MechStarsSeedSupernova.C deleted file mode 100644 index d4ca445e5..000000000 --- a/src/enzo/Grid_MechStarsSeedSupernova.C +++ /dev/null @@ -1,209 +0,0 @@ -/* - If the region can form stars but has no metals, - We seed the region with a Pop III supernova. - This takes mass from the host cell, converting it - into ejecta mass, energy, and ejecta metals and - deposits it using the MechStars infrastructure. - - 07/2019: Azton Wells - */ -#include -#include -#include -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "fortran.def" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" - - - int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, float *MassUnits, float Time); -extern "C" void FORTRAN_NAME(cic_deposit)(float* xPosition, float* yPosition, - float* zPosition, int* gridRank, int* nParticles, - float* DepositQuantity, float* FieldToDepositTo, - float* leftEdge, int* xGridDim, int* yGridDim, - int* zGridDim, FLOAT* gridDx, float* cloudsize); -int search_lower_bound(float *arr, float value, int low, int high, - int total); -unsigned_long_int mt_random(void); -int StarParticlePopIII_IMFInitialize(void); - -int grid::MechStars_SeedSupernova(float* totalMetal, float* temperature, int* seedIndex){ - debug = false; - /* Initialize the IMF lookup table if requested and not defined */ - if (debug) fprintf(stdout, "setting IMF\n"); - if (PopIIIInitialMassFunction) - StarParticlePopIII_IMFInitialize(); - int DensNum, GENum, TENum, Vel1Num, Vel2Num, Vel3Num; - /* Find fields: density, total energy, velocity1-3. */ - int CRNum; - if (debug) printf("IMF Set!\n"); - /* Find Multi-species fields. */ - int DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, HMNum, H2INum, H2IINum, - DINum, DIINum, HDINum; - - if (this->IdentifyPhysicalQuantities(DensNum, GENum, Vel1Num, Vel2Num, - Vel3Num, TENum) == FAIL) { - fprintf(stderr, "Error in IdentifyPhysicalQuantities.\n"); - return FAIL; - } - float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; - if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, &MassUnits, this->Time) == FAIL) { - fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } - int size = 1; - for (int dim = 0; dim < GridRank; dim++) - size *= GridDimension[dim]; - - /* set feedback to random cell in grid*/ - int ip = seedIndex[0];//rand() % (GridDimension[0]-2*NumberOfGhostZones)+NumberOfGhostZones ; - int jp = seedIndex[1];//rand() % (GridDimension[1]-2*NumberOfGhostZones)+NumberOfGhostZones; - int kp = seedIndex[2];//rand() % (GridDimension[2]-2*NumberOfGhostZones)+NumberOfGhostZones; - float position[3] = {((float)ip+0.5)*CellWidth[0][0]+CellLeftEdge[0][0], - ((float)jp+0.5)*CellWidth[0][0]+CellLeftEdge[1][0], - ((float)kp+0.5)*CellWidth[0][0]+CellLeftEdge[2][0]}; - int index = ip + jp*GridDimension[0]+kp*GridDimension[0]*GridDimension[1]; - /* Get mass of star in exact method used by Star_AssignFinalMassFromIMF.C */ - if (debug) fprintf (stdout, "Setting final mass\n"); - unsigned_long_int random_int = mt_random(); - const int max_random = (1<<16); - float x = (float) (random_int%max_random) / (float) (max_random); - float dm = log10(PopIIIUpperMassCutoff / PopIIILowerMassCutoff) / - (float) (IMF_TABLE_ENTRIES-1); - - /* (binary) search for the mass bin corresponding to the random - number */ - - int width = IMF_TABLE_ENTRIES/2; - int bin_number = IMF_TABLE_ENTRIES/2; - - while (width > 1) { - width /= 2; - if (x > IMFData[bin_number]) - bin_number += width; - else if (x < IMFData[bin_number]) - bin_number -= width; - else - break; - } - - float FinalMass = PopIIILowerMassCutoff * POW(10.0, bin_number * dm); - /* certain mass have no effect since they collapse to black holes */ - if (FinalMass < 10 || (FinalMass >40 && FinalMass < 140) || (FinalMass > 260)){ - printf("Mass Outside Supernova Range!\n"); - return SUCCESS; - } - if (FinalMass > 0.1*BaryonField[DensNum][index]*MassUnits){ - printf("Cell too small for PIII star!"); - return FAIL; - } - /* Now, calculate feedback parameters as in Star_CalculateFeedbackParameters.C */ - - // parameters of supernovae // - const float TypeIILowerMass = 11, TypeIIUpperMass = 20.; - const float HNLowerMass = 20.1, HNUpperMass = 40.1; - const float PISNLowerMass = 140, PISNUpperMass = 260; - - // From Nomoto et al. (2006) - const float HypernovaMetals[] = {3.36, 3.53, 5.48, 7.03, 8.59}; // SolarMass - const float HypernovaEnergy[] = {10, 10, 20, 25, 30}; // 1e51 erg - const float CoreCollapseMetals[] = {3.63, 4.41, 6.71, 8.95, 11.19}; // SolarMass - const float CoreCollapseEnergy[] = {1, 1, 1, 1, 1}; // 1e51 erg - - const float SNExplosionMass[] = {19.99, 25, 30, 35, 40.01}; // SolarMass - const float *SNExplosionMetals = (PopIIIUseHypernova ==TRUE) ? - HypernovaMetals : CoreCollapseMetals; - const float *SNExplosionEnergy = (PopIIIUseHypernova ==TRUE) ? - HypernovaEnergy : CoreCollapseEnergy; - float HeCoreMass = 0; - float SNEnergy = 0; - float EjectaMetal = 0; - float EjectaMass = FinalMass; - // if (BaryonField[DensNum][index]*DensityUnits*pow(LengthUnits*CellWidth[0][0],3) < 5.0*FinalMass){ - // /* Should probably remove from larger area if host cell is too small, - // but should only matter at VERY high resolution: M_cell < 50 M_sun*/ - // if (debug) fprintf(stdout, "Not enough mass in cell for Seed Supernova: %f < %f", - // BaryonField[DensNum][index]*DensityUnits*pow(LengthUnits*CellWidth[0][0],3), FinalMass); - // return FAIL; - // } - /* Reverse CIC out the star mass */ - int np = 1; float MassRem = -1*EjectaMass; - float LeftEdge[3] = {CellLeftEdge[0][0], CellLeftEdge[1][0], CellLeftEdge[2][0]}; - float cloudSize = CellWidth[0][0]; - if (debug) fprintf (stdout, "Removing PIII mass from grid\n"); - FORTRAN_NAME(cic_deposit)(&position[0], &position[1], &position[2], - &GridRank,&np,&MassRem, BaryonField[DensNum], LeftEdge, - &GridDimension[0], &GridDimension[1], &GridDimension[2], - &CellWidth[0][0], &cloudSize); - if (debug) fprintf(stdout, "PIII Mass: %f\n", FinalMass); - if (FinalMass > PISNLowerMass && FinalMass < PISNUpperMass){ - HeCoreMass = (13./24.)*(FinalMass-20); - SNEnergy = (5.0+1.304*(HeCoreMass-64))*1e51; - EjectaMetal = HeCoreMass; - } - if (FinalMass > TypeIILowerMass && FinalMass < TypeIIUpperMass){ - SNEnergy = 1e51; - EjectaMetal = 0.1077+0.3383*(FinalMass-11); - } - if (FinalMass > HNLowerMass && FinalMass < HNUpperMass){ - int bin = search_lower_bound((float*)SNExplosionMass, FinalMass, 0, 5, 5); - float frac = (SNExplosionMass[bin+1] - FinalMass) / - (SNExplosionMass[bin+1] - SNExplosionMass[bin]); - SNEnergy = 1e51 * (SNExplosionEnergy[bin] + - frac * (SNExplosionEnergy[bin+1] - SNExplosionEnergy[bin])); - EjectaMetal = (SNExplosionMetals[bin] + - frac * (SNExplosionMetals[bin+1] - SNExplosionMetals[bin])); - } - /* Need mu_field for deposition routine */ - - float mu_field [size]; - for (int k = GridStartIndex[2]; k <= GridEndIndex[2]; k++) { - for (int j = GridStartIndex[1]; j <= GridEndIndex[1]; j++) { - for (int i = GridStartIndex[0]; i <= GridEndIndex[0]; i++) { - - index = i + j*GridDimension[0] + k*GridDimension[0]*GridDimension[1]; - mu_field[index] = 0.0; - // calculate mu - - if (MultiSpecies == 0) { - mu_field[index] = Mu; - } else { - - if (IdentifySpeciesFields(DeNum, HINum, HIINum, HeINum, HeIINum, HeIIINum, - HMNum, H2INum, H2IINum, DINum, DIINum, HDINum) == FAIL) { - ENZO_FAIL("Error in grid->IdentifySpeciesFields.\n"); - } - - mu_field[index] = BaryonField[DeNum][index] + BaryonField[HINum][index] + BaryonField[HIINum][index] + - (BaryonField[HeINum][index] + BaryonField[HeIINum][index] + BaryonField[HeIIINum][index])/4.0; - if (MultiSpecies > 1) { - mu_field[index] += BaryonField[HMNum][index] + (BaryonField[H2INum][index] + BaryonField[H2IINum][index])/2.0; - } - if (MultiSpecies > 2) { - mu_field[index] += (BaryonField[DINum][index] + BaryonField[DIINum][index])/2.0 + (BaryonField[HDINum][index]/3.0); - } - - } - } - } - } - /* Add this to the grid using MechStars_DepositFeedback */ - float vp=0, up=0, wp=0; - if (debug) fprintf(stdout, "Calling DepositFeedback!\n"); - this->MechStars_DepositFeedback(SNEnergy, EjectaMass, EjectaMetal, totalMetal,temperature, - &up, &vp, &wp, &position[0], &position[1], &position[2], - ip, jp, kp, size, mu_field, 0, 0, 0, 0, 1); - - return SUCCESS; -} From a931f528dd7e21d19cab1507d12dc7b619c9f14f Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 11:46:47 +0100 Subject: [PATCH 107/115] Removing more mech files from this branch --- src/enzo/Make.config.objects | 1 - src/enzo/MechStars_calcPhotonRates.C | 59 ------ src/enzo/MechStars_checkCreationCriteria.C | 196 ------------------ src/enzo/MechStars_depositEmissivity.C | 92 -------- src/enzo/MechStars_determineWinds.C | 68 ------ .../MechStars_transformComovingWithStar.C | 56 ----- src/enzo/cic_deposit_mech_stars.F | 189 ----------------- 7 files changed, 661 deletions(-) delete mode 100644 src/enzo/MechStars_calcPhotonRates.C delete mode 100644 src/enzo/MechStars_checkCreationCriteria.C delete mode 100644 src/enzo/MechStars_depositEmissivity.C delete mode 100644 src/enzo/MechStars_determineWinds.C delete mode 100644 src/enzo/MechStars_transformComovingWithStar.C delete mode 100755 src/enzo/cic_deposit_mech_stars.F diff --git a/src/enzo/Make.config.objects b/src/enzo/Make.config.objects index e06b7896b..b134410c2 100644 --- a/src/enzo/Make.config.objects +++ b/src/enzo/Make.config.objects @@ -76,7 +76,6 @@ OBJS_CONFIG_LIB = \ CheckShearingBoundaryConsistency.o \ chtable.o \ cic_deposit.o \ - cic_deposit_mech_stars.o \ cic_deposit_c.o \ cic_flag.o \ cic_flag_c.o \ diff --git a/src/enzo/MechStars_calcPhotonRates.C b/src/enzo/MechStars_calcPhotonRates.C deleted file mode 100644 index c6ebf9d0c..000000000 --- a/src/enzo/MechStars_calcPhotonRates.C +++ /dev/null @@ -1,59 +0,0 @@ -/* - Calculates the luminosity of a mechanical star based on Hopkins 2018 - */ -#include -#include -#include -#include -#include "ErrorExceptions.h" -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "fortran.def" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" -//#include "gFLDProblem.h" - - -int MechStars_calcPhotonRates(Star* star, const float Time) -{ - // Modeling after fFLDSplit_RadiationSource.F90 to fill in Emissivity0 field. - // etaconst = h_nu0*NGammaDot*specconst/dV - // specconst ~ scaling factor for spectrum -> varies depeding on user choice of tracked radiation - // dV ~ proper volume of cell - // NGammaDot ~ photons per second. -> this will vary depending on age of particle! - const float LsunToErg = 3.85e33; // erg/s - const float evPerErg = 6.2415e11; - const float h_nu0 = 13.6/evPerErg; // erg - float age = Time - star->ReturnBirthTime(); - /* - Calculate rates of photons given the age-based luminosity in Hopkins 2017. Units are - L_sun/M_sun. While they are given, we dont bother with IR/optical bands here. - We only couple the ionizing radiation, Psi_ion. The others are calculated if they happen - to be used in the future. - */ - float Psi_fuv = 0.0, Psi_ion = 0.0; - if (age < 3.4){ - Psi_fuv = 271. * (1.0 + (age/3.4)*(age/3.4)); - } - if (age < 3.5){ - Psi_ion = 500; - } - if (age > 3.5 && age < 25){ - Psi_ion = 60.*pow(age/3.5, -3.6)+470*pow(age/3.5, 0.045-1.82*log(age)); - } - if (age > 3.4){ - Psi_fuv = 572.*pow(age/3.4, -1.5); - } - // convert to better units - //Psi_ion *= star->ReturnMass(); // L_sun - return Psi_ion; - - return SUCCESS; -} - diff --git a/src/enzo/MechStars_checkCreationCriteria.C b/src/enzo/MechStars_checkCreationCriteria.C deleted file mode 100644 index facd5773f..000000000 --- a/src/enzo/MechStars_checkCreationCriteria.C +++ /dev/null @@ -1,196 +0,0 @@ - /* - Routine actually checks to see whether the input grid - is capable of star formation - - 07/2019: Azton Wells - */ -#include -#include -#include -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "fortran.def" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" - - int GetUnits(float *DensityUnits, float *LengthUnits, - float *TemperatureUnits, float *TimeUnits, - float *VelocityUnits, float *MassUnits, float Time); -#define PASS 1; -int checkCreationCriteria(float* Density, float* Metals, - float* Temperature,float* DMField, - float* Vel1, float* Vel2, float* Vel3, float* TotE, - float* CoolingTime, int* GridDim, - float* shieldedFraction, float* freeFallTime, - float* dynamicalTime, int i, int j, int k, - float Time, float* RefinementField, float CellWidth, - bool* gridShouldFormStars, bool* notEnoughMetals, - int continuingFormation, int* seedIndex) -{ - float Zsolar = 0.02; - float maxZ = 0.0; - bool debug = false; - bool status = PASS; - float DensityUnits = 1, LengthUnits = 1, TemperatureUnits = 1, - TimeUnits = 1, VelocityUnits = 1, MassUnits = 1; - if (GetUnits(&DensityUnits, &LengthUnits, &TemperatureUnits, - &TimeUnits, &VelocityUnits, &MassUnits, Time) == FAIL) { - fprintf(stderr, "Error in GetUnits.\n"); - return FAIL; - } - MassUnits = DensityUnits*pow(LengthUnits*CellWidth, 3); - int index = i+j*GridDim[0]+k*GridDim[0]*GridDim[1]; - int iminus = index-1; - int iplus = index+1; - int jminus =i+(j-1)*GridDim[0]+k*GridDim[0]*GridDim[1]; - int jplus = i+(j+1)*GridDim[0]+k*GridDim[0]*GridDim[1]; - int kminus = i+j*GridDim[0]+(k-1)*GridDim[0]*GridDim[1]; - int kplus = i+j*GridDim[0]+(k+1)*GridDim[0]*GridDim[1]; - /* - Checking creation criteria! - */ - // if this isnt finest grid in this space, continue - //if (RefinementField[index] != 0) return FAIL; - /* Baryon overdensity. Take a local mean, but - weight the central cell more*/ - float dmean = (Density[index]*10.0+Density[iminus] - + Density[iplus]+Density[jplus] - + Density[jminus]+Density[kminus] - + Density[kplus])/17.0 * DensityUnits / (mh/0.6); - if (dmean < StarMakerOverDensityThreshold) - { - return FAIL; - } - // if (debug && status) fprintf(stdout, "Passed Density: %e: %e\n", - // dmean,StarMakerOverDensityThreshold); - /* in addition to the converging flow check, we check - the virial parameter of the gas to see if it is - locally gravitationally bound*/ - // check that metals exist in enough quantity - if (Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity) - return FAIL; - - float div = 0.0; //divergence - float alpha = 0.0; //virial parameter - float vfactor= 0.0; //norm of velocity gradient tensor - float cSound = 0.0; //sound speed - float dxvx, dxvy, dxvz, dyvx, dyvy, dyvz, dzvx, dzvy, dzvz; - dxvx = (Vel1[iplus] - Vel1[iminus])/2.0; - dxvy = (Vel2[iplus] - Vel2[iminus])/2.0; - dxvz = (Vel3[iplus] - Vel3[iminus])/2.0; - - dyvx = (Vel1[jplus] - Vel1[jminus])/2.0; - dyvy = (Vel2[jplus] - Vel2[jminus])/2.0; - dyvz = (Vel3[jplus] - Vel3[jminus])/2.0; - - dzvx = (Vel1[kplus] - Vel1[kminus])/2.0; - dzvy = (Vel2[kplus] - Vel2[kminus])/2.0; - dzvz = (Vel3[kplus] - Vel3[kminus])/2.0; - - /* Chck for converging flow */ - - div = dxvx+dyvy+dzvz; - if (div > 0.0) return FAIL; - - /* check for virial parameter */ - - vfactor = (dxvx*dxvx+dxvy*dxvy+dxvz*dxvz - +dyvx*dyvx+dyvy*dyvy+dyvz*dyvz - +dzvx*dzvx+dzvy*dzvy+dzvz*dzvz); - - /* approximate taking gas as monatomic and mu = 0.6*/ - /* Gravitational constant [cm3g-1s-2]*/ - float Gcode = GravConst*DensityUnits*pow(TimeUnits,2); - float KBcode = kboltz*MassUnits/(LengthUnits*CellWidth)/pow(TimeUnits,2); - cSound = sqrt(5/3*kboltz*Temperature[index]/mh/0.6)/VelocityUnits; - alpha = ((vfactor) + pow(cSound/(CellWidth), 2.0)) - / (8.0 * M_PI* Gcode * Density[index]); - - float AltAlpha = TotE[index]*MassUnits / (8.0 * M_PI * GravConst/MassUnits); - - - if (alpha > 1.0) return FAIL; - /* Is cooling time < dynamical time or temperature < 1e4 */ - - if (Temperature[index] > 1e4) - { - if (MultiSpecies > 0) return FAIL; //no hot gas forming stars! - float totalDensity = (Density[index] - +DMField[index])*DensityUnits; - *dynamicalTime = pow(3.0*pi/32.0/GravConst/totalDensity, 0.5); - if (*dynamicalTime/TimeUnits < CoolingTime[index]) - return FAIL; - } - /* is gas mass > critical jeans mass? */ - - float baryonMass = Density[index]*DensityUnits - *LengthUnits*LengthUnits*LengthUnits - *CellWidth*CellWidth*CellWidth - /SolarMass; - float IsoSndSpeed = 1.3095e8 * Temperature[index]; - float jeansMass = pi/(6.0*pow(Density[index]*DensityUnits, 0.5)) - *pow(pi*IsoSndSpeed/GravConst, 1.5)/SolarMass; - float altJeans = 2 * pow(cSound*VelocityUnits/1e5/0.2, 3) * pow((Density[index]*DensityUnits/(mh/0.6)/1e3), -0.5); - if (jeansMass > max(baryonMass, 1e3)) return FAIL; - - /* Is self Shielded fraction > 0.0 by Krumholz & Gnedin */ - - float gradRho = (Density[index+1]-Density[index-1]) - *(Density[index+1]-Density[index-1]); - gradRho += (Density[jplus]-Density[jminus]) - *(Density[jplus]-Density[jminus]); - gradRho += (Density[kplus]-Density[kminus]) - *(Density[kplus]-Density[kminus]); - gradRho = pow(gradRho, 0.5); - // factors were given in physical units - float TauFactor = 434.8/*cm**2/g*/ * MassUnits/pow(LengthUnits*CellWidth, 2); // cm**2/g - float Tau = TauFactor * Density[index] *(CellWidth+Density[index]/gradRho); - - float Phi = 0.756*pow(1+3.1*Metals[index]/Density[index]/Zsolar, 0.365); - - float Psi = 0.6*Tau*(0.01+Metals[index]/Density[index]/Zsolar)/ - log(1+0.6*Phi+0.01*Phi*Phi); - *shieldedFraction = 1.0 - 3.0/(1.0+4.0*Psi); - // if (debug) - // fprintf(stdout, "FS parts: Tau = %"GSYM" Phi = %"GSYM" Psi = %"GSYM" FS = %"GSYM"\n", - // Tau, Phi, Psi, *shieldedFraction); - - if (*shieldedFraction < 0) status = FAIL; - - *freeFallTime = pow(3*(pi/(32*GravConst*Density[index]*DensityUnits)), 0.5)/TimeUnits; // that theres code-time - if (status && debug) - { - fprintf(stdout, "Check Creation positive! n_b = %"GSYM" M_b = %"GSYM" gradRho = %"GSYM" Fs = %"FSYM" M_j = %"GSYM" VirialPar = %"FSYM" divergence = %"FSYM" Temperature = %"GSYM" cSnd = %"GSYM" AltJeans = %"GSYM" AltAlpha = %"GSYM" Z = %"GSYM"\n", - dmean, baryonMass, gradRho, *shieldedFraction, jeansMass, alpha, div, Temperature[index], cSound*VelocityUnits/1e5, altJeans, Metals[index]/Density[index]/0.02); - } - //if (status && debug) fprintf(stdout, "passed creation criteria\n"); - if (MechStarsSeedField && Metals[index]/Density[index]/0.02 > MechStarsCriticalMetallicity && !continuingFormation) - *notEnoughMetals = false; - if (status && (Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity)){ - status = FAIL; - } - - else if (status && Metals[index]/Density[index]/0.02 < MechStarsCriticalMetallicity && MechStarsSeedField - && !continuingFormation) - { - // if (debug) fprintf(stdout,"No metals, criteria passed, but not forming\n"); - status = FAIL; - /* May want to qualify this with H2 fraction/H2 self-shield approximations, but - This is really just to give a non-uniform seed-field in Pop3 metals*/ - *gridShouldFormStars = true; - if (Metals[index]/Density[index]/0.02 > maxZ) maxZ = Metals[index]/Density[index]/0.02; - /* Store index of this grid to potentially be center of P3 seed later */ - seedIndex[0] = i; - seedIndex[1] = j; - seedIndex[2] = k; - } - - return status; - -} diff --git a/src/enzo/MechStars_depositEmissivity.C b/src/enzo/MechStars_depositEmissivity.C deleted file mode 100644 index 6ef71e7cc..000000000 --- a/src/enzo/MechStars_depositEmissivity.C +++ /dev/null @@ -1,92 +0,0 @@ -/* - - *** CURRENTLY UNTESTED AND UNUSED *** - Couples the mechanical stars to the radiation machinery in ENZO by filling - in the emissivity0 field. - Code must be compiled with "make emissivity-yes" and "make photon-yes". - Usage at runtime determined by the StarMakerUseEmissivity flag. - Unlike the CIC depositions in the rest of this module, the emissivity is set - solely for the cell hosting the star particle (or its kicked location). - - The radiation deposited here is time varying depending on the age of the particle (and mass). - A better implementation will make the individual bands of radiation time dependent - (more UV early, more IR late). - */ -#include -#include -#include -#include -#include "ErrorExceptions.h" -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "fortran.def" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" -//#include "gFLDProblem.h" - -int MechStars_depositEmissivityField(int index, float cellwidth, - float* emissivity0, float age, float mass, - float TimeUnits, float dt) -{ - // Modeling after fFLDSplit_RadiationSource.F90 to fill in Emissivity0 field. - // etaconst = h_nu0*NGammaDot*specconst/dV - // specconst ~ scaling factor for spectrum -> varies depeding on user choice of tracked radiation - // dV ~ proper volume of cell - // NGammaDot ~ photons per second. -> this will vary depending on age of particle! - const float LsunToErg = 3.85e33; // erg/s - const float evPerErg = 6.2415e11; - const float h_nu0 = 13.6/evPerErg; // erg - /* - Calculate rates of photons given the age-based luminosity in Hopkins 2017. Units are - L_sun/M_sun. While they are given, we dont bother with IR/optical bands here. - We only couple the ionizing radiation, Psi_ion. The others are calculated if they happen - to be used in the future. - */ - float Psi_fuv = 0.0, Psi_ion = 0.0; - if (age < 3.4){ - Psi_fuv = 271. * (1.0 + (age/3.4)*(age/3.4)); - } - if (age < 3.5){ - Psi_ion = 500; - } - if (age > 3.5 && age < 25){ - Psi_ion = 60.*pow(age/3.5, -3.6)+470*pow(age/3.5, 0.045-1.82*log(age)); - } - if (age > 3.4){ - Psi_fuv = 572.*pow(age/3.4, -1.5); - } - // convert to better units - Psi_ion *= mass; // L_sun - Psi_ion *= LsunToErg/TimeUnits*dt; // erg/code_time - /* - assuming all those photons are in the HI ionization range, the number - of photons is - */ - float NGammaDot = Psi_ion / h_nu0; - - - // /* - // Select spectrum scaling based on parameters - // (probably just HI radiation for now) - // This routine only works with HI radiation for now, as the - // rest of the rates would require another Starburst99 sim to get - // */ - if (MechStarsRadiationSpectrum != -1){ - ENZO_FAIL("MechStars only implemented for RadHydroESpectrum = -1\n"); - } - const float specconst = 1.0; - - /* - Apply selected to Emissivity0 in the form of etaconst. - */ - emissivity0[index] += pow(cellwidth, 3.0)*specconst*NGammaDot*h_nu0; - - return SUCCESS; -} - diff --git a/src/enzo/MechStars_determineWinds.C b/src/enzo/MechStars_determineWinds.C deleted file mode 100644 index 200ea3566..000000000 --- a/src/enzo/MechStars_determineWinds.C +++ /dev/null @@ -1,68 +0,0 @@ -/* - Determines wind feedback parameters according to fits in Hopkins 2017: - These fits are known to be erroneous, need to re-run and fit using SB99 sims. - - 07/2019: Azton Wells - */ - -#include -#include -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" - -int determineWinds(float age, float* eWinds, float* mWinds, float* zWinds, - float massMsun, float zZsun, float TimeUnits, float dtFixed){ - float Zsolar = 0.02; - bool oldEnough = (age < 0.0001)?(false):(true); - float windE = 0, windM = 0, windZ = 0.0; - float wind_factor = 0.0; - float e_factor = 0.0; - // I dont want to deal with new particles - // printf("Computing Winds for age = %f, Msun = %e\n", age, massMsun); - if (StellarWinds && oldEnough && massMsun > 11){ - - if (0.001 < age && age < 1.0){ - wind_factor =4.763 * min((0.01 + zZsun), 1.0) ; - } - if (1 <= age && age < 3.5){ - wind_factor = 4.763*min(0.01+zZsun, 1.0)* - pow(age, 1.45+0.08*min(log(zZsun), 1.0)); - } - if (3.5 <= age && age < 100){ - wind_factor = 29.4*pow(age/3.5, -3.25)+0.0042; - - } - if (age < 100){ - float d = powl(1+age/2.5, 1.4); - float a50 = powl(double(age)/10.0, 5.0); - e_factor = 5.94e4 / d + a50 +4.83; - - } - if (100 <= age){ - e_factor = 4.83; - wind_factor = 0.42*pow(age/1000, -1.1)/(19.81/log(age)); - } - windM = massMsun * wind_factor; //Msun/Gyr - windM = windM*dtFixed*TimeUnits/(1e3 * Myr_s); //Msun - // if (debug) printf("First winds mass = %e\nFrom wf = %f, dt=%f Z = %e\n", windM, wind_factor, dtFixed, zZsun); - //printf("eFactor = %f age = %f\n", e_factor, age); - if (windM > massMsun){ - printf("Winds too large Mw = %e, Mp = %e age=%f, Z = %e\n", - windM, massMsun, age, zZsun); - windM = 0.125*massMsun; // limit loss to huge if necessary. - } - windZ = max(Zsolar, 0.016+0.0041*max(zZsun, 1.65)+0.0118)*windM; - windE = e_factor * 1e12 * windM; - //fprintf(stdout, "Age = %e Ewinds = %e Mwinds = %e Zwinds = %e Zsun = %e\n", - // age, windE, windM, windZ, zZsun); - *mWinds = windM; - *zWinds = windZ; - *eWinds = windE; - } - - return SUCCESS; -} \ No newline at end of file diff --git a/src/enzo/MechStars_transformComovingWithStar.C b/src/enzo/MechStars_transformComovingWithStar.C deleted file mode 100644 index 45ab26d5a..000000000 --- a/src/enzo/MechStars_transformComovingWithStar.C +++ /dev/null @@ -1,56 +0,0 @@ - - -#include -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "StarParticleData.h" - -int transformComovingWithStar(float* Density, float* Metals, - float* MetalsSNII, float* MetalsSNIA, - float* Vel1, float* Vel2, float* Vel3, - float* TE, float* GE, - float up, float vp, float wp, - int sizeX, int sizeY, int sizeZ, int direction){ - /* - transform velocities to momenta or back and make them comoving with the star particle - Metals are still densities here for CIC deposition. NB Metal transform to - fractions in Grid_StarParticleHandler is skipped for this method. Energy fields - are transformed from specific energy to just energy to facilitate CIC deposition - - */ - int size = sizeX*sizeY*sizeZ; - if (direction > 0){ - - /* To comoving with star */ - for (int ind = 0; ind < size; ++ind){ - float mult = Density[ind]; - TE[ind] *= mult; - GE[ind] *= mult; - float preV = Vel1[ind]; - Vel1[ind] = (preV-up)*mult; - preV = Vel2[ind]; - Vel2[ind] = (preV-vp)*mult; - preV = Vel3[ind]; - Vel3[ind] = (preV-wp)*mult; - - - } - } - if (direction < 0){ - - /* - back to "lab" frame - */ - for (int ind = 0; ind < size; ++ind){ - float mult = 1./Density[ind]; - TE[ind] *= mult; - GE[ind] *= mult; - Vel1[ind] = Vel1[ind]*mult+up; - Vel2[ind] = Vel2[ind]*mult+vp; - Vel3[ind] = Vel3[ind]*mult+wp; - - } - } - return SUCCESS; - -} \ No newline at end of file diff --git a/src/enzo/cic_deposit_mech_stars.F b/src/enzo/cic_deposit_mech_stars.F deleted file mode 100755 index 4b45b0ae7..000000000 --- a/src/enzo/cic_deposit_mech_stars.F +++ /dev/null @@ -1,189 +0,0 @@ -#include "fortran.def" - -c======================================================================= -c////////////////////// SUBROUTINE CIC_DEPOSIT \\\\\\\\\\\\\\\\\\\\\\\ -c - subroutine cic_deposit_ms(posx, posy, posz, ndim, npositions, - & mass, field, leftedge, - & dim1, dim2, dim3, cellsize) -c -c PERFORMS 1/2/3D CLOUD-IN-CELL INTERPOLATION FROM FIELD TO SUMFIELD -c -c written by: Greg Bryan -c date: January, 1998 -c modified1: -c -c PURPOSE: This routine performs a three-dimension, second-order -c interpolation from field to sumfield (without clearing sumfield -c first) at the positions specified. -c -c INPUTS: -c ndim - dimensionality -c cellsize - the cell size of field -c dim1,2,3 - real dimensions of field -c leftedge - the left edge(s) of field -c npositions - number of particles -c posx,y,z - particle positions -c sumfield - 1D field (length npositions) of masses -c -c OUTPUT ARGUMENTS: -c field - field to be deposited to -c -c EXTERNALS: -c -c LOCALS: -c -c----------------------------------------------------------------------- -c - implicit NONE -#include "fortran_types.def" -c -c----------------------------------------------------------------------- -c -c argument declarations -c - INTG_PREC dim1, dim2, dim3, npositions, ndim - P_PREC posx(npositions), posy(npositions), posz(npositions) - R_PREC leftedge(3) - R_PREC mass(npositions) - R_PREC field(dim1, dim2, dim3) - R_PREC cellsize -c -c locals -c - INTG_PREC iii, jjj, kkk - INTG_PREC i1, j1, k1, n - R_PREC xpos, ypos, zpos, dx, dy, dz, fact - R_PREC edge1, edge2, edge3, half - parameter (half = 0.5001) -c -c\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////// -c======================================================================= -c - -! write(0,*) npositions, leftedge, dim1, dim2, dim3, cellsize - - fact = 1.0/cellsize - edge1 = real(dim1) - half - edge2 = real(dim2) - half - edge3 = real(dim3) - half -c -c 1D -c - if (ndim .eq. 1) then -c - do n=1, npositions -c -c Compute the position of the central cell -c - xpos = min(max((posx(n) - leftedge(1))*fact, half), edge1) -c -c Convert this into an integer index -c - i1 = int(xpos + 0.5) -c -c Compute the weights -c - dx = real(i1) + 0.5 - xpos -c -c Interpolate from field into sumfield -c - field(i1 ,1,1) = field(i1 ,1,1) + mass(n)*dx - field(i1+1,1,1) = field(i1+1,1,1) + mass(n)*(1.0-dx) -c - enddo -c - endif -c -c 2D -c - if (ndim .eq. 2) then -c - do n=1, npositions -c -c Compute the position of the central cell -c - xpos = min(max((posx(n) - leftedge(1))*fact, half), edge1) - ypos = min(max((posy(n) - leftedge(2))*fact, half), edge2) -c -c Convert this into an integer index -c - i1 = int(xpos + 0.5) - j1 = int(ypos + 0.5) -c -c Compute the weights -c - dx = real(i1) + 0.5 - xpos - dy = real(j1) + 0.5 - ypos -c -c Interpolate from field into sumfield -c - field(i1 ,j1 ,1) = field(i1 ,j1 ,1) + - & mass(n)* dx * dy - field(i1+1,j1 ,1) = field(i1+1,j1 ,1) + - & mass(n)*(1.0-dx)* dy - field(i1 ,j1+1,1) = field(i1 ,j1+1,1) + - & mass(n)* dx *(1.0-dy) - field(i1+1,j1+1,1) = field(i1+1,j1+1,1) + - & mass(n)*(1.0-dx)*(1.0-dy) -c - enddo -c - endif -c -c 3D -c - if (ndim .eq. 3) then -c - do n=1, npositions -c -c Compute the position of the central cell -c - xpos = min(max((posx(n) - leftedge(1))*fact, half), edge1) - ypos = min(max((posy(n) - leftedge(2))*fact, half), edge2) - zpos = min(max((posz(n) - leftedge(3))*fact, half), edge3) -c -c Convert this into an integer index -c - i1 = int(xpos + 0.5) - j1 = int(ypos + 0.5) - k1 = int(zpos + 0.5) -c -c Compute the weights -c - dx = real(i1) + 0.5 - xpos - dy = real(j1) + 0.5 - ypos - dz = real(k1) + 0.5 - zpos -c -c Interpolate from field into sumfield -c - field(i1 ,j1 ,k1 ) = field(i1 ,j1 ,k1 ) + - & mass(n)* dx * dy * dz - field(i1+1,j1 ,k1 ) = field(i1+1,j1 ,k1 ) + - & mass(n)*(1.0-dx)* dy * dz - field(i1 ,j1+1,k1 ) = field(i1 ,j1+1,k1 ) + - & mass(n)* dx *(1.0-dy)* dz - field(i1+1,j1+1,k1 ) = field(i1+1,j1+1,k1 ) + - & mass(n)*(1.0-dx)*(1.0-dy)* dz - field(i1 ,j1 ,k1+1) = field(i1 ,j1 ,k1+1) + - & mass(n)* dx * dy *(1.0-dz) - field(i1+1,j1 ,k1+1) = field(i1+1,j1 ,k1+1) + - & mass(n)*(1.0-dx)* dy *(1.0-dz) - field(i1 ,j1+1,k1+1) = field(i1 ,j1+1,k1+1) + - & mass(n)* dx *(1.0-dy)*(1.0-dz) - field(i1+1,j1+1,k1+1) = field(i1+1,j1+1,k1+1) + - & mass(n)*(1.0-dx)*(1.0-dy)*(1.0-dz) -c - enddo - -! do kkk=1,dim3 -! write(0,'("K = ",i2)') kkk -! do jjj=1,dim2 -! write(0,'((14(1pe8.1)))')(field(iii,jjj,kkk),iii=1,dim1) -! end do -! end do - - endif - - return - end From 16ab1ef9342443e86d14747f723ef395266d3036 Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 12:06:40 +0100 Subject: [PATCH 108/115] Removing mechanical star stuff out of this branch --- src/enzo/InitializeNew.C | 2 +- src/enzo/MechStars_depositEmissivityField.C | 91 --------------------- src/enzo/RadiativeTransferInitialize.C | 2 - src/enzo/ReadParameterFile.C | 2 - src/enzo/StarParticleData.h | 1 - src/enzo/StarParticlePopIII_IMFInitialize.C | 2 +- src/enzo/Star_Accrete.C | 3 +- src/enzo/Star_AssignFinalMassFromIMF.C | 3 +- src/enzo/Star_CalculateFeedbackParameters.C | 5 +- src/enzo/Star_IsARadiationSource.C | 6 +- src/enzo/WriteParameterFile.C | 2 - 11 files changed, 6 insertions(+), 113 deletions(-) delete mode 100644 src/enzo/MechStars_depositEmissivityField.C diff --git a/src/enzo/InitializeNew.C b/src/enzo/InitializeNew.C index 267f98471..b8adf7b22 100644 --- a/src/enzo/InitializeNew.C +++ b/src/enzo/InitializeNew.C @@ -315,7 +315,7 @@ int InitializeNew(char *filename, HierarchyEntry &TopGrid, if (StarParticleCreation || StarParticleFeedback) { NumberOfParticleAttributes = 3; if (StarMakerTypeIaSNe) NumberOfParticleAttributes++; - // if (StarMakerTypeIISNeMetalField) NumberOfParticleAttributes++; + if (StarMakerTypeIISNeMetalField) NumberOfParticleAttributes++; } else { NumberOfParticleAttributes = 0; } diff --git a/src/enzo/MechStars_depositEmissivityField.C b/src/enzo/MechStars_depositEmissivityField.C deleted file mode 100644 index e4f0c5b98..000000000 --- a/src/enzo/MechStars_depositEmissivityField.C +++ /dev/null @@ -1,91 +0,0 @@ -/* - Couples the mechanical stars to the radiation machinery in ENZO by filling - in the emissivity0 field. - Code must be compiled with "make emissivity-yes" and "make photon-yes". - Usage at runtime determined by the StarMakerUseEmissivity flag. - Unlike the CIC depositions in the rest of this module, the emissivity is set - solely for the cell hosting the star particle (or its kicked location). - - The radiation deposited here is time varying depending on the age of the particle (and mass). - A better implementation will make the individual bands of radiation time dependent - (more UV early, more IR late). - */ -#include -#include -#include -#include -#include "ErrorExceptions.h" -#include "macros_and_parameters.h" -#include "typedefs.h" -#include "global_data.h" -#include "Fluxes.h" -#include "GridList.h" -#include "ExternalBoundary.h" -#include "Grid.h" -#include "fortran.def" -#include "CosmologyParameters.h" -#include "StarParticleData.h" -#include "phys_constants.h" -//#include "gFLDProblem.h" - - -int MechStars_calcPhotonRates(Star* star, const float Time) -{ - // Modeling after fFLDSplit_RadiationSource.F90 to fill in Emissivity0 field. - // etaconst = h_nu0*NGammaDot*specconst/dV - // specconst ~ scaling factor for spectrum -> varies depeding on user choice of tracked radiation - // dV ~ proper volume of cell - // NGammaDot ~ photons per second. -> this will vary depending on age of particle! - const float LsunToErg = 3.85e33; // erg/s - const float evPerErg = 6.2415e11; - const float h_nu0 = 13.6/evPerErg; // erg - float age = Time - star->ReturnBirthTime(); - /* - Calculate rates of photons given the age-based luminosity in Hopkins 2017. Units are - L_sun/M_sun. While they are given, we dont bother with IR/optical bands here. - We only couple the ionizing radiation, Psi_ion. The others are calculated if they happen - to be used in the future. - */ - float Psi_fuv = 0.0, Psi_ion = 0.0; - if (age < 3.4){ - Psi_fuv = 271. * (1.0 + (age/3.4)*(age/3.4)); - } - if (age < 3.5){ - Psi_ion = 500; - } - if (age > 3.5 && age < 25){ - Psi_ion = 60.*pow(age/3.5, -3.6)+470*pow(age/3.5, 0.045-1.82*log(age)); - } - if (age > 3.4){ - Psi_fuv = 572.*pow(age/3.4, -1.5); - } - // convert to better units - Psi_ion *= star->ReturnMass(); // L_sun - return Psi_ion; - // Psi_ion *= LsunToErg/TimeUnits*dt; // erg/code_time - // /* - // assuming all those photons are in the HI ionization range, the number - // of photons is - // */ - // float NGammaDot = Psi_ion / h_nu0; - - - // /* - // Select spectrum scaling based on parameters - // (probably just HI radiation for now) - // This routine only works with HI radiation for now, as the - // rest of the rates would require another Starburst99 sim to get - // */ - // if (MechStarsRadiationSpectrum != -1){ - // ENZO_FAIL("MechStars only implemented for RadHydroESpectrum = -1\n"); - // } - // const float specconst = 1.0; - - // /* - // Apply selected to Emissivity0 in the form of etaconst. - // */ - // emissivity0[index] += pow(cellwidth, 3.0)*specconst*NGammaDot*h_nu0; - - return SUCCESS; -} - diff --git a/src/enzo/RadiativeTransferInitialize.C b/src/enzo/RadiativeTransferInitialize.C index 0147f83aa..d6ba4b7fc 100644 --- a/src/enzo/RadiativeTransferInitialize.C +++ b/src/enzo/RadiativeTransferInitialize.C @@ -208,7 +208,6 @@ int RadiativeTransferInitialize(char *ParameterFile, } if (StarClusterUseMetalField && SmartStarFeedback > 0) { - printf("JR: Adding SS field"); TypesToAdd[FieldsToAdd++] = Metallicity; AddedMetallicity = true; } @@ -291,7 +290,6 @@ int RadiativeTransferInitialize(char *ParameterFile, "from %"ISYM" to %"ISYM"\n", OldNumberOfBaryonFields, OldNumberOfBaryonFields+FieldsToAdd); - printf("JR: OldNumberOfBaryonFields+FieldsToAdd = %d\n", OldNumberOfBaryonFields+FieldsToAdd); // Add an extra 1 because we will need it for flagging/marking cells. if (OldNumberOfBaryonFields+FieldsToAdd+1 > MAX_NUMBER_OF_BARYON_FIELDS) ENZO_FAIL("Exceeds MAX_NUMBER_OF_BARYON_FIELDS. " diff --git a/src/enzo/ReadParameterFile.C b/src/enzo/ReadParameterFile.C index 1296ef5fb..0652d07e9 100644 --- a/src/enzo/ReadParameterFile.C +++ b/src/enzo/ReadParameterFile.C @@ -1050,8 +1050,6 @@ int ReadParameterFile(FILE *fptr, TopGridData &MetaData, float *Initialdt) &PopIIISupernovaMustRefine); ret += sscanf(line, "PopIIISupernovaMustRefineResolution = %"ISYM, &PopIIISupernovaMustRefineResolution); - ret += sscanf(line, "PopIIIMustRefineRegionLifetime = %"FSYM, - &PopIIIMustRefineRegionLifetime); ret += sscanf(line, "PopIIIHeliumIonization = %"ISYM, &PopIIIHeliumIonization); diff --git a/src/enzo/StarParticleData.h b/src/enzo/StarParticleData.h index a77434e49..ce2faa397 100644 --- a/src/enzo/StarParticleData.h +++ b/src/enzo/StarParticleData.h @@ -96,7 +96,6 @@ SPEXTERN float PopIIIColorMass; SPEXTERN int PopIIIUseHypernova; SPEXTERN int PopIIISupernovaExplosions; SPEXTERN int PopIIIOutputOnFeedback; -SPEXTERN float PopIIIMustRefineRegionLifetime; SPEXTERN int StarClusterUseMetalField; SPEXTERN int StarClusterHeliumIonization; diff --git a/src/enzo/StarParticlePopIII_IMFInitialize.C b/src/enzo/StarParticlePopIII_IMFInitialize.C index fbe097cfc..9ca0f2c28 100644 --- a/src/enzo/StarParticlePopIII_IMFInitialize.C +++ b/src/enzo/StarParticlePopIII_IMFInitialize.C @@ -58,7 +58,7 @@ int StarParticlePopIII_IMFInitialize(void) /* Initialize the random number generator. Call it 1+NumberOfCalls to get the generator back to the same state as it was before the restart (if any). */ - + if (PopIIIInitialMassFunctionSeed == INT_UNDEFINED) mt_init(time(NULL)); //+100*MyProcessorNumber); else diff --git a/src/enzo/Star_Accrete.C b/src/enzo/Star_Accrete.C index 44732dc03..90ac899a4 100644 --- a/src/enzo/Star_Accrete.C +++ b/src/enzo/Star_Accrete.C @@ -31,8 +31,7 @@ int GetUnits(float *DensityUnits, float *LengthUnits, int Star::Accrete(void) { if (this->CurrentGrid == NULL || - (this->naccretions == 0 && fabs(this->DeltaMass) < tiny_number) - || FeedbackFlag == MECHANICAL) // mechanical accretion and feedback handled in mechstars routines + (this->naccretions == 0 && fabs(this->DeltaMass) < tiny_number)) return SUCCESS; diff --git a/src/enzo/Star_AssignFinalMassFromIMF.C b/src/enzo/Star_AssignFinalMassFromIMF.C index 71d65ca77..1d0e49585 100644 --- a/src/enzo/Star_AssignFinalMassFromIMF.C +++ b/src/enzo/Star_AssignFinalMassFromIMF.C @@ -70,8 +70,7 @@ int Star::AssignFinalMassFromIMF(float TimeUnits) // x, this->FinalMass, this->LifeTime * TimeUnits / Myr_s); PopIIIInitialMassFunctionCalls++; - printf("%s: PopIIIInitialMassFunctionCalls(%p) = %d\n", __FUNCTION__, - &PopIIIInitialMassFunctionCalls, PopIIIInitialMassFunctionCalls); + return SUCCESS; } diff --git a/src/enzo/Star_CalculateFeedbackParameters.C b/src/enzo/Star_CalculateFeedbackParameters.C index 7e4a679d3..613c1964e 100644 --- a/src/enzo/Star_CalculateFeedbackParameters.C +++ b/src/enzo/Star_CalculateFeedbackParameters.C @@ -46,7 +46,7 @@ void Star::CalculateFeedbackParameters(float &Radius, const double h=0.70; - const float TypeIILowerMass = 11, TypeIIUpperMass = 40.01; // 40.1->40.01 to be consistent with SNExplosionMass bins -AIW + const float TypeIILowerMass = 11, TypeIIUpperMass = 40.1; const float PISNLowerMass = 140, PISNUpperMass = 260; // From Nomoto et al. (2006) @@ -116,9 +116,6 @@ void Star::CalculateFeedbackParameters(float &Radius, // into some of the surrounding parent grids within the next // timestep if we inject the energy into a small radius. Radius *= 1.0; - // fprintf(stdout, "CalculateFeedbackParamaters: V = %g :: rho = %f :: rho_z = %f :: mass = %f :: metal :: %f\n", - // EjectaVolume, EjectaDensity, EjectaMetalDensity,EjectaVolume*EjectaDensity*DensityUnits/SolarMass, - // EjectaMetalDensity*EjectaVolume/SolarMass*DensityUnits); #define DEBUG #ifdef DEBUG diff --git a/src/enzo/Star_IsARadiationSource.C b/src/enzo/Star_IsARadiationSource.C index c4f6ee6e5..e92c4a0d9 100644 --- a/src/enzo/Star_IsARadiationSource.C +++ b/src/enzo/Star_IsARadiationSource.C @@ -44,15 +44,11 @@ bool Star::IsARadiationSource(FLOAT Time) // Particles only marked for nothing or continuous supernova rules[0] = (FeedbackFlag == NO_FEEDBACK || FeedbackFlag == CONT_SUPERNOVA || - FeedbackFlag == MECHANICAL || FeedbackFlag == MBH_THERMAL || FeedbackFlag == MBH_JETS); // Living - if (FeedbackFlag == MECHANICAL) // MechStars radiate ionizing radiation for 25 Myr - rules[1] = (Time >= BirthTime) && (Time <= BirthTime+LifeTime) && (type > 0); - else // other stars radiate for all time - rules[1] = (Time >= BirthTime) && (type > 0); + rules[1] = (Time >= BirthTime) && (Time <= BirthTime+LifeTime) && (type > 0); // Non-zero BH accretion (usually accretion_rate[] here is NULL - Ji-hoon Kim Sep.2009) if ((type == BlackHole || type == MBH) && naccretions > 0) diff --git a/src/enzo/WriteParameterFile.C b/src/enzo/WriteParameterFile.C index 127677bf3..60e7fcf19 100644 --- a/src/enzo/WriteParameterFile.C +++ b/src/enzo/WriteParameterFile.C @@ -1029,8 +1029,6 @@ int WriteParameterFile(FILE *fptr, TopGridData &MetaData, char *name = NULL) PopIIISupernovaMustRefine); fprintf(fptr, "PopIIISupernovaMustRefineResolution = %"ISYM"\n", PopIIISupernovaMustRefineResolution); - fprintf(fptr, "PopIIIMustRefineRegionLifetime = %"FSYM"\n", - PopIIIMustRefineRegionLifetime); fprintf(fptr, "PopIIIColorDensityThreshold = %"GSYM"\n", PopIIIColorDensityThreshold); fprintf(fptr, "PopIIIColorMass = %"GSYM"\n", From 677b4976b2f18f50f22648f841c58497e2d0786b Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 12:12:51 +0100 Subject: [PATCH 109/115] removing more mechanical star references --- src/enzo/Star_Accrete.C | 2 +- src/enzo/Star_SetFeedbackFlag.C | 5 ----- src/enzo/WriteParameterFile.C | 2 -- src/enzo/macros_and_parameters.h | 5 ++--- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/enzo/Star_Accrete.C b/src/enzo/Star_Accrete.C index 90ac899a4..fa71e9718 100644 --- a/src/enzo/Star_Accrete.C +++ b/src/enzo/Star_Accrete.C @@ -31,7 +31,7 @@ int GetUnits(float *DensityUnits, float *LengthUnits, int Star::Accrete(void) { if (this->CurrentGrid == NULL || - (this->naccretions == 0 && fabs(this->DeltaMass) < tiny_number)) + (this->naccretions == 0 && fabs(this->DeltaMass) < tiny_number)) return SUCCESS; diff --git a/src/enzo/Star_SetFeedbackFlag.C b/src/enzo/Star_SetFeedbackFlag.C index 4f90f68f7..e676409ca 100644 --- a/src/enzo/Star_SetFeedbackFlag.C +++ b/src/enzo/Star_SetFeedbackFlag.C @@ -128,11 +128,6 @@ int Star::SetFeedbackFlag(FLOAT Time) #endif break; - case NormalStar: - //printf("setting feedback flag to %d", MECHANICAL); - this->FeedbackFlag = MECHANICAL; - break; - default: this->FeedbackFlag = NO_FEEDBACK; break; diff --git a/src/enzo/WriteParameterFile.C b/src/enzo/WriteParameterFile.C index 60e7fcf19..5dac46d1b 100644 --- a/src/enzo/WriteParameterFile.C +++ b/src/enzo/WriteParameterFile.C @@ -1114,8 +1114,6 @@ int WriteParameterFile(FILE *fptr, TopGridData &MetaData, char *name = NULL) fprintf(fptr, "StarMakerMinimumMassRampStartMass = %"GSYM"\n", StarMakerMinimumMassRampStartMass); fprintf(fptr, "StarMakerMinimumMassRampEndTime = %"GSYM"\n", StarMakerMinimumMassRampEndTime); fprintf(fptr, "StarMakerMinimumMassRampEndMass = %"GSYM"\n", StarMakerMinimumMassRampEndMass); - -/* Most Stanford additions: */ fprintf(fptr, "StarFeedbackThermalEfficiencyRamp = %"ISYM"\n", StarFeedbackThermalEfficiencyRamp); fprintf(fptr, "StarFeedbackThermalEfficiencyRampStartTime = %"GSYM"\n", StarFeedbackThermalEfficiencyRampStartTime); diff --git a/src/enzo/macros_and_parameters.h b/src/enzo/macros_and_parameters.h index 7eba38549..4d5cb85df 100644 --- a/src/enzo/macros_and_parameters.h +++ b/src/enzo/macros_and_parameters.h @@ -70,11 +70,11 @@ #define MEMORY_POOL_SIZE __memory_pool_size -#define MAX_NUMBER_OF_OUTPUT_REDSHIFTS 2500 +#define MAX_NUMBER_OF_OUTPUT_REDSHIFTS 500 #define GRAVITY_BUFFER_SIZE 3 -#define MAX_FLAGGING_METHODS 21 +#define MAX_FLAGGING_METHODS 9 #define MAX_STATIC_REGIONS 1000 @@ -546,7 +546,6 @@ typedef long long int HDF5_hid_t; #define SINGLE_SUPERNOVA 12 #define DISTR_FEEDBACK 13 #define MOM_STAR 14 -#define MECHANICAL 15 #define STARMAKE_METHOD(A) (StarParticleCreation >> (A) & 1) #define STARFEED_METHOD(A) (StarParticleFeedback >> (A) & 1) From 64f9445d4b1b972d9ebf12750182ef10af3dd404 Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 12:37:36 +0100 Subject: [PATCH 110/115] Fixing issue that prevented build on circle-ci --- src/enzo/Grid_SetParticleMassFlaggingField.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enzo/Grid_SetParticleMassFlaggingField.C b/src/enzo/Grid_SetParticleMassFlaggingField.C index b012ab91d..a1f22d8e3 100644 --- a/src/enzo/Grid_SetParticleMassFlaggingField.C +++ b/src/enzo/Grid_SetParticleMassFlaggingField.C @@ -226,7 +226,7 @@ int grid::SetParticleMassFlaggingField(int StartProc, int EndProc, int level, /************************************************************************/ -int Return_MPI_Tag(int grid_num, int proc) +MPI_Arg Return_MPI_Tag(int grid_num, int proc) { // Return a somewhat-unique 16-bit MPI tag for communication. The factors // are prime. From b43a591fe687232f7733313ede39f19763af97c7 Mon Sep 17 00:00:00 2001 From: John Regan Date: Fri, 14 Oct 2022 15:10:36 +0100 Subject: [PATCH 111/115] Removing MPI timing from EvolveLevel.C --- src/enzo/EvolveLevel.C | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/enzo/EvolveLevel.C b/src/enzo/EvolveLevel.C index c24626477..d623b9f6f 100644 --- a/src/enzo/EvolveLevel.C +++ b/src/enzo/EvolveLevel.C @@ -284,8 +284,6 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], /* Declarations */ int dbx = 0; - float startEL = MPI_Wtime(); - float preCallEL; FLOAT When, GridTime; //float dtThisLevelSoFar = 0.0, dtThisLevel, dtGrid, dtActual, dtLimit; //float dtThisLevelSoFar = 0.0, dtThisLevel; @@ -815,7 +813,7 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], for (grid1 = 0; grid1 < NumberOfGrids; grid1++) Grids[grid1]->GridData->SetTimeStep(dtThisLevel[level]); } - preCallEL = MPI_Wtime()-startEL; + if (LevelArray[level+1] != NULL) { if (EvolveLevel(MetaData, LevelArray, level+1, dtThisLevel[level], Exterior #ifdef TRANSFER @@ -826,7 +824,7 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], ENZO_VFAIL("Error in EvolveLevel (%"ISYM").\n", level) } } - startEL = MPI_Wtime(); + #ifdef USE_LCAPERF // Update lcaperf "level" attribute @@ -1018,11 +1016,6 @@ int EvolveLevel(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], delete [] SiblingList; SiblingGridListStorage[level] = NULL; } - int32_t mpi_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - if (mpi_rank == 0) - fprintf(stdout, "[ %d ] TIMING %"ISYM" grids %"GSYM" s post EL\n", - level, NumberOfGrids, MPI_Wtime()-startEL + preCallEL); return SUCCESS; } From 2cdedc9451b4b6204f7c0efe06eb5fef68081bef Mon Sep 17 00:00:00 2001 From: fearmayo Date: Tue, 29 Nov 2022 14:05:02 +0100 Subject: [PATCH 112/115] Updates to Thermal Feedback routines --- src/enzo/ActiveParticleRoutines.C | 10 ++-- src/enzo/ActiveParticle_SmartStar.C | 37 ++++++++++--- src/enzo/ActiveParticle_SmartStar.h | 5 +- src/enzo/DetermineSEDParameters.C | 19 ++++++- .../Grid_ApplySmartStarParticleFeedback.C | 53 +++++++++++++------ src/enzo/Grid_ApplySphericalFeedbackToGrid.C | 38 ++++++++++--- 6 files changed, 124 insertions(+), 38 deletions(-) diff --git a/src/enzo/ActiveParticleRoutines.C b/src/enzo/ActiveParticleRoutines.C index 2118677b5..3fa164390 100644 --- a/src/enzo/ActiveParticleRoutines.C +++ b/src/enzo/ActiveParticleRoutines.C @@ -242,10 +242,10 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) { int dim; double ratio1, ratio2; - printf("%s: Merging particles with masses of (Code: %e) and (Code: %e)\n", - __FUNCTION__, Mass, a->Mass); - if((Mass <= 1e-6) || (a->Mass <= 1e-6)) - return; + //printf("%s: Merging particles with masses of (Code: %e) and (Code: %e)\n", + // __FUNCTION__, Mass, a->Mass); + //if((Mass <= 1e-6) || (a->Mass <= 1e-6)) + // return; ratio1 = (max(Mass, 1e-10)) / (max(1e-10,Mass) + max(1e-10, a->Mass)); ratio2 = 1.0 - ratio1; @@ -293,6 +293,8 @@ void ActiveParticleType_SmartStar::SmartMerge(ActiveParticleType_SmartStar *a) } WillDelete = min(WillDelete, a->WillDelete); Mass += a->Mass; + //printf("%s: New Mass = %e\n", __FUNCTION__, Mass); + return; } diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index 275a556be..e3dd49f23 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -22,7 +22,7 @@ #define MASSTHRESHOLD 0.1 //Msolar in grid #define COOLING_TIME 0 #define NUMSSPARTICLETYPES 4 -#define JEANS_FACTOR 4 +#define JEANS_FACTOR 2 int DetermineSEDParameters(ActiveParticleType_SmartStar *SS,FLOAT Time, FLOAT dx); /* We need to make sure that we can operate on the grid, so this dance is @@ -386,9 +386,6 @@ int ActiveParticleType_SmartStar::EvaluateFormation else if(HasMetalField && data.TotalMetals[index] > PopIIIMetalCriticalFraction) { stellar_type = POPII; } - else if(data.H2Fraction[index] > PopIIIH2CriticalFraction) { - stellar_type = POPIII; - } else if((accrate*3.154e7*ConverttoSolar/data.TimeUnits > CRITICAL_ACCRETION_RATE*10.0) && (dx_pc < SMS_RESOLUTION)) { /* @@ -399,7 +396,10 @@ int ActiveParticleType_SmartStar::EvaluateFormation printf("!!!!!!!!SMS Formed\t accrate = %e Msolar/yr", accrate*3.154e7*ConverttoSolar/data.TimeUnits); } - + else if(data.H2Fraction[index] > PopIIIH2CriticalFraction) { + stellar_type = POPIII; + } + if(stellar_type < 0) continue; @@ -738,6 +738,9 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel if(ThisParticle->ParticleClass == POPIII && PMass > 500.0) continue; //No stellar radiative feedback in this case (thermal mode only) + if((ThisParticle->ParticleClass == BH) && (ThisParticle->AccretionRate[ThisParticle->TimeIndex] == 0.0)) + continue; + float ramptime = 0.0; if(POPIII == ThisParticle->ParticleClass || SMS == ThisParticle->ParticleClass) { @@ -1349,14 +1352,14 @@ int ActiveParticleType_SmartStar::Accrete(int nParticles, continue; } - + grid* FeedbackZone = ConstructFeedbackZone(ParticleList[i], int(AccretionRadius/dx), dx, Grids, NumberOfGrids, ALL_FIELDS); grid* APGrid = ParticleList[i]->ReturnCurrentGrid(); if (MyProcessorNumber == FeedbackZone->ReturnProcessorNumber()) { float AccretionRate = 0; - + printf("%s: pclass = %d\t. Calculate accretion rate\n", __FUNCTION__, pclass); if (FeedbackZone->AccreteOntoSmartStarParticle(ParticleList[i], AccretionRadius, &AccretionRate) == FAIL) return FAIL; @@ -1449,11 +1452,17 @@ int ActiveParticleType_SmartStar::SmartStarParticleFeedback(int nParticles, for (i = 0; i < nParticles; i++) { + float cmass = ParticleList[i]->ReturnMass(); + if(cmass < 1e-10) { + static_cast(ParticleList[i])->WillDelete = true; //delete on the next pass + continue; + } + /* No feedback on very first cycle */ //if(static_cast(ParticleList[i])->TimeIndex < 2) // break; - + FLOAT AccretionRadius = static_cast(ParticleList[i])->AccretionRadius; grid* FeedbackZone = ConstructFeedbackZone(ParticleList[i], int(AccretionRadius/dx), dx, Grids, NumberOfGrids, ALL_FIELDS); @@ -1582,6 +1591,13 @@ int ActiveParticleType_SmartStar::UpdateAccretionRateStats(int nParticles, || (SS->TimeIndex == 0)) { float omass = SS->oldmass; float cmass = ParticleList[i]->ReturnMass(); + if(cmass < 1e-10) { //massless particles need to be deleted + printf("%s: cmass = %e\n", __FUNCTION__, cmass); + printf("%s: ParticleList[i]->ShouldDelete() = %d\n", __FUNCTION__, SS->ShouldDelete()); + SS->WillDelete = true; //delete on the next pass + printf("%s: (working?)ParticleList[i]->ShouldDelete() = %d\n", __FUNCTION__, SS->ShouldDelete()); + continue; + } if(cmass - omass < -1e-10) { //Can happen after a restart due to rounding printf("Updating masses....\n"); printf("cmass = %e\t omass = %e\n", cmass, omass); @@ -1677,6 +1693,11 @@ int ActiveParticleType_SmartStar::UpdateRadiationLifetimes(int nParticles, if (MyProcessorNumber == APGrid->ReturnProcessorNumber()) { ActiveParticleType_SmartStar* SS; SS = static_cast(ParticleList[i]); + float cmass = SS->ReturnMass(); + if(cmass < 1e-10) { //massless particles need to be deleted on the next pass + SS->WillDelete = true; //delete on the next pass + continue; + } if(POPIII == SS->ParticleClass) { double StellarMass = SS->Mass*MassConversion; //Msolar float logm = log10((float)StellarMass); diff --git a/src/enzo/ActiveParticle_SmartStar.h b/src/enzo/ActiveParticle_SmartStar.h index 1d5b68eed..5f2b6574b 100644 --- a/src/enzo/ActiveParticle_SmartStar.h +++ b/src/enzo/ActiveParticle_SmartStar.h @@ -34,7 +34,7 @@ #define ACCRETIONRADIUS 4 #define NUMRADIATIONBINS 5 #define CRITICAL_ACCRETION_RATE 0.005 //Msolar/yr (Haemerlee et al (2018)) -#define TIMEGAP 100 // * timestep +#define TIMEGAP 1000 // * timestep #define POPIII_RESOLUTION 0.001 //pc #define SMS_RESOLUTION 1.0 //pc /* Prototypes */ @@ -218,6 +218,9 @@ int GenerateGridArray(LevelHierarchyEntry *LevelArray[], int level, HierarchyEntry **Grids[]); int CalculateAccretedAngularMomentum(); + + + template void ActiveParticleType_SmartStar::MergeSmartStars( int *nParticles, ActiveParticleList& ParticleList, diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index 99ec78412..11209e51d 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -269,6 +269,7 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) */ else if(this->ParticleClass == BH && SmartStarBHRadiativeFeedback == TRUE) { double accrate = (this->AccretionRate[this->TimeIndex]*(MassUnits/SolarMass)/TimeUnits)*yr_s; //Msolar/yr + double prev_accrate = (this->AccretionRate[this->TimeIndex-1]*(MassUnits/SolarMass)/TimeUnits)*yr_s; //Msolar/yr double BHMass = _mass; float epsilon = this->eta_disk; double eddrate = 4*M_PI*GravConst*BHMass*SolarMass*mh/(epsilon*clight*sigma_thompson); // g/s @@ -293,15 +294,29 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) this->LuminosityPerSolarMass = LSuperEdd/BHMass; } } - + /* Calculate previous accretion history */ + double total_accrate = 0.0; + int zero_accrates = 0; + for(int i=this->TimeIndex-1; i>this->TimeIndex-11 && i > 0; i--) { + prev_accrate = (this->AccretionRate[i]*(MassUnits/SolarMass)/TimeUnits)*yr_s; //Msolar/yr + total_accrate += prev_accrate; + if(prev_accrate < 1e-6) + zero_accrates++; + } /* Employ some ramping to stop numerical meltdown */ float Age = (Time - this->ReturnBirthTime())*TimeUnits/yr_s; - //printf("%s: BH Age = %e yrs\n", __FUNCTION__, Age); fflush(stdout); + printf("%s: BH Age = %e yrs\n", __FUNCTION__, Age); fflush(stdout); if(Age < RAMPAGE) { float ramp = (Age/RAMPAGE); //printf("%s: ramp = %g\n", __FUNCTION__, ramp); fflush(stdout); this->LuminosityPerSolarMass = this->LuminosityPerSolarMass*ramp; } + /* If a BH has been inactive for sometime then we also need to ramp */ + else if(zero_accrates > 0) { + float ramp = 1.0/(zero_accrates*zero_accrates); /*varies between 0.25 and 0.01 */ + printf("%s: (Inactive BH) ramp = %g\n", __FUNCTION__, ramp); fflush(stdout); + this->LuminosityPerSolarMass = this->LuminosityPerSolarMass*ramp; + } /* Use values from the BHArray to set the SED Fractions */ for(int bin = 0; bin < NUMRADIATIONBINS; bin++) { this->RadiationEnergyBins[bin] = BHEnergyBins[bin]; diff --git a/src/enzo/Grid_ApplySmartStarParticleFeedback.C b/src/enzo/Grid_ApplySmartStarParticleFeedback.C index 7699f0e45..fc6c5f835 100644 --- a/src/enzo/Grid_ApplySmartStarParticleFeedback.C +++ b/src/enzo/Grid_ApplySmartStarParticleFeedback.C @@ -171,6 +171,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ DensityUnits; SS->WillDelete = true; printf("%s: PISN detected. Particle set for deletion.\n", __FUNCTION__); + /* EjectaThermalEnergy is the specific energy in code units */ EjectaThermalEnergy = SNEnergy / (StellarMass * SolarMass) / VelocityUnits / VelocityUnits; @@ -219,12 +220,17 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ { FLOAT EjectaMetalDensity = 0.0, EjectaThermalEnergy = 0.0, EjectaDensity = 0.0; printf("%s:!!!!!!!Using Stellar Thermal Feedback Mode\n", __FUNCTION__); fflush(stdout); - printf("%s: StellarMass = %lf\n", __FUNCTION__, StellarMass); - /* For this case we simply assume a Stroemgren sphere that ionised the nearby gas */ + /* For this case we simply assume a Stroemgren sphere that ionises the nearby gas */ float StellarTemperature = 1e5; - - EjectaThermalEnergy = StellarTemperature / (TemperatureUnits * (Gamma-1.0) * 0.6); + + /* Convert StellarTemperature to total gas energy energy in cgs*/ + EjectaThermalEnergy = kboltz * StellarTemperature / ((Gamma-1.0) * 0.6 * mh); + printf("%s: Energy Release as specific thermal feedback = %e ergs\n", __FUNCTION__, + EjectaThermalEnergy); + /* Convert to code units */ + EjectaThermalEnergy /= (VelocityUnits*VelocityUnits); + /* Pass EjectaThermalEnergy in as specific energy. */ this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, EjectaMetalDensity); } @@ -249,11 +255,12 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ printf("%s: POPII Continuous Supernova\n", __FUNCTION__); FLOAT StarLevelCellWidth = this->CellWidth[0][0]; - FLOAT Radius = StarClusterSNRadius * pc_cm / LengthUnits; - if (Radius < 2*StarLevelCellWidth) { - Radius = 2*StarLevelCellWidth; + //FLOAT Radius = StarClusterSNRadius * pc_cm / LengthUnits; + FLOAT PopIIRadius = SS->InfluenceRadius; + if (PopIIRadius < 2*StarLevelCellWidth) { + PopIIRadius = 2*StarLevelCellWidth; } - FLOAT BubbleVolume = (4.0 * pi / 3.0) * Radius * Radius * Radius; /* code volume */ + FLOAT BubbleVolume = (4.0 * pi / 3.0) * PopIIRadius * PopIIRadius * PopIIRadius; /* code volume */ float dtForThisStar = this->ReturnTimeStep(); double StellarMass = SS->Mass*MassConversion/SolarMass; /* In Msolar */ double Delta_SF = StarMassEjectionFraction * StellarMass * dtForThisStar * @@ -261,7 +268,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ printf("%s: dtForThisStar = %e Myr\n", __FUNCTION__, dtForThisStar * TimeUnits/Myr_s); printf("%s: OK I'm going to eject %e Msolar as Energy\n", __FUNCTION__, Delta_SF); - FLOAT EjectaVolume = 4.0/3.0 * pi * pow(Radius*LengthUnits, 3); /* cm^3 */ + FLOAT EjectaVolume = 4.0/3.0 * pi * pow(PopIIRadius*LengthUnits, 3); /* cm^3 */ FLOAT EjectaDensity = Delta_SF * SolarMass / EjectaVolume / DensityUnits; /* code density */ FLOAT EjectaMetalDensity = EjectaDensity * StarMetalYield; /* code density */ FLOAT EjectaThermalEnergy = StarClusterSNEnergy / SolarMass / @@ -293,9 +300,10 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ if(SmartStarBHFeedback == FALSE) return SUCCESS; // Similar to Supernova, but here we assume the followings: - // EjectaDensity = 0.0 + // EjectaDensity = -1.0 // EjectaMetalDensity = 0.0 - float EjectaDensity = 0.0, EjectaMetalDensity = 0.0; + float EjectaDensity = -1.0, EjectaMetalDensity = 0.0; + FLOAT MBHRadius = SS->InfluenceRadius*1.2; //set to 4 * AccretionRadius // The unit of EjectaThermalEnergy = ergs/cm^3, not ergs/g if (SmartStarBHThermalFeedback == TRUE) { printf("%s: eta_disk = %f\n", __FUNCTION__, SS->eta_disk); @@ -310,8 +318,8 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ accrate, SS->AccretionRate[SS->TimeIndex], SS->TimeIndex); - float EjectaVolumeCGS = 4.0/3.0 * PI * pow(SS->AccretionRadius*LengthUnits, 3); - float EjectaVolume = 4.0/3.0 * PI * pow(SS->AccretionRadius, 3); + FLOAT EjectaVolumeCGS = 4.0/3.0 * PI * pow(MBHRadius*LengthUnits, 3); + FLOAT EjectaVolume = 4.0/3.0 * PI * pow(MBHRadius, 3); float BHMass = SS->ReturnMass()*MassConversion/SolarMass; //In solar masses float eddrate = 4*M_PI*GravConst*BHMass*mh/(SS->eta_disk*clight*sigma_thompson); // Msolar/s @@ -338,9 +346,22 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ * must fix v_wind. For v_wind we choose 0.1 c (C.-A. Faucher-Giguere, E. Quataert Arxiv:1204.2547) */ float SmartStarDiskEnergyCoupling = 0.05; + + /* + This is the total energy created by the accretion process and dumped into an + area surrounding the black hole. This is NOT the specific energy. This is simply the + energy deposited homogeneously into each surrounding cell. + I then (in Grid_ApplySpehericalFeedbackToGrid) deposit this energy + into each cell and divide by the mass. This + gives the specific energy at that point. + */ + float NumCells = EjectaVolume/(dx*dx*dx); + /* EjectaThermalEnergy in code energy units*/ float EjectaThermalEnergy = SmartStarDiskEnergyCoupling * epsilon * dt * - mdot*clight*clight/(VelocityUnits*VelocityUnits*EjectaVolume); - + mdot*clight*clight/(VelocityUnits*VelocityUnits*NumCells); + printf("%s: Total Thermal Energy deposited (into %1.1f cells) by the black hole is %e ergs\n", + __FUNCTION__, NumCells, SmartStarDiskEnergyCoupling*epsilon*dt* + TimeUnits*mdot_cgs*clight*clight); /* Ramp up over RAMPTIME yrs */ float Age = Time - SS->BirthTime; float BH_Age = (Age - SS->StellarAge)*TimeUnits/yr_s; @@ -349,7 +370,7 @@ int grid::ApplySmartStarParticleFeedback(ActiveParticleType** ThisParticle){ printf("BH Age = %e yrs, ramp = %e\n", BH_Age, BH_Age/(float)RAMPTIME); EjectaThermalEnergy *= BH_Age/(float)RAMPTIME; } - EjectaDensity = 0.0; + EjectaDensity = -1.0; EjectaMetalDensity = 0.0; this->ApplySphericalFeedbackToGrid(ThisParticle, EjectaDensity, EjectaThermalEnergy, EjectaMetalDensity); diff --git a/src/enzo/Grid_ApplySphericalFeedbackToGrid.C b/src/enzo/Grid_ApplySphericalFeedbackToGrid.C index f05a277c9..192451251 100644 --- a/src/enzo/Grid_ApplySphericalFeedbackToGrid.C +++ b/src/enzo/Grid_ApplySphericalFeedbackToGrid.C @@ -96,16 +96,31 @@ int grid::ApplySphericalFeedbackToGrid(ActiveParticleType** ThisParticle, float factor = 0.578704; float OldDensity = this->BaryonField[DensNum][index]; - BaryonField[DensNum][index] += factor*EjectaDensity; + if(EjectaDensity > 0.0) + BaryonField[DensNum][index] += factor*EjectaDensity; /* Get specific energy */ if (GENum >= 0 && DualEnergyFormalism) { /* When injected energy is uniform throughout the volume; EjectaThermalEnergy in EnergyUnits/VolumeUnits */ float oldGE = this->BaryonField[GENum][index]; - float newGE = (OldDensity * this->BaryonField[GENum][index] + + float newGE = 0.0; + if(EjectaDensity > 0.0) { /* SuperNovae */ + newGE = (OldDensity * this->BaryonField[GENum][index] + ramp * factor * EjectaThermalEnergy * EjectaDensity) / BaryonField[DensNum][index] ; + } + else if (EjectaDensity == 0.0) { /* Thermal energy due to stellar luminosity */ + /* Thermal energy dump with no ejecta */ + /* For this case the EjectaThermalEnergy is passed in as simply an energy */ + newGE = EjectaThermalEnergy; + } + else if (EjectaDensity < 0.0) { + /* Black Hole accretion Thermal feedback */ + float cellmass = this->BaryonField[DensNum][index]*dx*dx*dx; + newGE = this->BaryonField[GENum][index] + EjectaThermalEnergy / cellmass; + } + newGE = min(newGE, maxGE); //printf("%s: Energy Before = %e\t Energy injected = %e\t Increase = %e\n", __FUNCTION__, @@ -123,11 +138,20 @@ int grid::ApplySphericalFeedbackToGrid(ActiveParticleType** ThisParticle, //printf("%s: Increase in GE energy is %e\n", __FUNCTION__, (newGE - oldGE)/oldGE); } else { - - float newGE = (OldDensity * this->BaryonField[TENum][index] + - ramp * factor * EjectaDensity * EjectaThermalEnergy) / - BaryonField[DensNum][index]; - + float newGE = 0.0; + if(EjectaDensity > 0.0) { + newGE = (OldDensity * this->BaryonField[TENum][index] + + ramp * factor * EjectaDensity * EjectaThermalEnergy) / + BaryonField[DensNum][index]; + } + else if (EjectaDensity == 0.0) { /* Thermal energy from luminosity */ + newGE = EjectaThermalEnergy; + } + else if (EjectaDensity < 0.0) { + /* Black Hole accretion Thermal feedback */ + float cellmass = this->BaryonField[DensNum][index]*dx*dx*dx; + newGE = this->BaryonField[GENum][index] + EjectaThermalEnergy / cellmass; + } newGE = min(newGE, maxGE); this->BaryonField[TENum][index] = newGE; From 269edd368c9a0e7fa2b9c52c769717f0f78bbfab Mon Sep 17 00:00:00 2001 From: fearmayo Date: Thu, 8 Dec 2022 19:15:29 +0100 Subject: [PATCH 113/115] Above 500 Msolar radiation from PopIII stars is non-ionising and thermal feedback --- src/enzo/ActiveParticle_SmartStar.C | 5 +++-- src/enzo/DetermineSEDParameters.C | 12 +++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/enzo/ActiveParticle_SmartStar.C b/src/enzo/ActiveParticle_SmartStar.C index e3dd49f23..7819ad8ba 100644 --- a/src/enzo/ActiveParticle_SmartStar.C +++ b/src/enzo/ActiveParticle_SmartStar.C @@ -735,8 +735,9 @@ int ActiveParticleType_SmartStar::BeforeEvolveLevel source = ThisParticle->RadiationSourceInitialize(); double PMass = ThisParticle->Mass*MassConversion; - if(ThisParticle->ParticleClass == POPIII && PMass > 500.0) - continue; //No stellar radiative feedback in this case (thermal mode only) + /* JR: I got rid of this restriction and instead restrict feedback to below 13.6 eV */ + //if(ThisParticle->ParticleClass == POPIII && PMass > 500.0) + // continue; //No stellar radiative feedback in this case (thermal mode only) if((ThisParticle->ParticleClass == BH) && (ThisParticle->AccretionRate[ThisParticle->TimeIndex] == 0.0)) continue; diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index 11209e51d..25e6f6945 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -173,7 +173,7 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) float x2 = x*x; if(this->ParticleClass == POPIII) { - + float E[NUMRADIATIONBINS] = {2.0, 12.8, 28.0, 30.0, 58.0}; double Q[NUMRADIATIONBINS] = {0.0, 0.0, 0.0, 0.0, 0.0}; @@ -182,7 +182,13 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) } _mass = max(min((float)(_mass), 500), 5); - if (_mass > 9 && _mass <= 500) { + if(_mass > 500.0) { //only non-ionising + Q[0] = 0.0; //IR + Q[1] = pow(10.0, 44.03 + 4.59*x - 0.77*x2); //LW + Q[2] = 0.0; + Q[3] = 0.0; + Q[4] = 0.0; + } else if (_mass > 9 && _mass <= 500) { Q[0] = 0.0; //IR Q[1] = pow(10.0, 44.03 + 4.59*x - 0.77*x2); //LW Q[2] = pow(10.0, 43.61 + 4.9*x - 0.83*x2); //HI @@ -191,7 +197,7 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) Q[4] = pow(10.0, 26.71 + 18.14*x - 3.58*x2); //HeII else Q[4] = 0.0; - } else if (_mass > 5 && _mass <= 9) { + } else if (_mass > 5 && _mass <= 9) { Q[0] = 0.0; //IR Q[1] = pow(10.0, 44.03 + 4.59*x - 0.77*x2); //LW Q[2] = pow(10.0, 39.29 + 8.55*x); //HI From 61372b3beafe94159a9be73bc2809c48c7a7549c Mon Sep 17 00:00:00 2001 From: John Regan Date: Tue, 28 Mar 2023 18:03:09 +0100 Subject: [PATCH 114/115] Updated ParticleSplitting to split only the particles read in from a file --- src/enzo/Grid_CreateChildParticles.C | 23 +++++++++++++++-------- src/enzo/ParticleSplitter.C | 3 --- src/enzo/ReadParameterFile.C | 2 ++ src/enzo/SetDefaultGlobalValues.C | 1 + src/enzo/WriteParameterFile.C | 2 ++ src/enzo/global_data.h | 1 + 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/enzo/Grid_CreateChildParticles.C b/src/enzo/Grid_CreateChildParticles.C index a8b55f1a2..13a204c5b 100644 --- a/src/enzo/Grid_CreateChildParticles.C +++ b/src/enzo/Grid_CreateChildParticles.C @@ -34,7 +34,7 @@ #include "CosmologyParameters.h" #include "phys_constants.h" -#define DEBUG_PS +#define NO_DEBUG_PS void mt_init(unsigned_int seed); @@ -72,7 +72,7 @@ int grid::CreateChildParticles(float dx, int NumberOfParticles, float *ParticleM //Reproducible random seed mt_init(((unsigned_int) ParticleSplitterRandomSeed)); - FLOAT sep[3], midpoint[3], newsep[3]; + FLOAT sep[3] = {0.0}, midpoint[3] = {0.0}, newsep[3] = {0.0}; /* * The following three options determine over what region @@ -118,6 +118,7 @@ int grid::CreateChildParticles(float dx, int NumberOfParticles, float *ParticleM } } + #ifdef DEBUG_PS fprintf(stdout, "%s: Iteration %d: midpoint = (%lf, %lf, %lf)\n", __FUNCTION__, iter, midpoint[0], midpoint[1], midpoint[2]); @@ -127,17 +128,16 @@ int grid::CreateChildParticles(float dx, int NumberOfParticles, float *ParticleM __FUNCTION__, iter, LeftEdge[0], LeftEdge[1], LeftEdge[2], RightEdge[0], RightEdge[1], RightEdge[2]); #endif - /* * Loop over existing (parent) particles; It implicitly assumes that - * only DM and conventional star particles get splitted. Other - * particles - which usually become Star class particles - doesn't - * seem to have any reason to be splitted. (as of Oct.2009) + * only DM and conventional star particles get split. Other + * particles - which usually become Star class particles - don't + * seem to have any reason to be split. (as of Oct.2009) */ /* (Apr 2018) Include must-refine particles */ - + for(partnum = 0; partnum < NumberOfParticles; partnum++) { if(ParticleMass[partnum] > 0.0 && @@ -161,6 +161,14 @@ int grid::CreateChildParticles(float dx, int NumberOfParticles, float *ParticleM continue; } + /* If we want to define the refinement region by + * the split particles then we only split the particles + * that were read in and so are MRPs. + */ + if(ParticleSplitterMustRefineOnly && + ParticleType[partnum] != PARTICLE_TYPE_MUST_REFINE) + continue; + /* * Compute index of the cell that the parent particle resides in. */ @@ -176,7 +184,6 @@ int grid::CreateChildParticles(float dx, int NumberOfParticles, float *ParticleM fprintf(stdout, "xind, yind, zind = %ld, %ld, %ld\n", xindex, yindex, zindex); continue; } - /* * CREATE CHILDREN PARTICLES */ diff --git a/src/enzo/ParticleSplitter.C b/src/enzo/ParticleSplitter.C index bfec90d8d..00a8df67f 100644 --- a/src/enzo/ParticleSplitter.C +++ b/src/enzo/ParticleSplitter.C @@ -89,7 +89,6 @@ int ParticleSplitter(LevelHierarchyEntry *LevelArray[], int ThisLevel, if (ParticleSplitterMustRefine && ParticleSplitterMustRefineIDFile != NULL) { - int NumberOfMustRefineIDs; hid_t file_id, dataset_id, dataspace_id; herr_t status; @@ -111,9 +110,7 @@ int ParticleSplitter(LevelHierarchyEntry *LevelArray[], int ThisLevel, } /* Initialize all star particles if this is a restart */ - for (i = 0; i < ParticleSplitterIterations; i++) { - for (level = 0; level < MAX_DEPTH_OF_HIERARCHY-1; level++) { #ifdef DEBUG_PS diff --git a/src/enzo/ReadParameterFile.C b/src/enzo/ReadParameterFile.C index 0652d07e9..faa6b06f8 100644 --- a/src/enzo/ReadParameterFile.C +++ b/src/enzo/ReadParameterFile.C @@ -1348,6 +1348,8 @@ int ReadParameterFile(FILE *fptr, TopGridData &MetaData, float *Initialdt) &ParticleSplitterMustRefine); if (sscanf(line, "ParticleSplitterMustRefineIDFile = %s", dummy) == 1) ParticleSplitterMustRefineIDFile = dummy; + ret += sscanf(line, "ParticleSplitterMustRefineOnly = %"ISYM, + &ParticleSplitterMustRefineOnly); ret += sscanf(line, "ParticleSplitterFraction = %"FSYM" %"FSYM" %"FSYM" %"FSYM"", ParticleSplitterFraction+0, ParticleSplitterFraction+1, ParticleSplitterFraction+2, ParticleSplitterFraction+3); diff --git a/src/enzo/SetDefaultGlobalValues.C b/src/enzo/SetDefaultGlobalValues.C index 812fad806..c9856a8b5 100644 --- a/src/enzo/SetDefaultGlobalValues.C +++ b/src/enzo/SetDefaultGlobalValues.C @@ -1013,6 +1013,7 @@ int SetDefaultGlobalValues(TopGridData &MetaData) ParticleSplitterRandomSeed = 131180; ParticleSplitterMustRefine = FALSE; ParticleSplitterMustRefineIDFile = NULL; + ParticleSplitterMustRefineOnly = FALSE; for(int i = 0; i < MAX_SPLIT_ITERATIONS; i++) ParticleSplitterFraction[i] = 1.0; for(int i = 0; i < MAX_DIMENSION; i++) diff --git a/src/enzo/WriteParameterFile.C b/src/enzo/WriteParameterFile.C index 5dac46d1b..077f48195 100644 --- a/src/enzo/WriteParameterFile.C +++ b/src/enzo/WriteParameterFile.C @@ -676,6 +676,8 @@ int WriteParameterFile(FILE *fptr, TopGridData &MetaData, char *name = NULL) ParticleSplitterMustRefine); fprintf(fptr, "ParticleSplitterMustRefineIDFile = %s\n", ParticleSplitterMustRefineIDFile); + fprintf(fptr, "ParticleSplitterMustRefineOnly = %"ISYM"\n", + ParticleSplitterMustRefineOnly); fprintf(fptr, "ResetMagneticField = %"ISYM"\n", ResetMagneticField); fprintf(fptr, "ResetMagneticFieldAmplitude = %"GSYM" %"GSYM" %"GSYM"\n", diff --git a/src/enzo/global_data.h b/src/enzo/global_data.h index a07debadf..eef276006 100644 --- a/src/enzo/global_data.h +++ b/src/enzo/global_data.h @@ -1061,6 +1061,7 @@ EXTERN float ParticleSplitterChildrenParticleSeparation; EXTERN int ParticleSplitterRandomSeed; EXTERN int ParticleSplitterMustRefine; EXTERN char *ParticleSplitterMustRefineIDFile; +EXTERN int ParticleSplitterMustRefineOnly; EXTERN float ParticleSplitterFraction[MAX_SPLIT_ITERATIONS]; EXTERN FLOAT ParticleSplitterCenter[MAX_DIMENSION]; EXTERN float ParticleSplitterCenterRegion[MAX_SPLIT_ITERATIONS]; From e42e928d2cee00c028d30e77400783c9b181d806 Mon Sep 17 00:00:00 2001 From: fearmayo Date: Tue, 20 Jun 2023 13:24:23 +0200 Subject: [PATCH 115/115] updated to particle splitter code to allow splitting only of particles from file --- src/enzo/DetermineSEDParameters.C | 4 ++-- src/enzo/Grid_ParticleSplitter.C | 2 +- src/enzo/ParticleSplitter.C | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/enzo/DetermineSEDParameters.C b/src/enzo/DetermineSEDParameters.C index 25e6f6945..5cdf5e00b 100644 --- a/src/enzo/DetermineSEDParameters.C +++ b/src/enzo/DetermineSEDParameters.C @@ -311,7 +311,7 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) } /* Employ some ramping to stop numerical meltdown */ float Age = (Time - this->ReturnBirthTime())*TimeUnits/yr_s; - printf("%s: BH Age = %e yrs\n", __FUNCTION__, Age); fflush(stdout); + //printf("%s: BH Age = %e yrs\n", __FUNCTION__, Age); fflush(stdout); if(Age < RAMPAGE) { float ramp = (Age/RAMPAGE); //printf("%s: ramp = %g\n", __FUNCTION__, ramp); fflush(stdout); @@ -320,7 +320,7 @@ int ActiveParticleType_SmartStar::DetermineSEDParameters(FLOAT Time, FLOAT dx) /* If a BH has been inactive for sometime then we also need to ramp */ else if(zero_accrates > 0) { float ramp = 1.0/(zero_accrates*zero_accrates); /*varies between 0.25 and 0.01 */ - printf("%s: (Inactive BH) ramp = %g\n", __FUNCTION__, ramp); fflush(stdout); + //printf("%s: (Inactive BH) ramp = %g\n", __FUNCTION__, ramp); fflush(stdout); this->LuminosityPerSolarMass = this->LuminosityPerSolarMass*ramp; } /* Use values from the BHArray to set the SED Fractions */ diff --git a/src/enzo/Grid_ParticleSplitter.C b/src/enzo/Grid_ParticleSplitter.C index 65079af1c..3612e5836 100644 --- a/src/enzo/Grid_ParticleSplitter.C +++ b/src/enzo/Grid_ParticleSplitter.C @@ -30,7 +30,7 @@ #include "fortran.def" #include "CosmologyParameters.h" -#define NO_DEBUG_PS +#define DEBUG_PS 0 /* function prototypes */ diff --git a/src/enzo/ParticleSplitter.C b/src/enzo/ParticleSplitter.C index 00a8df67f..11cc21e9c 100644 --- a/src/enzo/ParticleSplitter.C +++ b/src/enzo/ParticleSplitter.C @@ -39,7 +39,7 @@ #include "CosmologyParameters.h" #include "CommunicationUtilities.h" -#define NO_DEBUG_PS +#define DEBUG_PS 0 int RebuildHierarchy(TopGridData *MetaData, LevelHierarchyEntry *LevelArray[], int level);