• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.unittest;
2 
3 import com.google.common.base.Joiner;
4 import com.google.common.collect.ImmutableMap;
5 import com.google.common.collect.ImmutableSet;
6 import com.google.common.collect.Multimap;
7 import com.google.common.collect.TreeMultimap;
8 import com.ibm.icu.util.Output;
9 import java.util.Arrays;
10 import java.util.Collection;
11 import java.util.List;
12 import java.util.Map.Entry;
13 import java.util.Set;
14 import java.util.TreeSet;
15 import java.util.regex.Matcher;
16 import java.util.regex.Pattern;
17 import org.unicode.cldr.util.CLDRConfig;
18 import org.unicode.cldr.util.Pair;
19 import org.unicode.cldr.util.Rational;
20 import org.unicode.cldr.util.Rational.FormatStyle;
21 import org.unicode.cldr.util.SupplementalDataInfo;
22 import org.unicode.cldr.util.SupplementalDataInfo.UnitIdComponentType;
23 import org.unicode.cldr.util.UnitConverter;
24 import org.unicode.cldr.util.UnitConverter.ConversionInfo;
25 import org.unicode.cldr.util.UnitConverter.TargetInfo;
26 import org.unicode.cldr.util.UnitConverter.UnitId;
27 import org.unicode.cldr.util.UnitConverter.UnitSystem;
28 import org.unicode.cldr.util.UnitParser;
29 
30 public class GenerateNewUnits {
31 
32     private static final CLDRConfig CLDR_CONFIG = CLDRConfig.getInstance();
33     private static final CLDRConfig info = CLDR_CONFIG;
34     private static final SupplementalDataInfo SDI = info.getSupplementalDataInfo();
35     private static final UnitConverter converter = SDI.getUnitConverter();
36 
37     private static final String CHECK_UNIT = "kilogram-force";
38 
main(String[] args)39     public static void main(String[] args) {
40         Set<String> argSet = Set.copyOf(Arrays.asList(args));
41         boolean SI_ACCEPTED = argSet.isEmpty() || argSet.contains("accepted");
42         boolean SYMBOLS = argSet.isEmpty() || argSet.contains("symbols");
43         boolean GENERATE_XML = argSet.isEmpty() || argSet.contains("xml");
44         boolean OTHER = argSet.isEmpty() || argSet.contains("plain");
45 
46         boolean TEST_PARSER = argSet.contains("parser");
47         Output<String> base = new Output<>();
48 
49         int count = 0;
50         Set<ExternalUnitConversionData> cleanedNist = clean(NistUnits.externalConversionData);
51         UnitParser up = new UnitParser();
52         String lastQuantity = "";
53 
54         if (SI_ACCEPTED) {
55             System.out.println("\n# SI_Accepted\n");
56             for (ExternalUnitConversionData data : NistUnits.externalConversionData) {
57                 if (data.systems.contains(UnitSystem.si_acceptable)) {
58                     ConversionInfo convert = converter.parseUnitId(data.source, base, false);
59                     System.out.println((convert == null ? "OUT" : "IN") + "\t" + data);
60                 }
61             }
62         }
63         if (SYMBOLS) {
64             System.out.println("# Symbols\n");
65 
66             Multimap<String, String> unitsToSymbols = TreeMultimap.create();
67             Multimap<String, String> symbolsToUnits = TreeMultimap.create();
68             Matcher simple = Pattern.compile("^[^ ·/0-9]*$").matcher("");
69             for (ExternalUnitConversionData data : NistUnits.externalConversionData) {
70                 if (data.symbol != null) {
71                     ConversionInfo convert = converter.parseUnitId(data.source, base, false);
72                     if (convert != null && simple.reset(data.symbol).matches()) {
73                         unitsToSymbols.put(data.source, data.symbol);
74                         symbolsToUnits.put(data.symbol, data.source);
75                     }
76                 }
77             }
78             for (Entry<String, Collection<String>> entry : unitsToSymbols.asMap().entrySet()) {
79                 final String sourceUnit = entry.getKey();
80                 System.out.println(
81                         converter.getQuantityFromUnit(sourceUnit, false) //
82                                 + "\t"
83                                 + sourceUnit //
84                                 + "\t"
85                                 + Joiner.on('\t').join(entry.getValue())
86                                 + "\t"
87                                 + converter.getSystems(sourceUnit));
88             }
89             for (Entry<String, Collection<String>> entry : symbolsToUnits.asMap().entrySet()) {
90                 if (entry.getValue().size() > 1) {
91                     System.out.println(
92                             "Ambiguous! "
93                                     + entry.getKey()
94                                     + "\t"
95                                     + Joiner.on('\t').join(entry.getValue()));
96                 }
97             }
98         }
99         if (GENERATE_XML) {
100             System.out.println("\n# XML missing\n");
101             for (ExternalUnitConversionData data : cleanedNist) {
102 
103                 if (!lastQuantity.equals(data.quantity)) {
104                     System.out.println("<!-- " + data.quantity + "-->");
105                     lastQuantity = data.quantity;
106                 }
107                 System.out.println(
108                         "\t\t<convertUnit"
109                                 + " source='"
110                                 + data.source
111                                 + "'"
112                                 + (data.symbol == null ? "" : " symbol='" + data.source + "'")
113                                 + " baseUnit='"
114                                 + data.target
115                                 + "'"
116                                 + " factor='"
117                                 + data.info.factor
118                                 + "'"
119                                 + " systems=\'???\'"
120                                 + "/>");
121             }
122             if (OTHER) {
123                 System.out.println("\n# Missing\n");
124                 for (ExternalUnitConversionData data : cleanedNist) {
125                     System.out.println(
126                             ++count
127                                     + "\t"
128                                     + data.quantity
129                                     + "\t"
130                                     + data.source
131                                     + "\t"
132                                     + data.symbol
133                                     + "\t⟹\t"
134                                     + data.info.factor
135                                     + " × "
136                                     + data.target
137                                     + "\t"
138                                     + data.info.factor.toString(FormatStyle.approx));
139                 }
140             }
141             if (TEST_PARSER) {
142                 System.out.println("\n# Check parser\n");
143                 for (ExternalUnitConversionData data : cleanedNist) {
144                     up.set(data.source);
145                     try {
146                         List<Pair<UnitIdComponentType, String>> list = up.getRemaining();
147                         System.out.println(data.source + "\t" + list.size() + "\t⟹\t" + list);
148                     } catch (Exception e1) {
149                         System.out.println(e1.getMessage() + ", " + data);
150                         e1.printStackTrace();
151                     }
152                 }
153             }
154         }
155     }
156 
157     /** Filter out the most useful conversions */
clean( Set<ExternalUnitConversionData> externalconversiondata)158     private static Set<ExternalUnitConversionData> clean(
159             Set<ExternalUnitConversionData> externalconversiondata) {
160         Multimap<String, ExternalUnitConversionData> cleaned = TreeMultimap.create();
161         Output<String> base = new Output<>();
162         for (ExternalUnitConversionData data : NistUnits.externalConversionData) {
163             if (data.source.equals(CHECK_UNIT)) {
164                 SDI.getUnitIdComponentType(CHECK_UNIT);
165             }
166 
167             // skip the ones we have already
168 
169             ConversionInfo convert = converter.parseUnitId(data.source, base, false);
170             if (convert == null) {
171                 cleaned.put(data.source, data);
172             }
173         }
174         Set<ExternalUnitConversionData> result = new TreeSet<>();
175         ImmutableSet<String> absoluteTemperature =
176                 ImmutableSet.of("celsius", "fahrenheit", "kelvin", "rankine");
177         Output<String> baseUnit = new Output<>();
178         for (Entry<String, Collection<ExternalUnitConversionData>> items :
179                 cleaned.asMap().entrySet()) {
180             final String source = items.getKey();
181             if (absoluteTemperature.contains(source)) {
182                 continue;
183             }
184 
185             final Collection<ExternalUnitConversionData> mappings = items.getValue();
186             if (source.equals(CHECK_UNIT)) {
187                 int debug = 0;
188             }
189             ExternalUnitConversionData revisedItem = findBestMapping(baseUnit, source, mappings);
190             result.add(revisedItem);
191         }
192         return result;
193     }
194 
195     /**
196      * Get the best mapping
197      *
198      * @param baseUnit
199      * @param source
200      * @param mappings
201      * @return
202      */
findBestMapping( Output<String> baseUnit, final String source, final Collection<ExternalUnitConversionData> mappings)203     public static ExternalUnitConversionData findBestMapping(
204             Output<String> baseUnit,
205             final String source,
206             final Collection<ExternalUnitConversionData> mappings) {
207         String bestTarget = null;
208         Rational bestFactor = null;
209         String bestQuantity = null;
210         String bestSymbol = null;
211         for (ExternalUnitConversionData data : mappings) {
212             ConversionInfo conversionInfo = converter.parseUnitId(data.target, baseUnit, false);
213             if (conversionInfo != null) {
214                 String target = baseUnit.value;
215                 Rational endFactor = conversionInfo.convert(data.info.factor);
216                 if (bestTarget == null) {
217                     bestTarget = target;
218                     bestFactor = endFactor;
219                     bestQuantity = data.quantity;
220                     bestSymbol = data.symbol;
221                 }
222             } else {
223                 TargetInfo baseUnit2 = NistUnits.derivedUnitToConversion.get(data.target);
224                 if (baseUnit2 != null) {
225                     bestTarget = baseUnit2.target;
226                     bestFactor = baseUnit2.unitInfo.factor.multiply(data.info.factor);
227                     bestQuantity = data.quantity;
228                     bestSymbol = data.symbol;
229                 }
230             }
231         }
232         UnitId targetId = converter.createUnitId(bestTarget);
233         bestTarget = targetId == null ? bestTarget : targetId.resolve().toString();
234         String quantity = converter.getQuantityFromUnit(bestTarget, false);
235         bestQuantity = quantity == null ? "•" + bestQuantity : quantity;
236         return new ExternalUnitConversionData(
237                 bestQuantity,
238                 source,
239                 bestSymbol,
240                 bestTarget,
241                 bestFactor,
242                 Rational.ZERO,
243                 null,
244                 null,
245                 null);
246     }
247 
248     static final ImmutableMap<String, String> quantityFromUnit =
249             ImmutableMap.<String, String>builder()
250                     .put("curie", "radioactivity")
251                     .put("kayser", "spectroscopy")
252                     .put("gon", "angle")
253                     .put(
254                             "cubic-second-square-ampere-per-kilogram-square-meter",
255                             "electrical-conductance")
256                     .put("gram-per-meter", "dup")
257                     .put("joule-per-kelvin", "entropy")
258                     .put("joule-per-kilogram-kelvin", "specific-heat")
259                     .put("joule-per-square-meter", "radiant-exposure")
260                     .put("kelvin-per-watt", "absolute-thermal-resistance")
261                     .put("kilogram-per-meter", "linear-density")
262                     .put("kilogram-per-second", "mass-flow-rate")
263                     .put("kilogram-per-square-meter", "surface-density")
264                     .put("kilogram-per-square-second-ampere", "magnetic-flux-density")
265                     .put("kilogram-square-meter-per-square-second-ampere", "magnetic-flux")
266                     .put("kilogram-square-meter-per-square-second-square-ampere", "inductance")
267                     .put("meter-kelvin-per-watt", "thermal-resistance-coefficient")
268                     .put("meter-per-meter", "angle")
269                     .put("mole-per-second", "enzymatic-activity")
270                     .put("ohm-meter", "electric-resistivity")
271                     .put("ohm-square-millimeter-per-meter", "electrical-resistivity")
272                     .put("pascal-second", "dynamic-viscosity")
273                     .put("per-pascal-second", "dup")
274                     .put("per-second", "radioactivity")
275                     .put("pow4-second-square-ampere-per-kilogram-square-meter", "capacitance")
276                     .put("second-ampere", "emu-of-charge")
277                     .put("square-meter-per-second", "kinematic-viscosity")
278                     .put("square-meter-per-square-meter", "solid-angle")
279                     .put("square-meter-per-square-second", "dose")
280                     .put("watt-per-square-meter", "irradiance")
281                     .put("watt-per-square-meter-kelvin", "thermal-heat-transfer-coefficient")
282                     .put("watt-per-meter-kelvin", "thermal-conductivity")
283                     .put("square-meter-kelvin-per-watt", "thermal-insulance")
284                     .put(
285                             "kilogram-square-meter-per-meter-cubic-second-kelvin",
286                             "thermal-conductivity")
287                     .put("kilogram-second-per-meter-square-second", "viscosity")
288                     .put("kilogram-square-meter-per-square-meter-cubic-second", "surface-tension")
289                     // kilogram-square-meter-per-cubic-second
290                     .build();
291 }
292