diff --git a/geoschem.go b/geoschem.go index 4bc98b589..d7060d663 100644 --- a/geoschem.go +++ b/geoschem.go @@ -400,6 +400,13 @@ func (gc *GEOSChem) readChemGroupAlt(varGroup map[string]float64) NextData { return nextDataGroupAltNCF(gc.geosChem, geosChemFormat, varGroup, gc.ALT(), gc.start, gc.end, gc.chemRecordDeltaInterval, gc.chemFileDeltaInterval, readNCF, gc.msgChan) } +func (gc *GEOSChem) readChemGroupSTP(varGroup map[string]float64) NextData { + if gc.noChemHour { + return nextDataGroupSTPNCF(gc.geosChem, geosChemFormat, varGroup, gc.start, gc.end, gc.chemRecordDeltaInterval, gc.chemFileDeltaInterval, readNCFNoHour, gc.msgChan) + } + return nextDataGroupSTPNCF(gc.geosChem, geosChemFormat, varGroup, gc.start, gc.end, gc.chemRecordDeltaInterval, gc.chemFileDeltaInterval, readNCF, gc.msgChan) +} + var geosLayerConvert = func(nz int) func(NextData) NextData { const ( geosLayers = 72 @@ -698,37 +705,37 @@ func (gc *GEOSChem) W() NextData { } // AVOC helps fulfill the Preprocessor interface. -func (gc *GEOSChem) AVOC() NextData { return gc.readChemGroupAlt(gc.aVOC) } +func (gc *GEOSChem) AVOC() NextData { return gc.readChemGroupSTP(gc.aVOC) } // BVOC helps fulfill the Preprocessor interface. -func (gc *GEOSChem) BVOC() NextData { return gc.readChemGroupAlt(gc.bVOC) } +func (gc *GEOSChem) BVOC() NextData { return gc.readChemGroupSTP(gc.bVOC) } // NOx helps fulfill the Preprocessor interface. -func (gc *GEOSChem) NOx() NextData { return gc.readChemGroupAlt(gc.nox) } +func (gc *GEOSChem) NOx() NextData { return gc.readChemGroupSTP(gc.nox) } // SOx helps fulfill the Preprocessor interface. -func (gc *GEOSChem) SOx() NextData { return gc.readChemGroupAlt(gc.sox) } +func (gc *GEOSChem) SOx() NextData { return gc.readChemGroupSTP(gc.sox) } // NH3 helps fulfill the Preprocessor interface. -func (gc *GEOSChem) NH3() NextData { return gc.readChemGroupAlt(gc.nh3) } +func (gc *GEOSChem) NH3() NextData { return gc.readChemGroupSTP(gc.nh3) } // ASOA helps fulfill the Preprocessor interface. -func (gc *GEOSChem) ASOA() NextData { return gc.readChemGroupAlt(gc.aSOA) } +func (gc *GEOSChem) ASOA() NextData { return gc.readChemGroupSTP(gc.aSOA) } // BSOA helps fulfill the Preprocessor interface. -func (gc *GEOSChem) BSOA() NextData { return gc.readChemGroupAlt(gc.bSOA) } +func (gc *GEOSChem) BSOA() NextData { return gc.readChemGroupSTP(gc.bSOA) } // PNO helps fulfill the Preprocessor interface. -func (gc *GEOSChem) PNO() NextData { return gc.readChemGroupAlt(gc.pNO) } +func (gc *GEOSChem) PNO() NextData { return gc.readChemGroupSTP(gc.pNO) } // PS helps fulfill the Preprocessor interface. -func (gc *GEOSChem) PS() NextData { return gc.readChemGroupAlt(gc.pS) } +func (gc *GEOSChem) PS() NextData { return gc.readChemGroupSTP(gc.pS) } // PNH helps fulfill the Preprocessor interface. -func (gc *GEOSChem) PNH() NextData { return gc.readChemGroupAlt(gc.pNH) } +func (gc *GEOSChem) PNH() NextData { return gc.readChemGroupSTP(gc.pNH) } // TotalPM25 helps fulfill the Preprocessor interface. -func (gc *GEOSChem) TotalPM25() NextData { return gc.readChemGroupAlt(gc.totalPM25) } +func (gc *GEOSChem) TotalPM25() NextData { return gc.readChemGroupSTP(gc.totalPM25) } // SurfaceHeatFlux helps fulfill the Preprocessor interface by returning // sensible heat flux from turbulence [W/m2]. diff --git a/preproc.go b/preproc.go index c0b87ae17..352ddfe41 100644 --- a/preproc.go +++ b/preproc.go @@ -1133,6 +1133,24 @@ func nextDataGroupAltNCF(fileTemplate string, dateFormat string, varNames map[st } } +// nextDataGroupSTPNCF reads a group of variables using nextDataGroupNCF +// and multiplies the result by air density STP (1.2754 kg/m3). +func nextDataGroupSTPNCF(fileTemplate string, dateFormat string, varNames map[string]float64, start, end time.Time, recordDelta, fileDelta time.Duration, readFunc readNCFFunc, msgChan chan string) NextData { + f := nextDataGroupNCF(fileTemplate, dateFormat, varNames, start, end, recordDelta, fileDelta, readFunc, msgChan) + const rho = 1.2754 // kg/m3, air density at STP + return func() (*sparse.DenseArray, error) { + data, err := f() + if err != nil { + return nil, err + } + out := sparse.ZerosDense(data.Shape...) + for i, val := range data.Elements { + out.Elements[i] = val * rho + } + return out, nil + } +} + // ncfFromTemplate opens a NetCDF file from the given template, where // the [DATE] wildcard in the given fileTemplate is replaced by the given // date, formatted as the given dateFormat.