Added linking of nearest observatories to earthquakes
This commit is contained in:
parent
a03d265410
commit
db6ba00ded
@ -6,6 +6,7 @@ import { prisma } from "@utils/prisma";
|
|||||||
import { getRandomNumber } from "@utils/maths";
|
import { getRandomNumber } from "@utils/maths";
|
||||||
|
|
||||||
const csvFilePath = path.resolve(process.cwd(), "public/earthquakes.csv");
|
const csvFilePath = path.resolve(process.cwd(), "public/earthquakes.csv");
|
||||||
|
const DISTANCE_THRESHOLD_KM = 500; // Max distance for observatory matching
|
||||||
|
|
||||||
type CsvRow = {
|
type CsvRow = {
|
||||||
Date: string;
|
Date: string;
|
||||||
@ -18,6 +19,18 @@ type CsvRow = {
|
|||||||
Depth: string;
|
Depth: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Haversine formula to calculate distance between two points (in km)
|
||||||
|
function getDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
|
||||||
|
const R = 6371; // Earth's radius in km
|
||||||
|
const dLat = (lat2 - lat1) * (Math.PI / 180);
|
||||||
|
const dLon = (lon2 - lon1) * (Math.PI / 180);
|
||||||
|
const a =
|
||||||
|
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||||
|
Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
||||||
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||||
|
return R * c;
|
||||||
|
}
|
||||||
|
|
||||||
export async function POST() {
|
export async function POST() {
|
||||||
try {
|
try {
|
||||||
const fileContent = await fs.readFile(csvFilePath, "utf8");
|
const fileContent = await fs.readFile(csvFilePath, "utf8");
|
||||||
@ -28,12 +41,15 @@ export async function POST() {
|
|||||||
|
|
||||||
const failedImports: { row: CsvRow; reason: string }[] = [];
|
const failedImports: { row: CsvRow; reason: string }[] = [];
|
||||||
|
|
||||||
|
// Fetch all observatories once to avoid repeated queries
|
||||||
|
const observatories = await prisma.observatory.findMany({
|
||||||
|
select: { id: true, latitude: true, longitude: true },
|
||||||
|
});
|
||||||
|
|
||||||
const earthquakes = await Promise.all(
|
const earthquakes = await Promise.all(
|
||||||
records.map(async (row) => {
|
records.map(async (row) => {
|
||||||
const creators = await prisma.user.findMany({
|
const creators = await prisma.user.findMany({
|
||||||
where: {
|
where: { role: { in: ["SCIENTIST", "ADMIN"] } },
|
||||||
role: { in: ["SCIENTIST", "ADMIN"] },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const randomCreator = creators.length > 0 ? creators[getRandomNumber(0, creators.length - 1)] : null;
|
const randomCreator = creators.length > 0 ? creators[getRandomNumber(0, creators.length - 1)] : null;
|
||||||
|
|
||||||
@ -42,16 +58,43 @@ export async function POST() {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const eqLat = parseFloat(row.Latitude);
|
||||||
|
const eqLon = parseFloat(row.Longitude);
|
||||||
|
|
||||||
|
// Find observatories within distance threshold
|
||||||
|
let nearbyObservatories = observatories
|
||||||
|
.map((obs) => ({
|
||||||
|
id: obs.id,
|
||||||
|
distance: getDistance(eqLat, eqLon, obs.latitude, obs.longitude),
|
||||||
|
}))
|
||||||
|
.filter((obs) => obs.distance <= DISTANCE_THRESHOLD_KM)
|
||||||
|
.map((obs) => ({ id: obs.id }));
|
||||||
|
|
||||||
|
// If no observatories within range, find the nearest one
|
||||||
|
if (nearbyObservatories.length === 0) {
|
||||||
|
const nearest = observatories.reduce(
|
||||||
|
(min, obs) => {
|
||||||
|
const distance = getDistance(eqLat, eqLon, obs.latitude, obs.longitude);
|
||||||
|
return distance < min.distance ? { id: obs.id, distance } : min;
|
||||||
|
},
|
||||||
|
{ id: -1, distance: Infinity }
|
||||||
|
);
|
||||||
|
if (nearest.id !== -1) {
|
||||||
|
nearbyObservatories = [{ id: nearest.id }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
date: new Date(row.Date),
|
date: new Date(row.Date),
|
||||||
code: row.Code,
|
code: row.Code,
|
||||||
magnitude: parseFloat(row.Magnitude),
|
magnitude: parseFloat(row.Magnitude),
|
||||||
type: row.Type,
|
type: row.Type,
|
||||||
latitude: parseFloat(row.Latitude),
|
latitude: eqLat,
|
||||||
longitude: parseFloat(row.Longitude),
|
longitude: eqLon,
|
||||||
location: row.Location,
|
location: row.Location,
|
||||||
depth: row.Depth,
|
depth: row.Depth,
|
||||||
creatorId: randomCreator.id,
|
creatorId: randomCreator.id,
|
||||||
|
observatories: { connect: nearbyObservatories },
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -60,6 +103,7 @@ export async function POST() {
|
|||||||
(earthquake): earthquake is NonNullable<typeof earthquake> => earthquake !== null
|
(earthquake): earthquake is NonNullable<typeof earthquake> => earthquake !== null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Bulk insert earthquakes with observatory connections
|
||||||
await prisma.earthquake.createMany({
|
await prisma.earthquake.createMany({
|
||||||
data: validEarthquakes,
|
data: validEarthquakes,
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user