RCJuridisch

23. Broncode trillingstool Atabix.txt

Apr 23rd, 2024 (edited)
195
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.60 KB | Housing | 0 0
  1. <?php
  2.  
  3. namespace App\Services\Trillingstool;
  4.  
  5. use Illuminate\Support\Carbon;
  6. use Illuminate\Support\Facades\DB;
  7.  
  8. /**
  9. * Calculates information required for the earthquake (trillings) tool.
  10. */
  11. class CalculateService
  12. {
  13. public static function calculateFromLocation(string $longitude, string $latitude, Carbon $from, Carbon $until, float $minimumMagnitude, $gasFieldId = null, int $limit = 15, int $offset = 0): array
  14. {
  15. // Order is important, because we can't mix named and non-named parameters, and we need to bind multiple of the same name
  16. $bindings = [
  17. $longitude,
  18. $latitude,
  19. $from->toDateTimeString(),
  20. $until->toDateTimeString(),
  21. $minimumMagnitude,
  22. ];
  23.  
  24. if ($gasFieldId) {
  25. $bindings[] = $gasFieldId;
  26. }
  27.  
  28. // Optional
  29. $gasField = $gasFieldId ? 'AND gasfield_id = ?' : '';
  30.  
  31. // Create the earthquake location point
  32. $earthquakeLocation = <<<'SQL'
  33. POINT(longitude, latitude)
  34. SQL;
  35.  
  36. // Create the home location point
  37. $homeLocation = <<<'SQL'
  38. POINT(?, ?)
  39. SQL;
  40.  
  41. // Select the distance between the earthquake and the home
  42. $select = <<<SQL
  43. SELECT id, occurred_at, ST_Distance_Sphere({$earthquakeLocation}, {$homeLocation}) as distance, `magnitude`, depth, city, gasfield_id
  44. FROM trillingstool_earthquakes
  45. WHERE 1
  46. AND occurred_at >= ?
  47. AND occurred_at <= ?
  48. AND `magnitude` >= ?
  49. {$gasField}
  50. SQL;
  51.  
  52. [$pgvForOnePercent, $onePercentBindings] = self::pgv(2.326347874); // 50% = 0 | 25% = 0.67448975 | 1% = 2.326347874
  53. [$pgvForTwentyFivePercent, $twentyFivePercentBindings] = self::pgv(0.67448975);
  54. [$pgvForFiftyPercent, $fiftyPercentBindings] = self::pgv(0);
  55.  
  56. $bindings = \array_merge($onePercentBindings, $twentyFivePercentBindings, $fiftyPercentBindings, $bindings, [$limit, $offset]);
  57.  
  58. // Select the pgv (vibration strength) depending on the distance
  59. $query = <<<SQL
  60. SELECT *,
  61. {$pgvForOnePercent} as pgv_1pct,
  62. {$pgvForTwentyFivePercent} as pgv_25pct,
  63. {$pgvForFiftyPercent} as pgv_50pct
  64. FROM ({$select}) as earthquakes
  65. ORDER BY pgv_1pct DESC
  66. LIMIT ? OFFSET ?
  67. SQL;
  68.  
  69. return DB::select($query, $bindings);
  70. }
  71.  
  72. public static function calculateFromPgv(string $pgv, Carbon $from, Carbon $until, string $minimumMagnitude, string $maximumMagnitude, $gasFieldId = null, int $limit = 15, int $offset = 0): array
  73. {
  74. // Order is important, because we can't mix named and non-named parameters, and we need to bind multiple of the same name
  75. $bindings = [
  76. $from->toDateTimeString(),
  77. $until->toDateTimeString(),
  78. $minimumMagnitude,
  79. $maximumMagnitude,
  80. ];
  81.  
  82. if ($gasFieldId) {
  83. $bindings[] = $gasFieldId;
  84. }
  85.  
  86. // Optional
  87. $gasField = $gasFieldId ? 'AND gasfield_id = ?' : '';
  88.  
  89. [$distanceForOnePercent, $onePercentBindings] = self::distance(2.326347874, $pgv);
  90. [$pgvForTwentyFivePercent, $twentyFivePercentBindings] = self::distance(0.67448975, $pgv);
  91. [$distanceForFiftyPercent, $fiftyPercentBindings] = self::distance(0, $pgv);
  92.  
  93. $bindings = \array_merge([$pgv], $onePercentBindings, $twentyFivePercentBindings, $fiftyPercentBindings, $bindings, [$limit, $offset]);
  94.  
  95. $select = <<<SQL
  96. SELECT `longitude`,
  97. `latitude`,
  98. `occurred_at`,
  99. ? as `pgv`,
  100. {$distanceForOnePercent} as distance_1pct,
  101. {$pgvForTwentyFivePercent} as distance_25pct,
  102. {$distanceForFiftyPercent} as distance_50pct,
  103. `magnitude`,
  104. `depth`,
  105. `city`,
  106. `gasfield_id`
  107. FROM trillingstool_earthquakes
  108. WHERE 1
  109. AND occurred_at >= ?
  110. AND occurred_at <= ?
  111. AND `magnitude` >= ?
  112. AND `magnitude` <= ?
  113. {$gasField}
  114. SQL;
  115.  
  116. $query = <<<SQL
  117. SELECT * FROM ({$select}) as earthquakes
  118. LIMIT ? OFFSET ?
  119. SQL;
  120.  
  121. return DB::select($query, $bindings);
  122. }
  123.  
  124. public static function pgv($n): array
  125. {
  126. $bindings = [
  127. $n,
  128. $n,
  129. $n,
  130. ];
  131.  
  132. $acc = <<<'SQL'
  133. sqrt(POWER(distance / 1000, 2) + POWER(exp(0.4233 * `magnitude` - 0.6083), 2) )
  134. SQL;
  135.  
  136. $a = <<<SQL
  137. -1.9446*ln({$acc})
  138. SQL;
  139.  
  140. $b = <<<SQL
  141. -1.9446*ln(6.32) + -1.2077*ln({$acc}/6.32)
  142. SQL;
  143.  
  144. $c = <<<SQL
  145. -1.9446*ln(6.32) + -1.2077*ln(11.62/6.32) + -1.6533*ln({$acc}/11.62)
  146. SQL;
  147.  
  148. $result = static function ($var) {
  149. return "exp(-5.0006 + 2.2770 * `magnitude` + {$var} + 0.5777 * ?) * 10";
  150. };
  151.  
  152. return [<<<SQL
  153. CASE
  154. WHEN {$acc} <= 6.32 THEN
  155. {$result($a)}
  156. WHEN {$acc} <= 11.62 THEN
  157. {$result($b)}
  158. ELSE
  159. {$result($c)}
  160. END
  161. SQL, $bindings];
  162. }
  163.  
  164. public static function distance($n, $pgv): array
  165. {
  166. $bindings = [
  167. $pgv,
  168. $n,
  169. $pgv,
  170. $n,
  171. $pgv,
  172. $n,
  173. $pgv,
  174. $n,
  175. $pgv,
  176. $n,
  177. ];
  178.  
  179. $acc = <<<'SQL'
  180. log(? / 10) - 0.5777 * ? - (-5.0006 + 2.2770 * `magnitude`)
  181. SQL;
  182.  
  183. $a = <<<SQL
  184. exp(({$acc})/ -1.9446)
  185. SQL;
  186.  
  187. $b = <<<SQL
  188. exp(({$acc} - (-1.9446*ln(6.32))) / -1.2077) * 6.32
  189. SQL;
  190.  
  191. $c = <<<SQL
  192. exp(({$acc} - (-1.9446*LN(6.32)) - (-1.2077*LN(11.62/6.32))) / -1.6533) * 11.62
  193. SQL;
  194.  
  195. $result = static function ($var) {
  196. return "SQRT(POWER({$var}, 2)- POWER(EXP(0.4233 * `magnitude` - 0.6083), 2)) * 1000";
  197. };
  198.  
  199. $case = static function ($var) {
  200. return "sqrt(POWER(($var) / 1000, 2) + POWER(exp(0.4233 * `magnitude` - 0.6083), 2) )";
  201. };
  202.  
  203. return [<<<SQL
  204. CASE
  205. WHEN {$case($result($a))} <= 6.32 THEN
  206. {$result($a)}
  207. WHEN {$case($result($b))} <= 11.62 THEN
  208. {$result($b)}
  209. ELSE
  210. {$result($c)}
  211. END
  212. SQL, $bindings];
  213. }
  214.  
  215. /**
  216. * When no earthquakes are involved, we want to calculate the radius for a given pgv and magnitude.
  217. *
  218. * @param float $n
  219. *
  220. * @return float
  221. */
  222. public static function calculateDistanceFromPgvAndMagnitude($pgv, float $magnitude, $n = 2.326347874): ?float
  223. {
  224. [$distance, $extraBindings] = self::distance($n, $pgv);
  225.  
  226. // Order is important, because we can't mix named and non-named parameters, and we need to bind multiple of the same name
  227. $bindings = [$pgv, ...$extraBindings, $magnitude];
  228.  
  229. $distance = \str_replace('`magnitude`', (string) $magnitude, $distance);
  230.  
  231. $query = <<<SQL
  232. SELECT ? as pgv, {$distance} as distance
  233. FROM (SELECT ? as `magnitude`) as distance_calculation
  234. SQL;
  235.  
  236. return DB::select($query, $bindings)[0]->distance ?? null;
  237. }
  238.  
  239. /** Get a human readable formula. */
  240. public static function getPrettyPgvFormula(float $pgv, float $magnitude, float $n = 2.326347874): string
  241. {
  242. [$distance, $extraBindings] = self::distance($n, $pgv);
  243.  
  244. // Order is important, because we can't mix named and non-named parameters, and we need to bind multiple of the same name
  245. $bindings = [$pgv, ...$extraBindings, $magnitude];
  246.  
  247. $query = <<<SQL
  248. SELECT ? as pgv, {$distance} as distance, `magnitude`
  249. FROM (SELECT ? as `magnitude`) as distance_calculation
  250. SQL;
  251.  
  252. // Replace the bindings
  253. $result = \str_replace(PHP_EOL, ' ', $query);
  254. foreach ($bindings as $binding) {
  255. $pos = \strpos($result, '?');
  256. if ($pos !== false) {
  257. $result = \substr_replace($result, $binding, $pos, \strlen('?'));
  258. }
  259. }
  260.  
  261. // Replace excessive spaces
  262. return \strtolower(\preg_replace('/[ ]+/', ' ', $result));
  263. }
  264. }
  265.  
Advertisement
Add Comment
Please, Sign In to add comment